gpt4 book ai didi

c# - 处理 TCP 数据包碎片

转载 作者:太空宇宙 更新时间:2023-11-03 21:35:01 26 4
gpt4 key购买 nike

对我来说,数据包碎片是如何发生的似乎非常模糊,因为它从未在我的本地测试中发生过,而且在通知我的应用程序我实际收到一些信息之前,我不知道该怎么做才能处理碎片化的数据包。

这是我从连接的客户端套接字接收的方式

var asynchronousState = (AsynchronousState) ar.AsyncState; // AsynchronousState is an entity that Holds each connected socket's Buffer, IPEndPoint and so on...
try {
Socket socket = asynchronousState.Socket;
int length = socket.EndReceive(ar);
if (0 != length) {
if (null != ClientReceive) {
var bytes = new byte[length];
Array.Copy(asynchronousState.Buffer, bytes, length);
ClientReceive(asynchronousState, bytes);
Array.Clear(asynchronousState.Buffer, 0, asynchronousState.Buffer.Length);
}
if (socket.Connected) {
socket.BeginReceive(asynchronousState.Buffer, 0, asynchronousState.Buffer.Length, SocketFlags.None, HandleAsyncReceive, asynchronousState);
return;
}
}
DisposeSocket(asynchronousState);
}
catch (SocketException exception) {
if (exception.SocketErrorCode != SocketError.Disconnecting &&
exception.SocketErrorCode != SocketError.NotConnected &&
exception.SocketErrorCode != SocketError.ConnectionReset &&
exception.SocketErrorCode != SocketError.ConnectionAborted &&
exception.SocketErrorCode != SocketError.Shutdown) {
Console.WriteLine(exception);
Core.Logger.Log(exception);
}

DisposeSocket(asynchronousState);
}

我如何构建我的数据包

public class ExchangeMessage : PacketStructure //Packet Structure is a custom builder similar to `BinaryWrite/Reader` : This returns a byte[] or builds from a byte[]
{
public int Length;
public int Type;

public byte[] PublicKey
{
get { return ReadArray(140, 4); }
set { WriteArray(value, 4); }
}

public ExchangeMessage(byte[] receivedPacket) : base(receivedPacket) {}

public ExchangeMessage(int length, int type) : base(length, type)
{
Length = length;
Type = type;
}
}

现在,每当我收到期望应用程序能够反序列化或重建我的数据包的内容时,我都会调用 ClientReceive 事件处理程序。 如果数据包被分割怎么办?

我很困惑,因为通过研究这个主题,我发现他们之间有很多不同的意见,我对此表示怀疑 如果你自己构建你的数据包,它不会碎片化!

最佳答案

Sockets API 不会向您传送数据包片段,只会传送完整的数据包。 TCP/IP 堆栈将缓冲接收到的片段,直到它有一个完整的数据包,如果丢失了一些片段,整个数据包将被丢弃,并且必须完整地重新传输。

这是路径 MTU 检测提高性能的原因之一——它可以防止信道中间碎片和相应的数据包错误率增加。发送较小的数据包会导致同样多的错误,但可以通过选择性 ACK 处理整个丢失的数据包,这比丢弃部分数据包的接收片段要有效得多。

如果您使用较低级别的网络 API,您可能会看到数据包碎片。


请注意,TCP 数据包与 send() 调用并非 1:1 对应。 Nagle 算法可以将多个写入组合成一个数据包,大于路径 MTU 的单个写入将生成多个数据包。我认为这就是鲍勃在他的评论中所暗示的。


碎片、数据包丢失和重传都在 TCP/IP 内部处理。您的应用程序无需担心。您的应用程序应将 TCP 套接字视为字节流。

您输入的字节以相同的顺序输出。无法保证需要多长时间以及一次输出多少,这超出了您的控制范围。

由于您希望将数据视为具有结构,而不仅仅是字节,因此您必须自己添加该结构。长度前缀和记录分隔符都是执行此操作的常用方法。

例如,HTTP 对命令/响应和元数据使用记录分隔符。 HTTP 命令和所有 header 由 \r\n 分隔。缺点是如果分隔符出现在数据中,则需要对其进行转义。 This example is borrowed from wikipedia .

HTTP/1.1 200 OK
Date: Mon, 23 May 2005 22:38:34 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
ETag: "3f80f-1b6-3e1cb03b"
Content-Type: text/html; charset=UTF-8
Content-Length: 131
Accept-Ranges: bytes
Connection: close

<html>
<head>
<title>An Example Page</title>
</head>
<body>
Hello World, this is a very simple HTML document.
</body>
</html>

也使用长度前缀。 Content-Length header 给出了负载的长度。这允许任何字节出现在有效负载中。

关于c# - 处理 TCP 数据包碎片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22238695/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com