簡體   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