3

我正在编写一个套接字服务器和 Flash 游戏客户端。游戏需要实时命令,例如移动和转弯。服务器尽快将这些命令发送到客户端非常重要,因为否则其他客户端将与移动/转动的客户端发生很多不同步。

这是由 Nagle 算法引起的问题的一个示例:

注意:如果您想了解这些命令的含义,请参阅下面的命令表。

第一个是我移动的船(前移+右移,前移已收到但右未收到)

客户端发送命令:

84796: Sending data: 2#4
84796: Sending data: 2#2
84904: Sending data: 2#3
84904: Sending data: 2#0
86187: Sending data: 2#4
86188: Sending data: 2#2
86374: Sending data: 2#3
86404: Sending data: 2#0

客户端接收命令:

79244: Raw receive: 3#3#4$
79244: New command: 3#3#4
79398: Raw receive: 3#3#2$3#3#3$3#3#0$
79399: New command: 3#3#2
79399: New command: 3#3#3
79399: New command: 3#3#0
80635: Raw receive: 3#3#4$
80635: New command: 3#3#4
80908: Raw receive: 3#3#2$3#3#3$3#3#0$
80908: New command: 3#3#2
80908: New command: 3#3#3
80908: New command: 3#3#0

“时刻”是一个奇怪的术语,并不意味着我想说什么,但这里似乎是上一个命令之后的毫秒数

  1. 客户端 A 向前发送(时刻:0),客户端 B 接收(时刻:0)

  2. 右转由客户端 A 发送(时刻:0),由客户端 B 接收(时刻:155)

  3. 停止移动客户端A发送(时刻:108),客户端B接收(时刻:0)

  4. 停止由客户端 A 发送(时刻:0),由客户端 B 接收(时刻:0)

  5. 客户端 A 向前发送(时刻:1283),客户端 B 接收(时刻:1236)

  6. 右转由客户端 A 发送(时刻:1),由客户端 B 接收(时刻:273)

  7. 停止移动由客户端 A 发送(时刻:186),由客户端 B 接收(时刻:0)

  8. 停止由客户端 A 发送(时刻:30),由客户端 B 接收(时刻:0)

这是与命令对应的命令表:

客户端-> 服务器

2# (movement info)
0) now not turning
1) now turning left
2) now turning right
3) now not moving
4) now moving forward

服务器-> 客户端

3# (movement info)
[shipId]#
0) now not turning
1) now turning left
2) now turning right
3) now not moving
4) now moving forward

因此,您可以看到,由于“Nagle”,这些命令完全不同步。这导致停止移动命令与开始移动命令同时被其他客户端接收,导致该玩家根本不移动。

这就是为什么我需要通过 TCP 服务器尽可能快地实时发送这些命令。一个简单的解决方法是简单地禁用 Nagle。但是,我已经搜索了一下(注意他关于 tcp message partial 的建议已在我的系统中实现,但与时间无关)并注意到人们绝对不建议禁用 Nagle。

我真的不应该因为这个原因禁用 Nagle 算法,而是应该寻找其他解决方案吗?为什么不)?

提前致谢。- 汤姆

4

5 回答 5

5

您想使用 TCP_NODELAY 关闭该套接字的 nagle 算法。现代操作系统中有一些设置可以在系统范围内禁用它,这不受欢迎的,但没有理由不使用你知道需要低延迟的套接字来执行此操作。

setsockopt(TCP_NODELAY)

于 2009-10-22T21:08:13.027 回答
2

如果需要尽可能快,则应使用 UDP。

但是,请注意 TCP 提供交付订单保证,而 UDP 不提供。

这一点似乎是该应用程序中至关重要的一点,因此您必须将自己的确认/重试命令排序机制置于顶部。

如果你想坚持使用 TCP,TCP__NODELAY 会有所帮助。随着游戏的进展,您最终可能需要 TCP 非常适合没有 TCP_NODELAY 的数据流。

RFC1006 形式化了一种通过 TCP 流发送数据包的机制。

于 2009-10-22T21:30:53.693 回答
1

请注意,您的交换机、路由器、ISP 的交换机……等都可能会弄脏它们的黑色小胆。肮脏的小野兽可以读取数据包,因此它们会冒昧并有时会重写它们。

查看 RTP(通过 UDP 运行)以获得更多的网络生存方法。

于 2009-10-22T21:15:00.437 回答
1

如果你的目标是让船只最终在每个人的屏幕上做同样的事情,你将不得不发送位置更新。你不能仅仅因为客户 A 做了:

  • 左转
  • 等待 100 毫秒
  • 停止转动

客户端 B 将看到完全相同的 100 毫秒延迟。Nagle 缓冲只是让这变得更加极端——但总会有抖动和不同的延迟。

你真的需要发送类似的东西:

  • (我在位置 X1,Y1,航向 Z1)左转
  • (我在位置 X2,Y2,航向 Z2)停止转动

以便客户端不断地重新同步。

于 2009-10-22T23:04:47.300 回答
1

请注意,Windows 实现延迟 ACK以及 Nagle。这可以给你一个额外的 200 毫秒的单个 TCP 消息延迟。据我所知,您无法在 Windows 上更改此设置,除非通过注册表项(以及在某些情况下启用注册表项的热补丁)。

于 2009-11-01T13:55:34.643 回答