TCP-сокет перестает получать данные до закрытия
у меня очень странная проблема, которая сводит меня с ума.
у меня есть сервер Ruby и Flash-клиент (сценарий действий 3). Это многопользовательская игра.
проблема в том, что все работает идеально, а затем, внезапно, случайный игрок перестает получать данные. Когда сервер закрывает соединение из-за бездействия, примерно через 20-60 секунд клиент получает все буферизованные данные.
клиент использует XMLsocket
для получения данных, так проблема не в том, как клиент получает данные.
socket.addEventListener(Event.CONNECT, connectHandler);
function connectHandler(event)
{
sendData(sess);
}
function sendData(dat)
{
trace("SEND: " + dat);
addDebugData("SEND: " + dat)
if (socket.connected) {
socket.send(dat);
} else {
addDebugData("SOCKET NOT CONNECTED")
}
}
socket.addEventListener(DataEvent.DATA, dataHandler);
function dataHandler(e:DataEvent) {
var data:String = e.data;
workData(data);
}
сервер сбрасывает данные после каждой записи, поэтому не является проблемой промывки:
sock.write(data + DATAEOF)
sock.flush()
DATAEOF
является нулевым символом, поэтому клиент анализирует строку.
когда сервер принимает новый сокет, он устанавливает sync
к true, к autoflush, и TCP_NODELAY
для так:
newsock = serverSocket.accept
newsock.sync = true
newsock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
это мое исследование:
Info: я сбрасывал данные netstat в файл каждый второй.
- когда клиент перестает получать данные, netstat показывает, что состояние сокета по-прежнему
ESTABLISHED
. - через несколько секунд после этого очередь отправки растет соответственно отправленным данным.
- tcpflow показывает, что пакеты отправляются 2 раза.
- когда сервер закрывает сокет, состояние сокета изменяется на
FIN_WAIT1
, как ожидалось. Затем, tcpflow показывает, что все буферизованные данные отправляются клиенту, но клиент не получает данные. несколько секунд спустя таким образом, соединение исчезает из netstat и tcpflow показывает, что те же данные отправляются снова, но на этот раз клиент получает данные, поэтому начинает отправлять данные на сервер, и сервер получает его. Но уже слишком поздно... сервер закрыл соединение.
Я не думаю, что это проблема ОС/сети, потому что я изменился с VPS, расположенного в Испании, на Amazon EC2, расположенный в Ирландии, и проблема все еще остается.
Я не думаю, что это проблема клиентской сети тоже потому, что это происходит десятки раз в день, а среднее количество онлайн-пользователей составляет около 45-55, при этом около 400 уникальных пользователей в день, поэтому соотношение крайне высокое.
EDIT: Я провел больше исследований. Я изменил сервер на C++.
когда клиент перестает отправлять данные, через некоторое время сервер получает ошибку "сброс соединения одноранговым узлом". В этот момент tcpdump показывает мне, что клиент отправил первый пакет, это может быть потому, что клиент закрыл соединение и сервер попытался прочитать, но... почему клиент закрыл соединение? Я думаю, что ответ заключается в том, что клиент не закрывает соединение, является ядро. Вот некоторая информация: http://scie.nti.st/2008/3/14/amazon-s3-and-connection-reset-by-peer
Basically, as I understand it, Linux kernels 2.6.17+ increased the maximum size of the TCP window/buffer, and this started to cause other gear to wig out, if it couldn’t handle sufficiently large TCP windows. The gear would reset the connection, and we see this as a “Connection reset by peer” message.
я следовал инструкциям и теперь кажется, что сервер закрывает соединения только тогда, когда клиент теряет соединение с интернет.
Я собираюсь добавить это в качестве ответа, чтобы люди знали, немного больше об этом.
1 ответов
Я думаю, что ответ заключается в том, что ядро закрывает соединение. Вот некоторая информация: http://scie.nti.st/2008/3/14/amazon-s3-and-connection-reset-by-peer
Basically, as I understand it, Linux kernels 2.6.17+ increased the maximum size of the TCP window/buffer, and this started to cause other gear to wig out, if it couldn’t handle sufficiently large TCP windows. The gear would reset the connection, and we see this as a “Connection reset by peer” message.
Я выполнил шаги, и теперь кажется, что сервер закрывает соединения только тогда, когда клиент теряет соединение с интернетом.