Question

I have a puzzling problem when using Java 7 and SSL sockets.

I've got a client/server bundle. Both send XML data to each other by using a very simple protocol. The first 4 bytes of each message always contain the length of the whole message. That means, it's the length of the XML data plus 4 bytes.

At first, the client sends a greeting message to the server. Next, the server interprets the greeting and sends a response. Then, the client itself interprets that message and sends its login information. The server checks that information and sends a response back. But this time, the client does not receive anything, although it uses the very same method as when getting the greeting response from the server.

This is the simplified reading-method on the client side:

private String readResponse() throws Exception
{
    BufferedInputStream inputBuffer = new BufferedInputStream(sslSocket.getInputStream());

    // Read and interprete the first 4 bytes to get the length of the XML-data
    int messageLength = readMessageLength(inputBuffer) - 4;

    // PROBLEM OCCURS HERE!

    // Read bufferSize bytes from stream
        byte[] byteArray = new byte[messageLength];
    inputBuffer.read(byteArray);

    // Return the XML-data
    return new String(byteArray);
}

And here the method to retrieve the length from the first 4 bytes...

private int readMessageLength(BufferedInputStream in) throws IOException {
    byte[] b = new byte[4];
    in.read(b, 0, 4);

    return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff));
}

At the time the second response should be read by the client, the inputBuffer contains zeros only ([0, 0, 0, 0, 0, 0, ...]). So when trying to calculate the message length using readMessageLength(), it returns -4. And that, of course, leads to an exception.

It seems obvoius that the data sent by the server is not yet ready to be read by the client. Therefore, I made some changes:

int messageLength;
do {
    messageLength = readMessageLength(inputBuffer) - 4;
} while(messageLength <= 0);

However, that didn't work either. And now comes the puzzling part: What happens is that this loop is executed twice! The value assigned to messageLength now comes from the first 4 bytes of the XML data. The string returned by the reading-method now starts with ?xml, where the < is missing!

So, I tried mark and reset the first for bytes: inputBuffer.mark(4);

int messageLength;
do {
    inputBuffer.reset();
    messageLength = readMessageLength(inputBuffer) - 4;
} while(messageLength <= 0);

But that is actually an endless-loop. Since the contents of the inputBuffer never changes, messageLength never becomes anything else than -4.

When can I be sure that the data sent to client is available? How could I check that? What might be a better approach?

Regards, Walter

P.S. The method available() is not useful as it seems to always return zero when using SSL sockets.

Was it helpful?

Solution

You must absolutely, always check the number of bytes that are read from a communications channel. It can and will be zero at times, and you must keep reading in that case. End of stream has only been reached with a negative return value.

Specifically, in.read(new byte[100]) will not necessarily read 100 bytes.

If you want to guarantee you are getting everything, you need to use readFully.

OTHER TIPS

private int readMessageLength(BufferedInputStream in) throws IOException {
    byte[] b = new byte[4];
    int len = in.read(b, 0, 4);
    while(len<4)
        len += in.read(b, len, 4- len);

    return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff));
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top