【发布时间】:2017-05-15 03:18:56
【问题描述】:
是否有一个设置可以用来防止将多个 TCP 数据包合并到 Socket.BeginReceive 回调内的单个缓冲区中?
你的下意识反应是我无法阻止 TCP 拆分/合并数据,但 这不是我要的;我可以清楚地看到在 Wireshark 中接收到的各个数据包,我唯一关心的是延迟,即在数据段到达时立即处理它。这并不意味着我不知道如何处理拆分/合并段,而是意味着我想避免延迟。
我的代码如下所示:
void WaitForData(ISocketInfo soc)
{
if (socket != null && socket.Connected)
socket.BeginReceive(buffer, 0, buffer.Length,
SocketFlags.None, OnPacketReceived, socket);
}
void OnPacketReceived(IAsyncResult asyn)
{
try
{
var socket = (ISocketInfo)asyn.AsyncState;
numberOfBytesReceived = socket.EndReceive(asyn);
if (numberOfBytesReceived > 0)
{
_queue.Enqueue(buffer, 0, numberOfBytesReceived);
OnNewDataReceived();
}
WaitForData(socketInfo);
}
catch (SocketException ex)
{
Log.Warn("Socket error while receiving packet", ex);
Close();
}
}
当我在 WireShark 中检查这些数据包时,我可以看到每 50 毫秒接收一次单独的 TCP 数据包,每个(比如说)100 字节。但有时在我的应用程序中会有 100 毫秒的延迟,而 OnPacketReceived 方法获得 200 字节。
既然 WireShark 确认这不是操作系统/网络问题,那么这里的问题可能是什么? OnPacketReceived 只是在后台线程上触发,因此它不会阻塞该方法,并且程序实际上并不会消耗太多 CPU。
(更新)
看来我的问题表达得不够清楚。我的问题不是如果数据被分割成段,如何解析数据。我的协议定义明确(即START_COOKIE、LENGTH、DATA、CRC),我一收到数据就将数据排入字节FIFO(上面sn-p中的_queue.Enqueue调用),所以我可以轻松解析它是异步的。
问题是,如果我看到没有数据包。在 Wireshark 中 +50ms 时为 1(100 字节),数据包编号2(100 字节)在 Wireshark 中 +100 毫秒,我的应用程序没有阻塞 OnPacketReceived 方法并且不消耗 CPU,.NET 怎么会每隔一段时间在 +100 毫秒时调用 OnPacketReceived 并合并两个数据包合二为一?
【问题讨论】:
-
这里可能有什么问题?这里没有问题。 TCP 是一个无穷无尽的流,您所描述的行为是标准的和预期的。这取决于您的编程方式来处理传入的部分“消息”以及一次接收的多个“消息”。使用字节长度前缀、消息分隔符或这些东西的组合。
-
This answer 提供了更多信息。
-
@Idle_Mind:我认为你误解了这个问题。无论如何,我将所有数据排队到 FIFO 缓冲区中,我可以轻松解析它,格式定义明确。但问题是:如果 Wireshark 显示网卡正在接收两个实际的单独 TCP 数据包,为什么 .NET 会产生额外的延迟并将两个数据包合并到一个缓冲区中?我担心的是延迟,而不是解析。其次,TCP 不是“无穷无尽的流”,它是一种用于分段传输(可能)无穷无尽的数据流的协议。
-
很可能甚至没有 .NET 合并传入的数据。它可能已经发生在操作系统中。如果在短时间内接收到两个包含 TCP 连接数据的数据包,则它们的内容都将被放入 TCP 接收缓冲区,应用程序将简单地从该缓冲区中读取。它看不出这是一包还是两包。如果它偶尔发生一次,可能您的应用正忙于处理某些事情(垃圾收集?)并且在收到第二个数据包时没有获取第一个数据包。
-
TCP 堆栈将缓冲数据并处理flow control。它可以随意缓冲数据,也可以组合“数据包”,或者通过滑动窗口机制,在“数据包”中间停止数据流,即如果你的消息是 50 字节而接收窗口只有 28 字节,那么您可能会收到一小部分消息。所有这些都发生在 .NET 之下。 (“数据包”有点用词不当。由于段是从一个节点转发到另一个节点,它们可能会根据链接、缓冲区等进行拆分或组合。)
标签: c# .net sockets networking tcp