Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Socket.BeginReceive合并TCP数据包_C#_.net_Sockets_Networking_Tcp - Fatal编程技术网

C# Socket.BeginReceive合并TCP数据包

C# Socket.BeginReceive合并TCP数据包,c#,.net,sockets,networking,tcp,C#,.net,Sockets,Networking,Tcp,是否有一个设置可用于防止将多个TCP数据包合并到Socket.BeginReceivecallback内的单个缓冲区中 你下意识的反应是,我无法阻止TCP拆分/合并数据,但这不是我要问的;我可以清楚地看到Wireshark中接收到的各个数据包,我唯一关心的是延迟,即在数据段到达后立即处理它。这并不意味着我不知道如何处理分割/合并段,但这意味着我希望避免延迟 我的代码如下所示: void WaitForData(ISocketInfo soc) { if (socket != null &

是否有一个设置可用于防止将多个TCP数据包合并到
Socket.BeginReceive
callback内的单个缓冲区中

你下意识的反应是,我无法阻止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中检查这些数据包时,我可以看到每50ms接收一个TCP数据包,每个(比如)100字节。但有时在我的应用程序中会有100毫秒的延迟,并且
OnPacketReceived
方法会得到200字节

既然WireShark确认这不是操作系统/网络问题,那么这里会有什么问题?OnPacketReceived的
OnPacketReceived
只在后台线程上触发,因此它不会阻止该方法,并且程序不会真正消耗太多CPU

(更新)

我似乎没有把我的问题表达得足够清楚。我的问题不是如果数据被分割成多段,如何解析数据。我的协议定义得很好(即START_COOKIE、LENGTH、DATA、CRC),我一收到数据就将数据排入字节FIFO(上面代码段中的
\u queue.enqueue
调用),因此我可以轻松地异步解析它


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

您可能会收到更少或更多的数据包,但不能保证您会收到确切的发送内容

从MSDN:

无法保证您发送的数据会立即出现在网络上。为了提高网络效率,底层系统可能会延迟传输,直到收集到大量传出数据。BeginSend方法的成功完成意味着基础系统有空间为网络发送缓冲您的数据


这是一篇很好的文章,可以解释这一点以及如何解决问题。

您可能会收到更少或更多的邮件,但不能保证您会收到确切的邮件

从MSDN:

无法保证您发送的数据会立即出现在网络上。为了提高网络效率,底层系统可能会延迟传输,直到收集到大量传出数据。BeginSend方法的成功完成意味着基础系统有空间为网络发送缓冲您的数据

是一篇很好的文章来解释这一点以及如何解决您的问题。

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

  • 用消息的长度标记每个消息的开头(http会这样做)
  • 在邮件末尾添加分隔标记(/n)。要让接收者知道何时开始和停止阅读单个消息,请标记消息的开头和结尾(使用无法键入的特殊符号)
总之,您必须注意将流拆分为消息。或者在TCP之上使用HTTP、WebSockets或其他消息格式实现。

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

  • 用消息的长度标记每个消息的开头(http会这样做)
  • 在邮件末尾添加分隔标记(/n)。要让接收者知道何时开始和停止阅读单个消息,请标记消息的开头和结尾(使用无法键入的特殊符号)

总之,您必须注意将流拆分为消息。或者在TCP之上使用HTTP、WebSocket或其他消息格式实现。

这里会出现什么问题?这里没有问题。TCP是一个无穷无尽的流,您描述的行为是标准的和预期的。这取决于您的程序如何处理部分“消息”的传入,以及同时接收多个“消息”。可以使用字节长度前缀、消息分隔符,也可以是这些内容的组合。答案提供了更多的信息。@Idle\u Mind:我想你误解了这个问题。我将所有数据排队放入FIFO缓冲区,我可以轻松解析它,格式定义良好。但问题是:如果Wireshark显示网卡正在接收两个实际的TCP数据包,为什么.NET会创建额外的延迟并将两个数据包合并到一个缓冲区中?我关心的是延迟,而不是解析。第二,TCP并不是“无穷无尽的流”,它是一种以段的形式传输(可能)无穷无尽的数据流的协议。它很可能不是合并传入数据的.NET。这可能已经在操作系统中发生了。如果在短时间内收到包含TCP连接数据的两个数据包,则它们的内容都将被放入TCP接收缓冲区,应用程序将仅从该缓冲区读取。它看不出这是一个还是两个数据包。如果偶尔发生这种情况,则可能是您的应用程序正在忙于某些事情(垃圾收集?),并且在接收到第二个数据包时无法获取第一个数据包。TCP堆栈将缓冲数据并进行处理。它可以随意缓冲数据,并且可以组合“数据包”,或者通过滑动窗口机制停止数据流