我有一个Java TCP游戏服务器,我使用java.net.ServerSocket
并且一切运行得很好,但最近我的ISP做了某种升级,如果你为同一个TCP连接发送两个数据包非常快,他们强行关闭它。
这就是为什么我的很多玩家在游戏中有大量流量时会随机断开连接(当服务器有很多机会同时为同一个人发送2个数据包时)
这是我的意思的一个例子: 如果我做这样的事情,我的ISP将无缘无故地关闭连接到客户端和服务器端:
tcpOut.print("Hello.");
tcpOut.flush();
tcpOut.print("How are you?");
tcpOut.flush();
但如果我做这样的话,它会工作得很好:
tcpOut.print("Hello.");
tcpOut.flush();
Thread.sleep(200);
tcpOut.print("How are you?");
tcpOut.flush();
或者这个:
tcpOut.print("Hello.");
tcpOut.print("How are you?");
tcpOut.flush();
这仅在几周前开始,当时他们(ISP)对服务和网络进行了一些更改。我注意到使用Wireshark你必须在两个数据包之间至少有大约150ms的时间用于相同的TCP连接,否则它将关闭。
1)你们知道这叫什么吗?是甚至有名字?这是合法的吗?
现在我必须重新编写我的游戏服务器,因为我知道我使用的方法是:send(PrintWriter out, String packetData);
2)在将数据发送给客户端之前,是否有任何简单的解决方案要求java缓冲数据?或者在每次发送前等待150ms而不必重写整个事情?我做了一些谷歌搜索,但我找不到任何处理这个问题。任何有关此问题的提示或信息都会非常感激,顺便提一下速度优化非常关键。谢谢。
答案 0 :(得分:5)
如果您的ISP施加了这样的服务质量策略,并且您无法与之协商,我建议您使用TCP / IP堆栈QoS配置来强制执行该规则。
flush将TCP数据包标记为紧急(URG标志),以便无论缓冲区/ TCP窗口状态如何都会发送。现在您必须告诉您的操作系统或线路上的任何网络设备
可能存在一个昂贵的Windows软件。就个人而言,我认为在Windows工作站和调制解调器之间使用Linux框作为路由器与iptables和qdisc中的appropriate QoS settings一起使用。
答案 1 :(得分:3)
您可以创建一个Writer
包装器实现来跟踪最后flush
个呼叫时间戳。一个快速实现是添加一个等待调用,以纪念两次连续刷新之间的150 ms延迟。
public class ControlledFlushWriter extends Writer {
private long enforcedDelay = 150;
private long lastFlush = 0;
private Writer delegated;
public ControlledFlushWriter(Writer writer, long flushDelay) {
this.delegated = writer:
this.enforcedDelay = flushDelay;
}
/* simple delegation for other abstract methods... */
public void flush() {
long now = System.currentTimeMillis();
if (now < lastFlush + enforcedDelay) {
try {
Thread.sleep(lastFlush + enforcedDelay - now);
} catch (InterruptedException e) {
// probably prefer to give up flushing
// instead of risking a connection reset !
return;
}
}
lastFlush = System.currentTimeMillis();
this.delegated.flush();
}
}
现在应该足以将现有的PrintWriter
与此ControlledFlushWriter
一起包装,以解决您的ISP QoS问题,而无需重新编写所有应用程序。
毕竟,防止连接将其任何数据包标记为紧急是合理的......在这种情况下,很难实现公平的QoS链接共享。