Мой провайдер вынуждает меня буферизовать данные tcp перед отправкой
У меня есть игровой сервер 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 мс перед каждой отправкой, не переписывая все это? Я сделал некоторые поисковые запросы, но я не могу найти ничего, что касается этой проблемы. Любые советы или информация, чтобы помочь в этом, были бы очень оценены, btw оптимизация скорости очень важна. Спасибо.
Ответы
Ответ 1
Вы можете создать реализацию обертки 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.
Ответ 2
Если ваш интернет-провайдер накладывает такое качество политик обслуживания, и у вас нет способа согласовать их с ним, я предлагаю вам обеспечить соблюдение этих правил на вашей стороне с конфигурацией QoS с протоколом TCP/IP.
Флеш отмечает ваш TCP-пакет как срочный (флаг URG), так что он отправляется независимо от состояния окна buffer/TCP. Теперь вы должны сообщить своей операционной системе или любому сетевому оборудованию на линии либо
- игнорировать (или просто reset) флаг срочности, когда предыдущий пакет был отправлен за последние 150 мс, и при необходимости выполните некоторую буферизацию
- задерживает доставку последовательных срочных пакетов для соблюдения ограничения 150 мс.
Возможно, для этого существует дорогостоящее программное обеспечение для Windows. Лично я считаю, что ящик Linux как маршрутизатор между вашими рабочими станциями Windows и модемом с соответствующими настройками QoS в iptables и qdisc сделает трюк.