简体   繁体   中英

Java SocketChannel Read Entire String

In my current project, I am trying to transmit a string from one computer to another, and after finding and learning from numerous examples I have managed to get a basic form of communication working.

The issue I am having is if one computer tries sending a message that is too long, it seems to get broken up into multiple parts (roughly 3700 characters), and my parsing method fails.

I am using a Selector to iterate through all of the channels. Here is the relevant code:

if(key.isReadable()) {
    // Get the channel and read in the data
    SocketChannel keyChannel = (SocketChannel)key.channel();
    ByteBuffer buffer = buffers.get(keyChannel);
    int length  = 0;
    try {
        length = keyChannel.read(buffer);
    } catch ( IOException ioe) {
        closeChannel(keyChannel);
    }
    if(length > 0) {
        buffer.flip();
        // Gather the entire message before processing
        while( buffer.remaining() > 0) {
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            fireReceiveEvent(keyChannel, data);//Send the data for processing
        }
        buffer.compact();
    } else if (length < 0) {
        closeChannel(keyChannel);
    }
}

How can I guarantee that the entire message (regardless of length) is read at once before passing it along?

After talking to numerous people that know more about this than I do. The issue turns out to be that with TCP it is impossible to know when an entire "message" has arrived because there is no such thing as a message since TCP works on a two-way byte stream. The solution is to create your own protocol and implements your own definition of "message".

For my project, every message either starts with a [ or { and ends with a ] or } depending on the starting character. I search through the received data, and if there is a complete message, I grab it and pass it along to the handler. Otherwise skip the channel, and wait for more to arrive.

Here is the final version of my code that handles the message receiving.

if(key.isReadable()) {
    // Get the channel and read in the data
    SocketChannel keyChannel = (SocketChannel)key.channel();
    ByteBuffer buffer = buffers.get(keyChannel);
    int length = 0;
    try {
        length = keyChannel.read(buffer);
    } catch ( IOException ioe) {
        key.cancel();
        closeChannel(keyChannel);
    }
    if (length > 0) {
        buffer.flip();
        // Gather the entire message before processing
        if (buffer.remaining() > 0) {
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            buffer.rewind();
            int index = 0;
            int i = 0;
            // Check for the beginning of a packet
            //[ = 91
            //] = 93
            //{ = 123
            //} = 125
            if (data[0] == 91 || data[0] == 123) {
                // The string we are looking for
                byte targetByte = (byte) (data[0] + 2);
                for (byte b : data) {
                    i += 1;
                    if (b == targetByte) {
                        index = i;
                        break;
                    }
                }
                if (index > 0) {
                    data = new byte[index];
                    buffer.get(data, 0, index);
                    fireReceiveEvent(keyChannel, data);
                }
            } else {
                for (byte b : data) {
                    i += 1;
                    if (b == 91 || b == 123) {
                        index = i;
                        break;
                    }
                }
                if (index > 0) {
                    data = new byte[index];
                    buffer.get(data, 0, index); // Drain the data that we don't want
                }
            }
        }
        buffer.compact();
    } else if (length < 0) {
        key.cancel();
        closeChannel(keyChannel);
    }
}

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