类似Nagle的问题

时间:2011-07-07 09:21:43

标签: tcp network-programming real-time asyncsocket sfml

所以我有这个实时游戏,使用SFML library禁用nagle的C ++服务器,使用asyncsocket的客户端,也禁用nagle。我每1秒发送30个数据包。从客户端发送到服务器没有问题,但是当从服务器发送到客户端时,一些数据包正在迁移。例如,如果我在完全不同的数据包中发送“a”和“b”,则客户端将其读作“ab”。它只发生一次,但它在游戏中成为一个真正的问题。

那我该怎么办?我怎么解决这个问题?也许这是服务器中的东西?也许OS设置?

要明确:我没有使用nagle,但我仍然有这个问题。我在客户端和服务器都禁用了。

2 个答案:

答案 0 :(得分:3)

  

例如,如果我在完全不同的数据包中发送“a”和“b”,则客户端将其读作“ab”。它只发生一次,但它在游戏中成为一个真正的问题。

我认为您已经忽略了TCP的基本特性:它是一种流协议,而不是数据包协议。 TCP既不尊重也不保留发送方的数据边界。换句话说,TCP可以自由组合(或拆分!)您发送的“数据包”,并以任何方式将它们呈现在接收器上。 TCP尊重的唯一限制是:如果传递一个字节,它将按照发送的顺序传递。 (而且Nagle没有改变这一点。)

所以,如果你在服务器上调用send(或write)两次,发送这六个字节:

"packet" 1: A B C
"packet" 2: D E F

您的客户端可能recv(或read)这些字节序列中的任何一个:

ABC / DEF
ABCDEF
AB / CD / EF

如果您的应用程序需要了解发件人write之间的界限,那么您有责任保留和传输该信息。

正如其他人所说,有很多方法可以解决这个问题。例如,您可以在每个信息量之后发送换行符。这(部分)是HTTP,FTP和SMTP的工作方式。

您可以将数据包长度与数据一起发送。这种广义形式称为TLV,用于“类型,长度,值”。发送固定长度类型字段,固定长度字段,然后发送任意长度值。通过这种方式,您可以了解何时已读取整个值并准备好下一个TLV。

您可以安排发送的每个数据包的长度相同。

我想还有其他解决方案,我想你可以自己想一想。但首先你必须意识到这一点:TCP可以合并或破坏你的应用程序包。你可以依赖字节传递的顺序,但没有别的。

答案 1 :(得分:1)

你必须在两个对等体中禁用Nagle 。您可能希望找到基于记录的其他协议,例如SCTP

EDIT2

由于你在这里要求协议,我将如何做:

  • 定义邮件的标头。假设我会选择一个32位的标题。

    Header:
        MSG Length: 16b
        Version: 8b
        Type: 8b
    
  • 然后真正的消息进来,有MSG Length个字节。

所以现在我有一个格式,我该如何处理?

服务器

当我写一条消息时,我会预先设置控制信息(长度是最重要的,真的)并发送整个信息。启用NODELAY或不启用NODELAY没有任何区别。

客户端

我不断从服务器收到东西,对吧?所以我必须做某种read

  • 从服务器读取字节。任何金额都可以到达。继续阅读,直到你至少有4个字节。
  • 获得这4个字节后,将它们解释为标题并提取MSG Length
  • 继续阅读,直到您获得至少MSG Length个字节。现在您已收到消息并可以处理

无论TCP选项(如NODELAY),MTU限制等等,都可以使用