插座TCP通信数据包分裂



我开发了一个点对点项目,我尝试传达两台机器( a 由WiFi和 B 连接的我的笔记本电脑我的NAS通过以太网连接)在同一网络上。沟通效果很好,但是当我发送1696 bytes的包包时,我有一个问题。

所以在我的发件人中 a 我将1696 bytes的块写入 b ,当我在Wireshark上查看时,我看到两个数据包发送了一个大小1448比较,另一个是大小248bytes(1448 248 = 1696)。

因此,我认为该数据包是通过一个协议或网络和物理层之间的某些协议剪切的,因为1448可以与MTU相对应。因此,在我的接收器中 b 发生了一些奇怪的事情,如果我发送了两次1696的街区,那么我第一次将阅读1696年的一个街区,即使在Wireshark中,我看到了两个分裂的块,并且我第二次阅读了两个分裂的块两次...

对我来说,这是一个问题,因为我需要两个块来解密它们。

我从 b 发送到 a in a a ,然后我始终收到一个大小1696 bytes的块,在Wireshark中,我也看到了1696比较的一个街区。所以也许问题来自以太网...

所以我不知道哪种解决方案是最好的,我可以阅读一对一的字节,直到定义为2048的尺寸,然后在发件人的数据包上应用填充物以具有2048个数据包大小。也许您还有其他解决方案可以给我。

我希望我很清楚,

谢谢,

接收器类:

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();
    }
}

发件人类:

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是流协议。

写入TCP套接字就像写入文件一样。

从TCP套接字读取就像从文件中读取。

单个read()调用不对应于单个send()。相反,它只是读取目前TCP缓冲区中可用的内容。无论是一半消息,一条消息还是一百个消息。

如果您希望将单个消息写在文件上以彼此分开,则需要某种方法来告诉消息何时启动以及何时结束。有很多这样做的方法,这里有一对:

  • 在文本文件中,可以使用诸如"n之类的定界符分隔文件的部分。在二进制文件中,这很棘手,除非您可以保证定界符不会在消息中间显示。TCP也是如此。您可以使用一些特殊值(例如)界定消息。然后,从套接字读取另一侧需要做的一切,直到看到定界线为止。如果您不能保证出于明显的原因您的消息主体不包含界限。

  • 计数。将每个消息的前缀带有表示消息长度的整数(4个字节)。因此,如果要发送01 02 03 aa bb cc dd(HEX),请发送00 00 00 07 01 02 03 aa bb cc dd。接收器将读取每条消息的前4个字节,并找出必须读取的字节数以获取整个消息。但是,这确实要求发件人事先知道其消息的长度。但是,在大多数情况下,这不是问题。

最新更新