[英]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發送到A的A時 ,我總是收到一個大小為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.