我的ISP强迫我在发送之前缓冲tcp数据

Rea*_*cen 12 java networking tcp wireshark

我有一个Java TCP游戏服务器,我使用java.net.ServerSocket并且一切运行得很好,但最近我的ISP做了某种升级,其中,如果你为同一个TCP连接快速发送两个数据包,他们会强制关闭它.

这就是为什么我的很多玩家在游戏中有大量流量的情况下随机断开连接(当服务器有很多机会同时为同一个人发送2个数据包时)

这是我的意思的一个例子:如果我做这样的事情,我的ISP将无缘无故地关闭连接到客户端和服务器端:

tcpOut.print("Hello.");
tcpOut.flush();

tcpOut.print("How are you?");
tcpOut.flush();
Run Code Online (Sandbox Code Playgroud)

但是如果我做这样的事情,它会工作得很好:

tcpOut.print("Hello.");
tcpOut.flush();

Thread.sleep(200);

tcpOut.print("How are you?");
tcpOut.flush();
Run Code Online (Sandbox Code Playgroud)

或这个:

tcpOut.print("Hello.");
tcpOut.print("How are you?");
tcpOut.flush();
Run Code Online (Sandbox Code Playgroud)

这只是在几周前他们(ISP)对服务和网络进行了一些更改时才开始的.我注意到使用Wireshark你必须在两个数据包之间至少有大约150ms的时间用于相同的TCP连接,否则它将关闭.

1)你们知道这叫什么?是甚至有名字?这合法吗?

现在我必须重新编写我的游戏服务器,知道我使用了一个名为的方法: send(PrintWriter out, String packetData);

2)在将数据发送给客户端之前,是否有任何简单的解决方案要求java缓冲数据?或者在每次发送前等待150ms而不必重写整个事情?我做了一些谷歌搜索,但我找不到任何处理这个问题.任何有关此问题的提示或信息都会非常感激,顺便提一下速度优化非常关键.谢谢.

Yve*_*tin 5

如果您的ISP施加了这样的服务质量策略而您无法与之协商,我建议您使用TCP/IP堆栈QoS配置来强制执行该规则.

刷新将TCP数据包标记为紧急(URG标志),以便无论缓冲区/ TCP窗口状态如何都会发送.现在,您必须告诉您的操作系统或线路上的任何网络设备

  • 当前一个数据包在最后150毫秒内被发送时忽略(或简单地重置)紧急标志,并在必要时进行一些缓冲
  • 延迟连续紧急数据包的传递以兑现150毫秒的约束.

可能是一个昂贵的Windows软件.就个人而言,我认为在Windows工作站和调制解调器之间使用Linux框作为路由器,在iptables和qdisc中使用适当的QoS设置就可以了.


Yve*_*tin 3

您可以创建一个Writer包装器实现来跟踪上次flush调用时间戳。一个快速实现是添加一个等待调用,以实现两次连续刷新之间的 150 毫秒延迟。

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();
    }

}
Run Code Online (Sandbox Code Playgroud)

现在应该足以用PrintWriter它来包装您的现有内容ControlledFlushWriter,以解决您的 ISP QoS,而无需重新编写所有应用程序。

毕竟,阻止连接将其任何数据包标记为紧急听起来很合理……在这种情况下,很难实现公平的 QoS 链路共享。