【问题标题】:Socket Behaviour - Data written out of order套接字行为 - 乱序写入的数据
【发布时间】:2015-10-15 23:00:39
【问题描述】:

我有一个接口,线程写入套接字并由远程服务器接收。当线程争用变高时,会出现套接字数据乱序的问题。我有一条通过套接字发送的“标准”消息,我可以在字节级别看到第二条逻辑消息正在写入第一条逻辑消息的一半。显然,这意味着接口失败,因为数据已损坏。

在套接字上使用的唯一特殊设置是

m_socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Tcp,
System.Net.Sockets.SocketOptionName.NoDelay, 1)
m_Socket.Connect(m_remoteServerName, m_remoteServerPort)

我尝试了一个简单的解决方案,即锁定我的逻辑消息,所以我的逻辑是:

lock (sending)
{
    msgbytes = GetLogicalMessage();
    m_socket.Send(msgbytes, 0, msgbytes.Length, SocketFlags.None);
}

接收者实际上是在做相反的事情,从每个逻辑消息中读取消息头,然后是消息负载。

正在从多个线程访问 send 方法,但我不知道从哪里看。我查看了代码,所有对套接字的访问都是通过锁定的方法(接收除外)。除了 .Send() 没有按我期望的方式工作之外,我看不到任何明显的东西。根据我的理解,这是一个流,因此缓冲区写入需要完成,即使在调用结束时数据没有被推出套接字。

【问题讨论】:

  • Receive()一样,你必须检查Send()的返回值。并非所有字节都必须写入发送缓冲区(至少在非阻塞模式下)。
  • 我们也看不到 GetLogicalMEssage。我希望您不希望收到与发送相对应的消息。它们可以被切成小块 - 但总是会按顺序到达(或根本不按顺序)
  • 我将逻辑消息序列化到流中。在另一端,我读回逻辑消息并反序列化它们。我知道传输可以以奇怪的方式将它们送到那里,但保证流是有序的。

标签: c# multithreading sockets networking


【解决方案1】:

是的,您对Send 方法的理解是不正确的——它不能保证您给它的所有字节都放入套接字发送缓冲区。缓冲区可能没有足够的空间,因此您必须注意返回值,即复制的字节数。

编辑 0:

通常的技巧是循环send。请注意内核 TCP/IP 堆栈异步耗尽缓冲区的事实,因此下一次对 send 的调用不一定会再次阻塞。

在存在线程的情况下这仍然不是太漂亮,因为您会在发送消息时得到任意延迟。

我可能会建议将套接字处理转移到它自己的线程中,并通过队列将工作线程连接到它,这将适应您的消息传递中的峰值。

【讨论】:

  • 如果字节未完全写入,应采取什么行为?推进缓冲区上的指针并再次调用发送?我假设当我拨打电话时缓冲区已满,如果我再试一次,它仍然是满的
  • @Spence 如果缓冲区已满,您最终可能会旋转一段时间,等待空间将下一个数据块写入。让一个线程处理与通过ConcurrentQueue 向其发布信息的其他人的通信要好得多。然后他们可以继续他们正在做的事情,而无需等待发送完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
  • 2012-05-18
  • 2010-10-26
  • 1970-01-01
  • 1970-01-01
  • 2013-05-25
相关资源
最近更新 更多