Мой провайдер заставляет меня буферизовать tcp-данные перед отправкой - PullRequest
12 голосов
/ 09 марта 2012

У меня есть игровой сервер Java TCP, я использую java.net.ServerSocket, и все работает просто отлично, но недавно мой провайдер провёл какое-то обновление, где, если вы очень быстро отправляете два пакета для одного и того же соединения TCP, онизакройте его силой.

Вот почему многие мои игроки случайно отключаются, когда в игре много трафика (когда есть большая вероятность, что сервер отправит 2 пакета одновременно длятот же человек)

Вот пример того, что я имею в виду: если я сделаю что-то подобное, мой провайдер без причины закроет соединение как со стороны клиента, так и со стороны сервера:

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, я заметил, что между двумя пакетами должно быть не менее ~ 150 мс для одного и того же соединения TCP, иначе он закроется.

1) Ребята, вы знаете, как это называется?у него вообще есть имя?Это законно?

Теперь я должен переписать свой игровой сервер, зная, что я использую метод под названием: send(PrintWriter out, String packetData);

2) Есть ли простое решение, чтобы попросить Java буферизоватьданные, прежде чем он отправит его клиентам?Или подождать 150 мс перед каждой отправкой без необходимости переписывать все это?Я немного погуглил, но не могу найти ничего, что решает эту проблему.Буду очень признателен за любые советы или информацию, которые могут помочь в этом. Оптимизация скорости очень важна.Спасибо.

Ответы [ 2 ]

5 голосов
/ 11 марта 2012

Если ваш интернет-провайдер налагает такие политики качества обслуживания, и у вас нет возможности договориться о них с ними, я предлагаю вам также применить эти правила с помощью конфигурации QoS стека TCP / IP.

Сброс помечает ваш пакет TCP как срочный (флаг URG), чтобы он отправлялся независимо от состояния окна буфера / окна TCP. Теперь вы должны указать своей операционной системе или любому сетевому оборудованию на линии либо

  • игнорировать (или просто сбрасывать) флаг срочности, когда предыдущий пакет был отправлен за последние 150 мс, и при необходимости выполнять некоторую буферизацию
  • задержка доставки последовательных срочных пакетов для соблюдения ограничения 150 мс.

Вероятно, для этого существует дорогое программное обеспечение для Windows. Лично я думаю, что установка Linux-бокса в качестве маршрутизатора между вашими рабочими станциями Windows и модемом с соответствующими настройками QoS в iptables и qdisc поможет.

3 голосов
/ 16 марта 2012

Вы можете создать реализацию оболочки 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();
    }

}

Теперь этого должно быть достаточно, чтобы обернуть имеющиеся у вас PrintWriter этим ControlledFlushWriter, чтобы обойти QoS вашего провайдера без переписывания всего приложения.

В конце концов, кажется разумным не допустить, чтобы соединение помечало какой-либо пакет как срочное ... В таких условиях сложно реализовать справедливое совместное использование ссылок QoS.

...