Events are being forwarded to a client socket, which is being read by the code below. Most of the time the code works as expected. Sometimes a data packet is sent to the socket which causes the readline to unblock with a null message. From that point forward, the readline call never blocks again, causing a CPU spike. I have verified with code that the socket is not closed, the input stream has not been shutdown, isSocketClosed and isInputShutdown both return false. The ready call is just an attempt to see what's happening, the read call always returns -1. The socket is still accepting data, new valid packets come in, processed correctly, but the readline never blocks again. Any idea how why readline is behaving this way?
while (!this.isInterrupted())
{
String message = null;
do {
message = reader.readLine();
if ( message != null && message.length() > 0 ) {
//if ( log().isDebugEnabled())
log().info( "Got a message, raw data: " + message );
createEvent( message );
}
} while ( message != null && !this.isInterrupted());
if(!reader.ready()) {
log().info("Bytes read: " + reader.read());
Thread.sleep(1000);
}
}
BufferedReader.readLine() returns null when the other end closes the connection.
If it is not doing this you have a particularly bug JVM. I would make sure you have the latest update.
I have verified with code that the socket is not closed, the input stream has not been shutdown, isSocketClosed and isInputShutdown both return false
This just means your end didn't close() the stream. It doesn't tell you anything about the other end of the stream.
The ready call is just an attempt to see what's happening, the read call always returns -1
This also means you have an end of stream.
Just a small thing, but if you have empty (not null) strings coming in on your socket, they won't fall under if ( message != null && message.length() > 0 ).
You might wanna change it to if ( message != null ).
The reason this happens comes from the String#length() method:
Returns the length of this string. The length is equal to the number
of Unicode code units in the string. #return the length of the
sequence of characters represented by this object.
You have a bug in your code. If readLine() returns null, it means the peer has closed the connection. You must do likewise and exit the loop. Once it has returned null, it will never block again, and it will never stop returning null.
The part of your loop that tests ready() and sleeps is literally a compete waste of time. Remove it.
Related
I want to check if the InputStream buffer contains any data which it can read and output without having to initially call readLine() and waiting for data.
I have looked into available() but this didn't seem to work as it always output 0.
while (true)
{
fromServer = in.readLine(); //Causing a hang waiting for reply
System.out.println(fromServer);
if ((fromUser = stdIn.readLine()) != null)
{
out.println(fromUser);
fromServer = in.readLine();
System.out.println(fromServer);
}
}
available() might tell you the number of bytes available, if implemented, but nothing can tell you whether there is a complete line other than trying to read it.
You need to read in a separate thread.
The issue is readLine() causes the client to get stuck hanging for a server reply if access isn't permitted for the client.
So the issue is really that the server should send something 'if access isn't permitted for the client', i.e. a message that says so, rather than doing nothing. You can't use absence of a message as a message in a blocking I/O system.
You also need to check every readLine() result for null, and if you get it when reading a socket you need to close it.
Create a new Instance of BufferedInputStream and call available on that object:
InputStream is = ...;
BufferedInputStream bis = new BufferedInputStream(inputStream);
if (bis.available() == 0) {
// do sth if input is available
}
I tried it with a little server-client application, it worked for me.
EDIT: Type mismatch gone.
As the Java Documentation says, the InputStream.available() always returns zero. In comparison to that, the BufferedInputStream returns „the number of bytes remaining that can be read in the buffer“
I have a classic Java client/server app, where client and server exchange messages by a TCP connection.
When one elemement, let's call it Receiver (no matter if client or server), has to receive a message, it listens and waits for a message coming from the other element, let's call it Sender.
The receiver implements it by the following code:
BufferedReader myBufferedReader = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
receivedMessageCompleto = myBufferedReader.readLine();
The sender, after some time, will send a text message implementing the following code:
String messageCompleto = "whatever text";
String packetSend = messageCompleto + '\n' ;
DataOutputStream myDataOutputStream = new DataOutputStream(mySocket.getOutputStream());
myDataOutputStream.writeBytes(packetSend );
The probelm is:
in some cases "myBufferedReader.readLine()" get null value, but I'm quite sure that the sender didn't send a message NULL.
The question is: why?
According to my understanding the Receiver should remain blocked until it receives something (let's consider that timeout is set to infinite), then "myBufferedReader.readLine()" should return a value only when something arrives. The point is that I'm sure that the sender didn't send a null message.
Any idea???
Thank you very much in advance
Fausto
public String readLine()
throws IOException
Reads a line of text. A line is considered to be terminated by any one
of a line feed ('\n'), a carriage return ('\r'), or a carriage return
followed immediately by a linefeed.
Returns:
A String containing the contents of the line, not including any
line-termination characters, or null if the end of the stream has been
reached
Basically you get null if the underlying stream hits EOF.
As it says in the documentation for the readLine method:
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been
reached
So, in your case, end-of-stream has been reached. Probably, the remote end of the socket was closed.
I'm using a java server to connect to a browser with secure websockets. All works fine with the connect, but many times i get an unexpected -1 result from socket.in.read(buffer,off,len), this happens also in the middle of a frame. Normally i close a socket directly upon reception of -1, since it is end of stream. However i noted that it can also happen on a connection reset. I have come over many cases where in my tests the socket whould return valuable data after read returned -1. I even have the feeling this is more often than not. My problem arrises when sometimes i just get some scrambled data out of the socket after such a case. Another problem is that the other side is not notified when a frame cannot be delivered... So what good is TCP/SSL than? if you need to consider it an unreliable connection for transporting websocket frames in java?
I have some schemes to use that are used to deal with unreliable connections for making shure a packet arrives. But i hope that somebody knows what to do after read returns -1.
Sorry for the somewhat vague description in this one... i'm getting tired with solving this issue.
Just an example of some rubbish comming in (only text frames are submitted containing JSON data):
16-06-13 22:43:13.918;WebSocket;7: Read frame from websocket: 377, opcode:UNKNOWN
data: null
16-06-13 22:43:13.918;WebSocket;7: Read frame from websocket: 377, opcode:PONG_FRAME
data: null
16-06-13 22:43:13.918;WebSocket;7: Read frame from websocket: 377, opcode:TEXT_FRAME
data: =,6GiGGV7C6_TfPHg\~\c
Here another example of a received frame that is just a bit malformed!? how is this possible with a TCP/TLS connection???:
17-06-13 09:42:37.510;WebSocket;7: Read frame from websocket: 15, opcode:TEXT_FRAME
data: "kep-aiveY:"d613Nb2-N24eV463K-808-fJb30I9e3M02
It is supposed to read {"keep-alive":"[UUID]"}
Meanwhilst i have done some more testing and found that 9 out of 10 times it works if you continue reading after reception of -1. So even if you are reading halfway the frame and receive a -1 then you should test somehow if the socket is closed or not, i now use: socket.isInputShutdown(). if this is not the case then just continue filling up the buffer. To do so i now use the following code where socket is the SSLSocket:
public static int readFully(Socket socket, InputStream is, byte[] buffer, int off, int len) throws IOException
{
int read = 0;
while(read < len)
{
int b = is.read();
if(b < 0)
{
Logger.log(TAG, "readFully read returned: " + b + " testing if connection is reset or closed.", Logger.WARNING);
if(socket.isInputShutdown())
{
throw new IOException("InputStream closed before data could be fully read! (readFully read returned -1 and socket.isInputShutdown() is true");
}
}
else
{
buffer[off + (read++)] = (byte) b;
}
}
return read;
}
It is still not a hundred % correct but at leas i get more reliable results then before.
i get an unexpected -1 result from socket.in.read(buffer,off,len)
You have already reached EOS (end of stream) before you called this method.
this happens also in the middle of a frame.
There is no such thing as a 'frame' in TCP. If you mean it happens in the middle of an application message, you have an application protocol error.
Normally i close a socket directly upon reception of -1, since it is end of stream.
Correct.
However i noted that it can also happen on a connection reset
No it doesn't. If it did, you could not possibly have detected the reset. The statement is self-contradictory.
I have come over many cases where in my tests the socket whould return valuable data after read returned -1.
No you haven't. A socket can't return anything but -1 after it first does so. You can't be getting any data at all, let alone 'valuable' data, unless you are ignoring the -1 somewhere.
My problem arrises when sometimes i just get some scrambled data out of the socket after such a case.
Only if you ignore the -1, as you are doing.
Another problem is that the other side is not notified when a frame cannot be delivered.
Of course it isn't. If you could deliver a notification to the other side, you could deliver the packet. This doesn't make sense either. If you mean that the other side doesn't get notified when it couldn't deliver the packet, you are up against the fact that TCP sends are asyncrhonous, so you won't normally get a send error on the send that caused it. You will get it on a later send. If you need per-send acknowledgements, you need to build them into your application protocol.
So what good is TCP/SSL then?
TCP is a reliable data-stream protocol, and SSL is a secure reliable data-stream protocol. That's what use they are.
if you need to consider it an unreliable connection for transporting websocket frames in java?
Neither of them is unreliable.
I hope that somebody knows what to do after read returns -1.
Close the socket.
Meanwhilst i have done some more testing and found that 9 out of 10 times it works if you continue reading after reception of -1.
No it doesn't. 1000 times of 1000 it continues to return -1. All you are seeing here is the effect of other bugs in your code.
So even if you are reading halfway the frame and receive a -1 then you should test somehow if the socket is closed or not
You can't. The socket isn't closed. Proof: you just read from it without getting an exception. You can't test whether the connection is closed either, other than by read() returning -1.
I now use: socket.isInputShutdown().
Pointless. That tells you whether you have called Socket.shutdownInput() on your own socket. It doesn't tell you diddly-squat about the state of the connection. There is no TCP API that can do that, other than reading or writing.
if this is not the case then just continue filling up the buffer.
I.e. reading gargabe by ignoring the -1 that read() is returning.
To do so i now use the following code where socket is the SSLSocket:
Why? DataInputStream.readFully() already exists. Re-implementing it won't help.
if(b < 0)
{
Logger.log(TAG, "readFully read returned: " + b + " testing if connection is reset or closed.", Logger.WARNING);
if(socket.isInputShutdown())
At this point it is 100% irrelevant whether your Socket is shutdown for input. read() has returned -1, which means the peer has closed the connection. Period.
{
throw new IOException("InputStream closed before data could be fully read! (readFully read returned -1 and socket.isInputShutdown() is true");
}
This is all nonsense.
}
else
{
buffer[off + (read++)] = (byte) b;
}
Here you are adding the low byte of -1, which is 0xff, to the buffer. This is also nonsense.
I am reading data off a socket using the following loop
InputStream in = getInputStream();
int retCode;
try {
while( ( retCode = in.read()) > -1) {
// do something
}
logger.info( "Done reading : Code " + retCode);
} catch( IOException ioe) {
logger.warning( "IOException while reading : " + ioe.getMessage());
}
Sometimes connection gets dropped, which is expected, but the consequence is inconsistent.
I get an exception, or retCode==-1
Hence my question What determines exception vs return Code when reading a socket?
As #PeterLawrey rightly mentioned
if in.read() returns -1 - means the end of the stream is reached.
Exception in case on any unavailability of Stream / communication failure - depends on the Type of Exception thrown.
More
#PeterLawrey's answer is correct
if in.read() returns -1 - means the end of the stream is reached.
but there is more to it. The Java stream is backed by an operating system socket. If your program tries to write to the socket after the socket has been closed, or if it tries to read from a broken socket, then your program would get a SocketException with a reason such as broken pipe or connection reset by peer. I couldn't find anything official in the Java documentation, but it seems that if your program is blocked doing a read on the input stream of the socket, and the socket is then closed cleanly (without socket exception), then your program would be unblocked, and the read method would return -1.
I'm a real newbie to java, so please excuse me if this is a hopelessly straightforward problem.
I have the following from my java game server:
// Get input from the client
DataInputStream in = new DataInputStream (server.getInputStream());
PrintStream out = new PrintStream(server.getOutputStream());
disconnect=false;
while((line = in.readLine().trim()) != null && !line.equals(".") && !line.equals("") && !disconnect) {
System.out.println("Received "+line);
if(line.equals("h")){
out.println("h"+EOF); // Client handshake
System.out.println("Matched 1");
}else if (line.equals("<policy-file-request/>")) {
out.println("..."+EOF); // Policy file
System.out.println(server.getInetAddress()+": Policy Request");
disconnect=true;
System.out.println("Matched 2");
}else if(line.substring(0,3).equals("GET")||line.substring(0,4).equals("POST")){
out.println("HTTP/1.0 200 OK\nServer: VirtuaRoom v0.9\nContent-Type: text/html\n\n..."); // HTML status page
disconnect=true;
System.out.println("Matched 3");
} else {
System.out.println(server.getInetAddress()+": Unknown command, client disconnected.");
disconnect=true;
System.out.println("Matched else");
}
}
server.close();
First of all, the client sends an "h" packet, and expects the same back (handshake). However, I want it to disconnect the client when an unrecognised packet is received. For some reason, it responds fine to the handshake and HTML status request, but the else clause is never executed when there's an unknown packet.
Thanks
From the information added in your comments it seems that what will be happening is the client is sending a single character (e.g. 'n'). The line
line.substring(0,3).equals("GET")||line.substring(0,4).equals("POST"))
will be executed, but since line is only a single character line.substring(0,3) will throw a StringIndexOutOfBoundsException. Either this is causing your program to fail and you haven't mentioned that. Or you have some exception handling going on in another part of your code that you haven't shown and this is either supressing the error or printing a log line or something and again you haven't mentioned this (or noticed it).
Try replacing substring().equals with startsWith
You need to check for null before you trim it. The result of trim() can never be null.
You should check disconnect first, before the readLine(), otherwise you are always doing one readLine() too many.
If you are never getting to your 'else' it means one of the other conditions is always true.
There are a number of problems with your code
in.readLine().trim()
readLine do returns null and calling null.trim() will result in ... NullPointerException
Is there a reason to append EOF to every response you send.
calling substring without making sure it has at least that much elements will throw StringIndexOutOfBoundsException if it is shorter.
Are you testing with "P" for example?
It would seem highly unlikely that the else is not executing. Are you sure your loop does not exit on such packets and hence your conditions do not even run? Does your
System.out.println("Received "+line); print anything for the packet that seems to be missing the else statement?