简体   繁体   中英

Java SSLSocket what to do after read returns -1?

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.

Ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM