C# 异步TCP套接字字节合并

C# 异步TCP套接字字节合并,c#,.net,C#,.net,我不太确定如何在标题中解释我的问题,但我将尝试详细说明我的问题 基本上,我编写的聊天不是P2P,而是所有用户连接到一个中央服务器,类似于IRC。这些连接是异步的,几乎可以完美地工作。主要问题是,当大量数据同时发送到一个用户(或从一个用户发送到服务器)时,字节可能会合并,从而导致错误。我通过在其余数据前面添加一个包含数据长度的4字节头来实现这一点。不过,字节似乎合并了。我还尝试将NoDelay设置为true并将dontframent设置为false;不过,它还是不起作用 我猜问题是,当字节合并时,

我不太确定如何在标题中解释我的问题,但我将尝试详细说明我的问题

基本上,我编写的聊天不是P2P,而是所有用户连接到一个中央服务器,类似于IRC。这些连接是异步的,几乎可以完美地工作。主要问题是,当大量数据同时发送到一个用户(或从一个用户发送到服务器)时,字节可能会合并,从而导致错误。我通过在其余数据前面添加一个包含数据长度的4字节头来实现这一点。不过,字节似乎合并了。我还尝试将NoDelay设置为true并将dontframent设置为false;不过,它还是不起作用

我猜问题是,当字节合并时,我只处理第一个字节,然后对剩余的字节不做任何处理。处理这个问题的最佳方式是什么


接收回调代码:

这就是为什么他们称之为流。您将字节放在一端,TCP保证它们在远端以相同的顺序出现,没有丢失或重复。任何大于一个字节的都是你的问题

您必须在缓冲区中累积足够的字节,以获得标头。然后解释它并开始处理额外的字节。你可能有一些剩余的开始下一个标题


这是正常的行为。当应用程序未接收数据时,系统将为您缓冲数据。下次您提出请求时,它将尝试移交可用数据。另一方面,大型写操作可能会在不支持足够帧大小的连接上进行。它们将根据需要进行分割,最终以点滴的形式到达。

这就是为什么他们称之为流。您将字节放在一端,TCP保证它们在远端以相同的顺序出现,没有丢失或重复。任何大于一个字节的都是你的问题

您必须在缓冲区中累积足够的字节,以获得标头。然后解释它并开始处理额外的字节。你可能有一些剩余的开始下一个标题


这是正常的行为。当应用程序未接收数据时,系统将为您缓冲数据。下次您提出请求时,它将尝试移交可用数据。另一方面,大型写操作可能会在不支持足够帧大小的连接上进行。它们将根据需要进行拆分,并最终以点滴方式到达。

这通常发生在两个或多个数据包以紧密间隔发送时。 最近我自己也遇到了这个问题,我解决这个问题的方法是用一把分开的钥匙。然后可以标记每条消息。例如,您可以像我一样将ASCII字符#4(传输结束字符)添加到发送的每条消息的末尾

Write("Message1" + ((char)4).ToString())
Write("Message2" + ((char)4).ToString())
然后,当客户机接收到数据时,您可以迭代接收到的数据。当它发现那个特殊的字符时,它知道这是一条消息的结束,也可能是一条新消息的开始

"Message1(EOT char)Message2(EOT char)"

\n
可能比使用ASCII字符更容易操作。

这通常发生在两个或多个数据包以紧密间隔发送时。 最近我自己也遇到了这个问题,我解决这个问题的方法是用一把分开的钥匙。然后可以标记每条消息。例如,您可以像我一样将ASCII字符#4(传输结束字符)添加到发送的每条消息的末尾

Write("Message1" + ((char)4).ToString())
Write("Message2" + ((char)4).ToString())
然后,当客户机接收到数据时,您可以迭代接收到的数据。当它发现那个特殊的字符时,它知道这是一条消息的结束,也可能是一条新消息的开始

"Message1(EOT char)Message2(EOT char)"

\n
可能比使用ASCII字符更容易操作。

解决此问题的最佳方法是什么?
向我们展示您的代码会有很大帮助。@orzechowskid当然。在op.on中添加了接收回调源的链接,因此习惯上是向问题添加代码,而不是链接到问题。如果代码太长,请将其简化为一个简短的自包含的问题示例。好的,谢谢您让我知道spender。
解决此问题的最佳方法是什么?
向我们展示您的代码会有很大帮助。@orzechowskid当然。在op.on中添加了接收回调源的链接,因此习惯上是向问题添加代码,而不是链接到问题。如果代码太长,请将其简化为一个简短的自包含的问题示例。好的,感谢您让我知道spender。因此,最好的解决方案是这样的:读取缓冲区,获取数据长度,检查数据长度+4=读取长度,如果读取长度>数据长度+4处理缓冲区的其余部分?我不确定我是否说得很清楚。当你在处理头和体之间交替时,状态机使这变得更容易。继续将接收到的数据附加到缓冲区。每次读取完成时:如果缓冲区长度>=标头长度,则处理标头。若剩余缓冲区长度>=消息正文长度,则处理消息。并检查是否已经有下一个标题。(起泡、冲洗、重复)在尝试你的建议之前,我尝试了另一种方法。首先,我异步读取4个字节,显然包含数据的长度。然后,我做一个循环,直到收到所有数据为止。我将所有数据写入一个流,并在收到数据后进行处理。然后,它重复并再次读取4个字节。您对这种方法有何看法?需要处理的问题是:(1)初始读取不能在接收4字节之前完成。(2) 在读取消息正文时,必须确保最后一次读取在消息结束的地方结束,或者缓冲到达的任何附加字节。您选择的API可能会限制您的选择。至于完成消息的重新组装只是将其放入另一个流,这比我选择的开销要大。而一个流仅仅是个字节