7

I have socket already declared socket like this:

serverAddr = InetAddress.getByName(this.ip);
socket = new Socket(serverAddr, port);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

however, the following doesn't work. in.ready() always returns false and if removed the program will freeze at String message = in.readLine();

private void receive() {
        try {
            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            System.out.println(isr.getEncoding());
            BufferedReader in = new BufferedReader(isr);
            if (in.ready()) {
                String message = in.readLine();
                if (message != null) {
                    if (listener != null) {
                        listener.receiveMessage(ip, message);
                    } else {
                        print("Client recieved: " + message);//
                    }
                }
            }
            in.close();
        } catch (Exception e) {
            print("Error with input stream: " + e);
            disconnect();
        }

    }

How could i solve this?

EDIT:

This is how sending looks like in my server class: out.println(message); out.flush(); This happens in a loop whenever i've put something in message. out is closed after this loop.

Sadface
  • 73
  • 1
  • 4
  • 1
    Do you call `flush()` or `close()` on the server's writer? If not, the message will be buffered and only sent when the buffer is full. Until then, your client won't receive anything – king_nak May 19 '11 at 10:51
  • 1
    Currently i'm calling flush() whenever the server has written anything – Sadface May 19 '11 at 10:57

4 Answers4

4

You shouldn't be using ready() like this. The javadoc says this:

"Returns: True if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block. "

Your code is implicitly assuming that ready() -> false means that the next read will block. In actual fact, it means the next read might or might not block.

As @EJP says ... just do the read call.


What could i do to prevent a block though? The client will be unable to send anything if it's blocked

If blocking in read is a problem for your application, either use a separate thread to do the reading, or change your code to use NIO channel selectors.

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096
  • I see. What could i do to prevent a block though? The client will be unable to send anything if it's blocked – Sadface May 19 '11 at 11:00
2

Just remove the in.ready() test. It isn't helping you. readLine() will block until there is data available. What else were you planning to do if no data has arrived yet?

user207421
  • 289,834
  • 37
  • 266
  • 440
  • I'm sending a response from the server, however it's never received for some reason. This client is capable of sending messages, but it can't receive. – Sadface May 19 '11 at 10:46
  • Yes, client is able to send and server successfully receives messages. However, server->client appears unstable. Sometimes the client will just freeze at in.readLine(); – Sadface May 19 '11 at 10:52
  • @Sadface - you didn't answer @EJP's (rhetorical) question. – Stephen C May 19 '11 at 10:53
  • The problem with the client freezing at in.readLine(); means it's unable to send. It's basically dead. Meaning, i might want to send even if i haven't received anything yet. – Sadface May 19 '11 at 10:55
  • @Sadface the problem with the client freezing at readLine() is that there is no line to read. ready() returning false indicates exactly the same condition. You appear to have a problem with your application protocol. The solution is to fix it. – user207421 May 19 '11 at 11:01
  • @Sadface fix what? If the sender hasn't sent anything there is nothing to read. You can't fix that, you can only wait. – user207421 May 19 '11 at 23:35
1

There are 3 things that come to my mind:

  • You are re-opening the input stream in every receive call, and wrapping it into a BufferedReader. This might read more than a single line into the buffer, and after finishing (closing it), the remaining buffered bytes will no longer be available for subsequent receive calls
  • Did you think about using an own thread for reading the server messages? There it won't harm if it is blocked
  • I have experienced some problems when closing one side of a socket after writing data, and immediately closing it. Sometimes not all of the data was received by the other side, despite flush() and close() calls. Maybe this is also an issue in your situation

Edit:
Smiply keeping the in reference outside of the receive method will not fully solve your problem. You should use a while loop for reading all buffered messages and call the listener for everyone, e.g.:

if (in.ready()) {
    String message;
    while ((message = in.readLine()) != null) {
        // ...
    }
 }

But watch out as the last line might be a partially read message (e.g. 3 and 1/2 messages were buffered). If this is an issue, you could read the messages char-by-char for determining when a line ends, and use a PushbackReader for putting back incomplete messages.

king_nak
  • 10,729
  • 30
  • 55
  • I see. Do you suggest i'm keeping the inputreader outside of my recieve-method? Should i also close my output on the server after sending a message? Right now i'm keeping it open until i no longer need it. – Sadface May 19 '11 at 11:13
  • Yes, you should keept the input reader outside of the receive method. On the server side, I meant to not close the _socket_ _immediately_ after writing a big message. So keeping the output stream is perfectly ok – king_nak May 19 '11 at 11:19
0

You may need to call out.flush() to flush anything in BufferedWriter

secmask
  • 6,349
  • 4
  • 31
  • 51