如何避免来自同一套接字的消息合并

时间:2015-02-18 16:24:27

标签: c# sockets

类似的问题: C# Socket BeginReceive / EndReceive capturing multiple messages

我目前正在管理网站和winform应用程序之间的通信,这是通过以这种方式创建的websocket来完成的:

Socket socket = new Socket(AddressFamily.InterNetwork, 
SocketType.Stream, 
ProtocolType.Tcp);

如果该emmitter发送两个消息A([TagBeginMessage:lengthMessageA] aaaaaaaaaaaaaaaa [EndMessage])和B([TagBeginMessage:lengthMessageB] bbbbbbbbbbbbbbbbbbb [EndMessage]),我期望接收机将得到

[TagBeginMessage:lengthMessageA] aaaaaaaaaaaaaaaa [EndMessage] [TagBeginMessage:lengthMessageB] bbbbbbbbbbbbbbbbbbb [EndMessage]

[TagBeginMessage:lengthMessageB] bbbbbbbbbbbbbbbbbbb [EndMessage] [TagBeginMessage:lengthMessageA] aaaaaaaaaaaaaaaa [EndMessage]

对于绝大多数消息来说确实如此,但是当消息A很长并且消息B非常短时,接收的必要异步性质有时会导致错误,其中接收者得到这个:

[TagBeginMessage:lengthMessageA] aaaaaaaaaa [TagBeginMessageB:lengthMessageB] bbbbbbbbbbbbbbbbbbb [EndMessage] aaaaaa [EndMessageA]

虽然它需要每条消息的唯一结尾,但仍然可以对其进行解析。但是,虽然我没有看到它,但我担心这意味着以下情况也是可能的(由于套接字通过数据包发送数据):

[TagBeginMessage:lengthMessageA] aaaaa [TagBeginMessageB:lengthMessageB] bbbbbbaaaabbbbbbbbbbbbb [EndMessage] aaaaaa [EndMessageA]

这是不可解析的。在消息开头添加长度(如http://blog.stephencleary.com/2009/04/sample-code-length-prefix-message.html中所示)表示问题但未解决。我该怎么做才能避免这种情况?

我目前的解决方案是:

  • 发送小信息。不优雅,但应该工作。
  • 发送非常小的消息,表示套接字的缓冲区为空。

3 个答案:

答案 0 :(得分:3)

听起来您正在同时从多个线程向同一连接发送数据。没问题,但如果你这样做,请确保在发送逻辑包(长度+数据)的过程中锁定与当前线程的连接 - 这样你就会收到一个完整的数据包(从一个发送线程)在接收不同线程发送的任何内容之前。

在TCP / IP下,保证包的顺序与它们发送的顺序相同,但如果你从一个线程发送半个逻辑包(长度+数据),然后从另一个线程发送半个包,那么协议层或接收端无法知道这一点。

答案 1 :(得分:2)

您已经链接到Stephen Cleary的博客,因此您知道tcp要求您进行某种形式的消息框架。 Here is the another one of Cleary's posts that describe your problem.

简而言之,您必须构建tcp消息。你也应该永远不会看到你的最终,不可解决的例子。 Tcp将以正确的顺序发送您的所有数据。

答案 2 :(得分:0)

我不是插座专家,但我有一些经验。您可以做的是拆分正在发送的数据。假设您有一个非常长的字符串,其中包含以下内容:" AAAAAAAABBBBBBCCCCDDDDDEEE"。您可以做的不是一次性发送整个字符串通过套接字,而是发送所有A字符然后是B然后是C然后是D等。在用户收到消息之前,您可以将所有字符合并在一起。这只是一个想法。