类内格尔问题

发布于 2024-11-18 15:33:51 字数 427 浏览 5 评论 0原文

所以我有这个实时游戏,使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三月梨花 2024-11-25 15:33:51

例如,如果我在完全不同的数据包中发送“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 可以并且合并或破坏您的应用程序数据包。您可以依赖字节传送的顺序,但除此之外别无其他。

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.

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 (or write) on the server twice, sending these six bytes:

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

Your client side might recv (or read) any of these sequences of bytes:

ABC / DEF
ABCDEF
AB / CD / EF

If your application requires knowledge of the boundaries between the sender's writes, 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.

温暖的光 2024-11-25 15:33:51

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

EDIT2

既然您要求一个协议,我将这样做:

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

    <前><代码>标题:
    味精长度:16b
    版本:8b
    类型:8b

  • 然后,真正的消息进来,具有 MSG 长度 字节。

现在我有了格式,我该如何处理呢?

服务器

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

客户端

我不断地从服务器接收东西,对吧?所以我必须进行某种读取

  • 从服务器读取字节。任何金额都可以到达。继续阅读,直到至少获得 4 个字节。
  • 获得这 4 个字节后,将它们解释为标头并提取 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 as SCTP.

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.

    Header:
        MSG Length: 16b
        Version: 8b
        Type: 8b
    
  • 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.

  • Read bytes from the server. Any amount can arrive. Keep reading until you've got at least 4 bytes.
  • Once you have these 4 bytes, interpret them as the header and extract the MSG Length
  • Keep reading until you've got at least MSG Length bytes. Now you've got your message and can process it

This works regardless of TCP options (such as NODELAY), MTU restrictions, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文