所以我有这个实时游戏,使用SFML library禁用nagle的C ++服务器,使用asyncsocket的客户端,也禁用nagle。我每1秒发送30个数据包。从客户端发送到服务器没有问题,但是当从服务器发送到客户端时,一些数据包正在迁移。例如,如果我在完全不同的数据包中发送“a”和“b”,则客户端将其读作“ab”。它只发生一次,但它在游戏中成为一个真正的问题。
那我该怎么办?我怎么解决这个问题?也许这是服务器中的东西?也许OS设置?
要明确:我没有使用nagle,但我仍然有这个问题。我在客户端和服务器都禁用了。
答案 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
。
由于你在这里要求协议,我将如何做:
定义邮件的标头。假设我会选择一个32位的标题。
Header:
MSG Length: 16b
Version: 8b
Type: 8b
然后真正的消息进来,有MSG Length
个字节。
所以现在我有一个格式,我该如何处理?
当我写一条消息时,我会预先设置控制信息(长度是最重要的,真的)并发送整个信息。启用NODELAY或不启用NODELAY没有任何区别。
我不断从服务器收到东西,对吧?所以我必须做某种read
。
MSG Length
MSG Length
个字节。现在您已收到消息并可以处理无论TCP选项(如NODELAY),MTU限制等等,都可以使用