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

Tcp 唠叨样问题 P>所以我有这个实时游戏,用C++的服务器,用禁用的NGLE使用,客户端使用,也禁用NAGLE。我每1秒发30包。从客户端发送到服务器没有问题,但是当从服务器发送到客户端时,一些数据包正在迁移。例如,如果我在完全不同的数据包中发送“a”和“b”,则客户端将其读取为“ab”。这种情况一次只发生一次,但它在游戏中造成了真正的问题,tcp,network-programming,real-time,asyncsocket,sfml,Tcp,Network Programming,Real Time,Asyncsocket,Sfml,那我该怎么办?我怎样才能解决这个问题?也许是服务器里的东西?也许是操作系统设置 要明确的是:我没有使用nagle,但我仍然有这个问题。我在客户端和服务器中都禁用了Nagle。您必须在两个对等机中禁用Nagle。您可能希望找到另一个基于记录的协议,例如SCTP 编辑2 既然你要的是协议,我就这样做: 定义消息的标题。假设我选择一个32位的头 Header: MSG Length: 16b Version: 8b Type: 8b 然后真正的消息进入,具有MSG长度字节

那我该怎么办?我怎样才能解决这个问题?也许是服务器里的东西?也许是操作系统设置

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

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

编辑2 既然你要的是协议,我就这样做:

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

    Header:
        MSG Length: 16b
        Version: 8b
        Type: 8b
    
  • 然后真正的消息进入,具有
    MSG长度
    字节

既然我有了一个格式,我该如何处理呢

服务器 当我写一条消息时,我预先准备了控制信息(长度是最重要的,真的)并发送整个消息。启用或不启用节点延迟没有区别

客户 我不断地从服务器接收东西,对吗?所以我必须做一些
阅读

  • 从服务器读取字节。任何数量都可以到达。继续阅读,直到你至少有4个字节
  • 一旦有了这4个字节,就将它们解释为头并提取
    MSG长度
  • 继续阅读,直到至少有
    MSG Length
    字节。现在,您已经收到消息并可以处理它了
无论TCP选项(如节点延迟)、MTU限制等如何,此功能都有效。

您必须在两个对等节点中禁用Nagle。您可能希望找到另一个基于记录的协议,例如
SCTP

编辑2 既然你要的是协议,我就这样做:

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

    Header:
        MSG Length: 16b
        Version: 8b
        Type: 8b
    
  • 然后真正的消息进入,具有
    MSG长度
    字节

既然我有了一个格式,我该如何处理呢

服务器 当我写一条消息时,我预先准备了控制信息(长度是最重要的,真的)并发送整个消息。启用或不启用节点延迟没有区别

客户 我不断地从服务器接收东西,对吗?所以我必须做一些
阅读

  • 从服务器读取字节。任何数量都可以到达。继续阅读,直到你至少有4个字节
  • 一旦有了这4个字节,就将它们解释为头并提取
    MSG长度
  • 继续阅读,直到至少有
    MSG Length
    字节。现在,您已经收到消息并可以处理它了
无论TCP选项(如节点延迟)、MTU限制等如何,此功能都有效

例如,如果我在完全不同的数据包中发送“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
如果您的应用程序需要了解发送方的
写入
s之间的边界,则您有责任保存和传输该信息

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

您可以将数据包长度与数据一起发送。通用形式称为TLV,表示“类型、长度、值”。发送固定长度类型字段、固定长度字段,然后发送任意长度值。这样,您就可以知道何时读取了整个值并准备好进行下一个TLV

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

我想还有其他的解决办法,我想你可以自己想办法。但首先您必须认识到:TCP可以并且将合并或破坏您的应用程序数据包。您可以依赖字节的传递顺序,但不能依赖其他内容

例如,如果我在完全不同的数据包中发送“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
如果您的应用程序需要了解