Java TCP 延迟

4
我正在开发一款Android应用程序,通过WLAN连接与TCP Java服务器通信。这个Android应用程序是一个带有精灵的游戏,精灵在屏幕上移动。每当一个精灵移动时,Android客户端会将其坐标发送到Java服务器,然后服务器将数据发送给其他客户端(最多4个客户端)。服务器在单独的线程上处理每个客户端,数据更新大约每20毫秒发送一次,每个数据包由1-10字节组成。我在70 Mbit网络上(无线网络实际效果约为15 Mbit)。
我遇到了不稳定的连接问题,并且在每10-30个数据包中经历了50-500毫秒的延迟。我已经将tcpNoDelay设置为true,这停止了持续200毫秒的延迟,但仍然存在很多卡顿。由于我对Android和网络都比较新,我不知道这是否是可以预期的。我也想知道UDP是否适合我的程序,因为我希望快速发送更新,而不是每个数据包都正确到达。
我希望得到任何关于如何避免/解决这个延迟问题的指导。对于如何实现这样的客户端-服务器架构的一般提示也将受到赞赏。

2
UDP 绝对听起来是更好的选择。 - MK.
对于一个游戏,你可能想要添加一些预测(你可能已经在某些游戏中看到了错误预测的影响)。 - ninjalj
使用Wireshark或Tcpdump捕获网络活动并在此处发布。 - gudok
听起来你的协议并不适用于低延迟的TCP传输。你能解释一下它是如何工作的吗?例如,它是如何确保ACK piggybacking的?当你将tcpNoDelay设置为true时,它实际上有所帮助,而不是阻碍,这表明你的协议从未被设计用于低延迟的TCP传输。我的猜测是:1)你的编写代码可能很糟糕,并将部分应用程序级消息推送到传输层。2)你的协议可能很糟糕,并且在需要减少延迟的地方没有应用程序级别的确认。 - David Schwartz
2个回答

2
在无线局域网中,您偶尔会看到丢包现象,这会导致延迟后的数据包重传。如果您想控制重传前的延迟时间,那么几乎肯定需要使用UDP协议。

0

你肯定想使用UDP。对于游戏来说,如果精灵的位置在短时间内不正确,也无所谓。所以在这种情况下,UDP是理想的选择。

另外,如果你对服务器代码有控制权,我不建议为客户端使用单独的线程。线程在需要调用无法控制并且可能会阻塞的库(例如因为它们涉及文件或尝试执行额外的网络通信)时很有用。但是它们是昂贵的。它们消耗大量资源,因此实际上会使事情变得更慢

所以对于网络游戏服务器,延迟和性能绝对至关重要,我只会使用一个线程来处理具有状态的命令队列,并确保您永远不会执行阻塞操作。因此,每个命令按顺序处理,其状态被评估和更新(例如激光爆炸与其他对象相交)。如果命令需要阻塞(例如从文件中读取),那么您需要执行非阻塞读取,并相应地设置该命令的状态,以便您的命令处理器永远不会阻塞。关键是命令处理器绝对不能阻塞。它将在循环中运行,但您必须以适当的方式调用Thread.sleep(x),以免浪费CPU。

关于客户端,当客户端提交命令(比如他们发射了激光之类的),客户端将生成一个响应对象并将其插入到一个以序列 ID 为键的 Map 中。然后它会发送带有序列 ID 的请求,当服务器用该 ID 响应时,您只需在 Map 中查找响应对象并将响应解码为该对象即可。这意味着您可以执行并发操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接