Socket.BeginReceive合并TCP数据包 [英] Socket.BeginReceive merging TCP packets

查看:95
本文介绍了Socket.BeginReceive合并TCP数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以使用某个设置来防止将多个TCP数据包合并到 Socket.BeginReceive 回调内部的单个缓冲区中?

Is there a setting I can use to prevent merging multiple TCP packets into a single buffer inside Socket.BeginReceive callback?

您的下意识的反应是,我无能为力,无法阻止TCP拆分/合并数据,但是这不是我要问的;我可以清楚地看到Wireshark中接收到单个数据包,而我唯一关心的是延迟,即在分段到达时立即对其进行处理.这并不意味着我不知道如何处理拆分/合并的段,而是意味着我想避免延迟.

Your knee-jerk reaction will be that there is nothing I can do to prevent TCP from splitting/merging the data, but this is not what I asking; I can clearly see individual packets being received in Wireshark, and my only concern is latency, i.e. to process the segment as soon as it arrives. This doesn't mean I don't know how to process split/merged segment, but it means I want to avoid the delay.

我的代码如下:

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字节.但是有时在我的应用程序中有100ms的延迟, OnPacketReceived 方法获取200个字节.

When I examine these packets in WireShark, I can see individual TCP packets being received every 50ms, each of them (say) 100 bytes. But sometimes in my app there is a delay of 100ms, and the OnPacketReceived methods gets 200 bytes.

由于WireShark确认这不是操作系统/网络问题,所以这里可能是什么问题? OnPacketReceived 只会在后台线程上触发,因此它不会阻塞该方法,并且程序实际上并不会消耗太多CPU.

Since WireShark confirms that this is not a OS/networking issue, what could be the problem here? The OnPacketReceived just fires on a background thread so it doesn't block the method, and the program doesn't really consume much CPU.

(更新)

似乎我没有足够清楚地表达我的问题.我的问题不是如果数据被分割成多个段怎么解析.我的协议定义明确(即START_COOKIE,LENGTH,DATA,CRC),收到数据后,我便将数据排队到字节FIFO中(上面代码段中的 _queue.Enqueue 调用),因此我可以轻松地异步解析它.

It seems like I didn't convey my question clearly enough. My problem is not how to parse the data if it gets split across segments. My protocol is well defined (i.e. START_COOKIE, LENGTH, DATA, CRC), and I enqueue the data into a byte FIFO as soon as I receive it (the _queue.Enqueue call inside the snippet above), so I can easily parse it asynchronously.

问题是,如果我看到数据包编号.Wireshark中+ 50ms时为1(100字节),数据包号为1.在Wireshark中+ 100ms处2个(100字节),并且我的应用程序没有阻塞 OnPacketReceived 方法并且不占用CPU,.NET偶尔会调用 OnPacketReceived 在+ 100ms时将两个数据包合并为一个?

The question is, if I am seeing packet no. 1 (100 bytes) at +50ms in Wireshark, and packet no. 2 (100 bytes) at +100ms in Wireshark, and my application is not blocking the OnPacketReceived method and consuming no CPU, how come does .NET, every once in a while, invoke OnPacketReceived at +100ms and merge two packets into one?

推荐答案

TCP 是一个根据定义,连续的数据流(这是它的主要功能,它看起来好像根本没有数据包,这与UDP不同).因此,由您的软件来定义消息格式.您可以:

TCP is a continuous stream of data by definition (it is its main feature, to make it seems as if there were no packets at all, unlike UDP). Thus, it's up to your software to define the message format. You could:

  • 在每封邮件的开头标记其长度(http会标出该长度).
  • 在消息末尾添加分隔符(/n).为了让接收者知道何时开始和停止阅读一条消息,请标记消息的开头和结尾(使用无法键入的特殊符号).

总而言之,您必须注意将流分成消息.或在TCP之上使用HTTP,WebSockets或其他消息格式实现.

To sum up, you have to care of splitting the stream into messages. Or use HTTP, WebSockets or other message format implementations on top of TCP.

这篇关于Socket.BeginReceive合并TCP数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆