简体   繁体   中英

Socket TCP Communication packet splitted

I develop a Peer-to-Peer Project, i try to communicate two machines ( A my laptop connected by WiFi and B my NAS connected by Ethernet) on the same network. The communication work well but i have an issue when i send a packet of size 1696bytes.

So in my sender A i write the block of 1696bytes to B , when i look on Wireshark i see two packets are send one of size 1448bytes and another of size 248bytes (1448+248=1696).

So i think the packet are cut by one protocol or something between the network and physical layer because 1448 can correspond to a MTU. And so in my receiver B something weird happen, if i send two times the block of 1696, the first time i will read one block of 1696 even if in Wireshark i see the two splitted blocks, and the second time i read two times for the two splitted blocks...

For me it's a problem because i need the two blocks together to decrypt them.

And when i send from B to A in A and i receive always one block of size 1696bytes, and in Wireshark i see also one block of 1696bytes. So maybe the issue come from Ethernet...

So i don't know which solution is the best, i could read bytes one to one until a size defined like 2048 and so apply a padding to my packet in the sender to have a 2048 packet size. Or maybe you have other fix to give me.

I hope i was clear,

Thank you,

The Receiver class :

public abstract class DataReceiver implements Runnable {
protected ConnectionType    type;
protected AsymmetricEncryption as;
protected Socket            socket;
protected FIFOQueue         buffer;
protected int               dataPacketSize;

protected abstract IDataStructure dataFormatter(byte[] data, int len) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException;

public DataReceiver(ConnectionType type, Socket socket, FIFOQueue buffer, AsymmetricEncryption as) {
    this.type = type;
    this.socket = socket;
    this.buffer = buffer;
    this.dataPacketSize = 2048;
    this.as = as;
}

public int waitData() {
    try {
        System.out.println(socket.getPort() + " : I wait data from " + socket.getInetAddress().getHostAddress());
        byte[] data = new byte[dataPacketSize];
        int len;
        IDataStructure dataStructure;
        while ((len = socket.getInputStream().read(data, 0, data.length)) != -1) {
            try {
                if ((dataStructure = dataFormatter(data, len)) == null) {
                    System.err.println("Error: bad data format.");
                } else if (type == ConnectionType.EXTRA) {
                    ((ExtraDataStructure)dataStructure).getContent().setParam();
                    buffer.putData(dataStructure);
                } else if (type == ConnectionType.INTRA) {
                    ((IntraDataReceiver)this).getRqManager().doRequest((IntraDataStructure)dataStructure, buffer, socket);
                }
                Arrays.fill(data, (byte)0);
            } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | JsonSyntaxException | InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            }
            System.out.println("New data received from " + socket.getInetAddress().getHostAddress());
            //dumpBuffer();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return (0);
}

    @Override
    public void run() {
        waitData();
    }
}

The sender class :

public class ExtraDataDispatcher extends DataDispatcher {

public ExtraDataDispatcher(AsymmetricEncryption as, NodeIdentifier nodeId) {
    super(ConnectionType.EXTRA, as, nodeId);
}

@Override
public boolean dispatchData(IDataStructure data, Socket destSocket) throws IOException {
    System.out.println("HERE");
    destSocket.getOutputStream().write(new Gson().toJson(((ExtraDataStructure)data).getContent()).getBytes());
    return false;
}
}

TCP is a stream protocol.

Writing to a TCP socket is like writing to a file.

Reading from a TCP socket is like reading from a file.

A single read() call doesn't correspond to a single send() . Instead, it just reads whatever is available in the TCP buffer at the moment. Whether it's half a message, a whole message or a hundred messages.

If you want individual messages written to a file to be separate from one another, you'd need some way of telling when a message starts, and when it ends. There are plenty of ways of doing that, here are a couple:

  • In text files, one can use a delimiter such as "\\n to separate parts of the file. In a binary file, this is trickier unless you can guarantee that the delimiter won't show up in the middle of a message. The same is true in TCP. You could delimit messages using some special value (eg \\0 ). Then, all you'd need to do on the other side is read from the socket until you see the delimiter. Don't do this if you can't guarantee that your message body doesn't contain the delimiter for obvious reasons.

  • Count. Prefix each message with, say, an integer (4 bytes) that indicates the length of the message. So if you want to send 01 02 03 aa bb cc dd (hex), send 00 00 00 07 01 02 03 aa bb cc dd . The receiver would read the first 4 bytes of every message, and figure out the number of bytes it has to read to get the entire message. This does however require the sender to know the length of its message in advance. It's not a problem in most cases, though.

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