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.

Я выполнил шаги, и теперь кажется, что сервер закрывает соединения только тогда, когда клиент теряет соединение с интернетом.