Какой обходной путь для отложенного подтверждения TCP?

Я отправил онлайн (основанную на сетке) видеоигру, которая использует протокол TCP для обеспечения надежного взаимодействия в топологии сети сервер-клиент. Моя игра работает довольно хорошо, но страдает от большей, чем ожидалось, задержки (аналогичные TCP-игры в жанре, кажется, лучше справляются с сохранением задержки до минимума).

В ходе расследования я обнаружил, что задержка является неожиданно высокой только для клиентов, работающихМайкрософт Виндоус (в отличие отMac OS X клиенты). Кроме того, я обнаружил, что если клиент Windows устанавливаетTcpAckFrequency=1 в реестре и перезапускает их машину, их задержка становится нормальной.

Похоже, что мой дизайн сети не учитывал задержку подтверждения:

Дизайн, который не учитывает взаимодействиеотложенное подтверждение, алгоритм Nagle и буферизация Winsock могут существенно повлиять на производительность. (http://support.microsoft.com/kb/214397)

Тем не менее, я считаю, что почти невозможно принять во внимание задержку подтверждения в моей игре (или любой игре). Согласно MSDN, стек Microsoft TCP использует следующие критерии, чтобы решить, когда отправлять один ACK на полученные пакеты данных:

Если второй пакет данных получен до истечения таймера задержки (200 мс), отправляется ACK.Если есть данные, которые должны быть отправлены в том же направлении, что и ACK, до получения второго пакета данных и истекает таймер задержки, ACK объединяется с сегментом данных и отправляется немедленно.Когда таймер задержки истекает (200 мс), ACK отправляется.

(http://support.microsoft.com/kb/214397)

Читая это, можно предположить, что обходной путь для отложенного подтверждения в стеке TCP Microsoft заключается в следующем:

Отключить алгоритм Nagle (TCP_NODELAY).Отключить буфер отправки сокета (SO_SNDBUF= 0), так что вызовsend можно ожидать отправки пакета.При звонкеsend, если дальнейшие данные не будут отправлены немедленно, позвонитеsend снова с однобайтовыми данными, которые будут отброшены получателем.

При таком подходе второй пакет данных будет получен приемником примерно в то же время, что и предыдущий пакет данных. В результатеACK должен быть отправлен немедленно от получателя к отправителю (эмулируя чтоTcpAckFrequency=1 делает в реестре).

Однако, как показал мой тест, это время ожидания увеличилось лишь наполовину по сравнению с редактированием реестра. Что мне не хватает?

В: Почему бы не использовать UDP?

A: Я выбрал TCP, потому что каждый пакет, который я посылаю, должен прибыть (и быть в порядке); нет пакетов, которые не стоит повторно передавать, если они теряются (или становятся неупорядоченными). Только когда пакеты могут быть отброшены / неупорядочены, UDP может быть быстрее, чем TCP!