繁体   English   中英

套接字TCP通信数据包已拆分

[英]Socket TCP Communication packet splitted

我开发了一个对等项目,我尝试在同一网络上通信两台计算机( A我的笔记本电脑通过WiFi连接, B我的NAS通过以太网连接)。 通信工作正常,但是当我发送大小为1696bytes的数据包时出现问题。

因此,在我的发送方A中,我将1696bytes的块写入B ,当我查看Wireshark时,我看到发送了两个大小为1448bytes的数据包,另一个发送了大小为248bytes的数据包(1448 + 248 = 1696)。

因此,我认为该数据包被网络和物理层之间的一种协议或某些内容削减,因为1448可以对应于MTU。 因此,在我的接收器B中,发生了一些奇怪的事情,如果我发送两次1696的块,即使我在Wireshark中看到了两个拆分的块,我第一次也会读取一个1696的块,而第二次我读了两次两个分开的方块...

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

当我从B发送到AA时 ,我总是收到一个大小为1696bytes的块,而在Wireshark中,我也看到一个大小为1696bytes的块。 所以也许问题出在以太网...

所以我不知道哪种解决方案是最好的,我可以一对一读取字节,直到定义为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中为true。您可以使用一些特殊值(例如\\0 )对消息进行定界。然后,从套接字读取另一边需要做的所有事情,直到看到定界符为止。由于明显的原因,不能保证您的邮件正文不包含定界符。

  • 计数。 给每个消息加上前缀(例如,整数(4个字节)),该整数指示消息的长度。 因此,如果您要发送01 02 03 aa bb cc dd (十六进制),请发送00 00 00 07 01 02 03 aa bb cc dd 接收器将读取每个消息的前4个字节,并弄清为获得整个消息必须读取的字节数。 但是,这确实需要发送方事先知道其消息的长度。 不过,在大多数情况下这不是问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM