我有一个非常奇怪的问题让我发疯。
我有一个 Ruby 服务器和一个 Flash 客户端(Action Script 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
true:
newsock = serverSocket.accept
newsock.sync = true
newsock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
这是我的研究:
信息:我每秒都在将 netstat 数据转储到一个文件中。
- 当客户端停止接收数据时,netstat 显示套接字状态仍为
ESTABLISHED
. - 几秒钟后,发送队列会随着发送的数据而增长。
- tcpflow 显示数据包被发送了 2 次。
- 当服务器关闭套接字时,套接字状态按预期更改
FIN_WAIT1
为 。然后,tcpflow 显示所有缓冲的数据都发送到客户端,但客户端没有接收到数据。几秒钟后,netstat 的连接消失,tcpflow 显示再次发送相同的数据,但这次客户端接收到数据,因此开始向服务器发送数据,服务器接收到它。但是为时已晚...服务器已关闭连接。
我不认为这是操作系统/网络问题,因为我已经从位于西班牙的 VPS 更改为位于爱尔兰的 Amazon EC2,但问题仍然存在。
我也不认为是客户端网络问题,因为这种情况每天会发生几十次,平均在线用户数量在45-55左右,每天有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.
我已经按照这些步骤进行操作,现在似乎服务器仅在客户端失去与 Internet 的连接时才关闭连接。
我将添加此作为答案,以便人们对此有所了解。