私は本当に奇妙な問題を抱えており、それが私を夢中にさせています。
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
null charであるため、クライアントは文字列を解析します。
サーバーが新しいソケットを受け入れると、sync
true、autoflush、およびtrueに設定されますTCP_NODELAY
。
newsock = serverSocket.accept
newsock.sync = true
newsock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
これは私の研究です:
情報:netstatデータを毎秒ファイルにダンプしていました。
- クライアントがデータの受信を停止すると、netstatはソケットステータスがまだであることを示します
ESTABLISHED
。 - その数秒後、送信されたデータに応じてsend-queueが大きくなります。
- tcpflowは、パケットが2回送信されることを示しています。
- サーバーがソケットを閉じると、期待どおりにソケットのステータスがに変わります
FIN_WAIT1
。次に、tcpflowは、バッファリングされたすべてのデータがクライアントに送信されているが、クライアントはデータを受信していないことを示します。その数秒後、netstatから接続が失われ、tcpflowは同じデータが再度送信されたことを示しますが、今回はクライアントがデータを受信するため、サーバーへのデータの送信を開始し、サーバーがデータを受信します。しかし、手遅れです...サーバーが接続を閉じました。
スペインにあるVPSからアイルランドにあるAmazonEC2に変更したのですが、まだ問題が残っているため、OS/ネットワークの問題ではないと思います。
クライアントネットワークの問題でもないと思います。これは1日に数十回発生し、オンラインユーザーの平均数は約45〜55人で、1日あたりのユニークユーザー数は約400人であるため、この比率は非常に高くなっています。
編集: 私はより多くの研究をしました。サーバーをC++に変更しました。
クライアントがデータの送信を停止すると、しばらくするとサーバーは「ピアによる接続リセット」エラーを受け取ります。その瞬間、tcpdumpは、クライアントがRSTパケットを送信したことを示します。これは、クライアントが接続を閉じ、サーバーが読み取りを試みたことが原因である可能性がありますが、クライアントが接続を閉じたのはなぜですか。答えは、クライアントは接続を閉じるものではなく、カーネルであるということだと思います。ここにいくつかの情報があります: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.
手順を実行しましたが、クライアントがインターネットへの接続を失った場合にのみ、サーバーが接続を閉じているようです。
これを答えとして追加して、人々がこれについて少しおかしなことを知っているようにします。