Re: problem reading TCP packets on socket



antoine wrote:
I'm having a pretty annoying issue with a TCP connection in a
client/server environment.

my client connects to a server that sends it messages of variable
lengths.

on reception of each message, the client strips down the message in the
following manner:

1. the first two characters of the message are first read to indicate
the length of the message (as in the "decodeLength" method in the code
below)
2. knowing the length of the message, I read the appropriate number of
characters on my bufferedReader, and I start over.

So far, so good, though you didn't actually include the implementation of decodeLength(). Your approach is a standard one.


this method has proven effective for a very long time for me, but
recently I installed a new server on a slightly different environment
(stable though), and started experiencing strange things. after
tracking down the errors, I realized that problems arised when TCP
packets were not received properly, and the TCP stack asked for a
resend.

I haven't exactly figured out what's happening at the TCP layer yet,
but I "trust" the TCP stack, and think my client should be able to
handle such situation, however it does not.

[...]

Your client /could/ easily handle the situation, but it is buggy.

    public char[] receive() throws IOException {
        char[]        bufLen = new char[2];
        try {
        	_bufferedReader.read(bufLen);

The above is broken, though in practice it is not likely to fail often. (See below.)

        }
        catch (SocketException se) {
            _exit = true;
            se.printStackTrace();
            return null;
        }

        int len = decodeLength(bufLen);

        try {
            char[] _rawMsg = new char[len];
            _bufferedReader.read(_rawMsg);

This bit has the same bug as the earlier read, but it is more likely to be affected. (See explanation below.)


            return _rawMsg;
        }
        catch (SocketException se) {
            se.printStackTrace();
            _exit = true ;
        }
        return null;
    }


You should read the docs of Reader.read(char[]). You will then see that the method returns an int, which indicates the number of bytes actually read. This is by no means a formality: the method promises to block until it receives at least one character or sees the end of the stream, but it is by no means guaranteed to fill the array, regardless of the number of characters the sender is sending. There are many reasons why one logical message might be split up over multiple reads, and the TCP behavior you observed is just one of them. Using a BufferedReader as you have done improves the chances of getting a whole array in one read, but still does not ensure it.


The usual idiom for reading a fixed number of chars from a character stream is this:

    Reader reader;
    char[] buf;
    int numberToRead;

    [Assign suitable values to the variables]

    // Read repeatedly until the expected number of chars has been read:
    for (int totalCharsRead = 0; totalCharsRead < numberToRead; ) {
        int numberLeft = numberToRead - totalCharsRead;
        int numberRead = reader.read(buf, totalCharsRead, numberLeft);

        if (numberRead < 0) {
            // premature end of data
            break;
        } else {
            totalCharsRead += numberRead;
        }
    }

You can pop that into a handy method so that you don't need to repeat it every time, but you do need to use something like it for *both* of the reads in your method. Also, when you do it that way you are effectively buffering the input manually, so the BufferedReader doesn't provide much advantage over an unbuffered stream.

By the way, the appropriate technique for reading a fixed number of bytes from a byte stream is completely parallel to the above.

--
John Bollinger
jobollin@xxxxxxxxxxx
.



Relevant Pages

  • problem reading TCP packets on socket
    ... the client strips down the message in the ... characters on my bufferedReader, and I start over. ... I realized that problems arised when TCP ...
    (comp.lang.java.programmer)
  • Re: Deadlock situation while reading from sockets
    ... > When the client connects to the socket it only writes the one time then ... Each communication from the client has a new socket, ... What method in the BufferedReader class can I use to read all the data ... >> any particular sequence of characters. ...
    (comp.lang.java)
  • Re: OWA for exchange 2003 - Garbled characters
    ... > If the issue appears on only one client, ... > ForceClientsDownLevel registry key on the Exchange server. ... OWA for exchange 2003 - Garbled characters ... I have a problem when replying to an email using outlook web access ...
    (microsoft.public.exchange.clients)
  • Re: Problem with writing fast UDP server
    ... it likely means you have reached your ethernet bandwidth ... frames) to achieve your desired results. ... Keep in mind TCP is stream based, not datagram based so you may need ... On your client, make the following changes. ...
    (comp.lang.python)
  • Re: Log Out Issues
    ... UDP is the way to go for internet games. ... Apparently the extra overhead in TCP can cause a lot more lag in your game, ... >> Lets say the client sends a log out request to the server reliably. ...
    (microsoft.public.win32.programmer.networks)