类内格尔问题
所以我有这个实时游戏,使用 SFML 库 禁用 nagle 的 C++ 服务器和客户端使用 asyncsocket 也会禁用 nagle。我每 1 秒发送 30 个数据包。从客户端发送到服务器没有问题,但从服务器发送到客户端时,某些数据包发生迁移。例如,如果我在完全不同的数据包中发送“a”和“b”,客户端会将其读取为“ab”。虽然这种情况只会发生一次,但它却在游戏中造成了真正的问题。
那我该怎么办呢?我该如何解决这个问题?也许是服务器里的东西?也许操作系统设置?
需要明确的是:我没有使用 nagle,但我仍然有这个问题。我在客户端和服务器上都禁用了。
so I have this real-time game, with a C++ sever with disabled nagle using SFML library , and client using asyncsocket, also disables nagle. I'm sending 30 packets every 1 second. There is no problem sending from the client to the server, but when sending from the server to the clients, some of the packets are migrating. For example, if I'm sending "a" and "b" in completly different packets, the client reads it as "ab". It's happens just once a time, but it makes a real problem in the game.
So what should I do? How can I solve that? Maybe it's something in the server? Maybe OS settings?
To be clear: I AM NOT using nagle but I still have this problem. I disabled in both client and server.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为您已经忽视了 TCP 的基本性质:它是一个流协议,而不是一个数据包协议。 TCP 既不尊重也不保留发送方的数据边界。换句话说,TCP 可以自由地组合(或拆分!)您发送的“数据包”,并以任何它想要的方式将它们呈现在接收器上。 TCP 遵循的唯一限制是:如果传送了一个字节,则它将按照发送时的顺序传送。 (Nagle 并没有改变这一点。)
因此,如果您在服务器上调用
send
(或write
)两次,发送这六个字节:您的客户端可能会
recv
(或read
)任何这些字节序列:如果您的应用程序需要了解发送者的
write
之间的边界,那么您有责任保存并传输该信息。正如其他人所说,有很多方法可以解决这个问题。例如,您可以在每个信息量之后发送换行符。这(部分)是 HTTP、FTP 和 SMTP 的工作原理。
您可以将数据包长度与数据一起发送。其通用形式称为 TLV,即“类型、长度、值”。发送一个固定长度的类型字段,一个固定长度的长度字段,然后一个任意长度的值。这样您就知道何时已读取整个值并准备好下一个 TLV。
您可以安排发送的每个数据包的长度都相同。
我想还有其他的解决方案,我想你可以自己想到。但首先您必须认识到这一点:TCP 可以并且合并或破坏您的应用程序数据包。您可以依赖字节传送的顺序,但除此之外别无其他。
I think you have lost sight of the fundamental nature of TCP: it is a stream protocol, not a packet protocol. TCP neither respects nor preserves the sender's data boundaries. To put it another way, TCP is free to combine (or split!) the "packets" you send, and present them on the receiver any way its wants. The only restriction that TCP honors is this: if a byte is delivered, it will be delivered in the same order in which it was sent. (And nothing about Nagle changes this.)
So, if you invoke
send
(orwrite
) on the server twice, sending these six bytes:Your client side might
recv
(orread
) any of these sequences of bytes:If your application requires knowledge of the boundaries between the sender's
write
s, then it is your responsibility to preserve and transmit that information.As others have said, there are many ways to go about that. You could, for example, send a newline after each quantum of information. This is (in part) how HTTP, FTP, and SMTP work.
You could send the packet length along with the data. The generalized form for this is called TLV, for "Type, Length, Value". Send a fixed-length type field, a fixed-length length field, and then an arbitrary-length value. This way you know when you have read the entire value and are ready for the next TLV.
You could arrange that every packet you send is identical in length.
I suppose there are other solutions, and I suppose that you can think of them on your own. But first you have to realize this: TCP can and will merge or break your application packets. You can rely upon the order of the bytes' delivery, but nothing else.
您必须在两个对等点中禁用 Nagle。您可能想要找到基于记录的不同协议,例如SCTP
。EDIT2
既然您要求一个协议,我将这样做:
定义消息的标头。假设我会选择 32 位标头。
<前><代码>标题:
味精长度:16b
版本:8b
类型:8b
然后,真正的消息进来,具有
MSG 长度
字节。现在我有了格式,我该如何处理呢?
服务器
当我写一条消息时,我会在前面添加控制信息(实际上,长度是最重要的)并发送整个消息。启用或不启用 NODELAY 没有什么区别。
客户端
我不断地从服务器接收东西,对吧?所以我必须进行某种
读取
。MSG 长度
MSG 长度
字节。现在您已收到消息并可以对其进行处理。无论 TCP 选项(例如 NODELAY)、MTU 限制等如何,这都有效。
You have to disable Nagle in both peers. You might want to find a different protocol that's record-based such asSCTP
.EDIT2
Since you are asking for a protocol here's how I would do it:
Define a header for the message. Let's say I would pick a 32 bits header.
Then the real message comes in, having
MSG Length
bytes.So now that I have a format, how would I handle things ?
Server
When I write a message, I prepend the control information (the length is the most important, really) and send the whole thing. Having NODELAY enabled or not makes no difference.
Client
I continuously receive stuff from the server, right ? So I have to do some sort of
read
.MSG Length
MSG Length
bytes. Now you've got your message and can process itThis works regardless of TCP options (such as NODELAY), MTU restrictions, etc.