0

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

所以我该怎么做?我该如何解决?也许它是在服务器中的东西?也许操作系统设置?

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

4

2 回答 2

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 可以并且将会合并或破坏你的应用程序包。您可以依赖字节传递的顺序,但仅此而已。

于 2011-07-07T17:24:33.637 回答
1

您必须在两个对等方中禁用 Nagle。您可能希望找到基于记录的不同协议,例如SCTP.

编辑2

既然你要求一个协议,我会这样做:

  • 定义消息的标头。假设我会选择一个 32 位的标头。

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

所以现在我有了一个格式,我将如何处理事情?

服务器

当我写一条消息时,我会在前面加上控制信息(长度是最重要的,真的)并发送整个信息。是否启用 NODELAY 没有区别。

客户

我不断地从服务器接收东西,对吧?所以我必须做一些事情read

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

无论 TCP 选项(例如 NODELAY)、MTU 限制等如何,这都有效。

于 2011-07-07T09:31:22.107 回答