TCP异常关闭研究分析

版权声明:本文由谢代斌原创文章,转载请注明出处: 
文章原文连接:https://www.qcloud.com/community/article/108服务器

来源:腾云阁 https://www.qcloud.com/community网络

研究测试TCP断开和异常的各类状况,以便于分析网络应用(好比tconnd)断网的缘由和场景,帮组分析和定位链接异常掉线的问题,并提供给TCP相关的开发测试人员做为参考。测试

各个游戏接入都存在必定的掉线问题,并且有的游戏项目的掉线比例还比较高,如今互娱自研游戏的网络接入基本上都用的是tconnd和ProtocalHandler组件(该组件请参考附件的《TSF4G_ProtocalHandler开发指导手册》),所以参与其掉线缘由分析和研究。spa

在参与A项目的掉线问题研究分析过程当中,tconnd增长了玩家每一个链接的流水日志和ProtocalHandler增长了每一个链接的Qos上报日志,经过这些日志记录了每一次链接的断开缘由和相关统计数据,其中包括了链接异常断开时TCP的底层错误码。操作系统

经过对tconnd的流水日志和ProtocalHandler的Qos日志进行统计分析,发现链接异常断开时TCP的错误码大部分是“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下),单纯从错误码原本来讲,你们都明白是“网络被对端重置了”,但究竟什么状况下会致使这种状况呢?所以就对TCP的各类关闭状况作了进一步的测试研究。日志

一. TCP异常关闭的研究测试

1. 服务器端只Recv消息而不Send消息

1.1 测试方法

服务器程序在接受客户端的TCP链接后Sleep几秒钟,客户端程序在TCP链接后当即发送不少消息给对端后作相应动做(退出或等待),服务器程序Sleep完后开始Recv消息。code

注意:服务器程序测试了Linux和Windows版本,但客户端只测试了Windows版本,若是是Linux客户端则有些Case的结果会不同。游戏

1.2 测试Case

  • 客户端程序正常运行的状况下,拔掉网线,杀掉客户端程序
    目的:模拟客户端死机、系统忽然重启、网线松动或网络不通等状况。
    结论:这种状况下服务器程序没有检测到任何异常,并最后等待“超时”才断开TCP链接。进程

  • 客户端程序发送不少数据包后正常关闭Socket并exit进程(或不退出进程)
    目的:模拟客户端发送完消息后正常退出的状况。
    结论:这种状况下服务器程序可以成功接收完全部消息,并最后收到“对端关闭”(Recv返回零)消息。事件

  • 客户端程序发送不少数据包后不关闭Socket直接exit进程
    目的:模拟客户端程序退出而忘记关闭Socket的状况(好比经过Windows窗口的关闭图标退出进程,而没有捕获相应关闭事件作正常退出处理等)。
    结论:这种状况下服务器程序可以收到部分TCP消息,而后收到“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)错误。

  • 客户端程序发送不少数据包的过程当中直接Kill进程
    目的:模拟客户端程序崩溃或非正常方式结束进程(好比Linux下"kill -9"或Windows的任务管理器杀死进程)的状况。
    结论:这种状况下服务器程序很快收到“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)错误。

2.服务器端Recv消息并Send应答消息

2.1 测试方法

服务器程序在接受客户端的TCP链接后Sleep几秒钟,客户端程序在TCP链接后当即发送不少消息给对端后作相应动做(退出或等待),服务器程序Sleep完后开始Recv和Send消息。

注意:服务器程序测试了Linux和Windows版本,但客户端只测试了Windows版本,若是是Linux客户端则有些Case的结果可能会不同。

2.2 测试结果

  • 客户端程序发送不少数据包后正常关闭Socket并exit进程(或不退出进程)
    目的:模拟客户端正常关闭Socket后,服务器端在检查到TCP对端关闭前向客户端发送消息的状况。
    结论:这种状况下服务器程序接收和发送部分TCP消息后,在Send消息时产生“32: Broken pipe”(Linux下)或“10053: An established connection was aborted by the software in your host machine”(Windows下)错误。

  • 客户端程序发送不少数据包后不关闭Socket直接exit或Kill进程
    目的:模拟客户端程序退出而忘记关闭Socket、或客户端程序崩溃或非正常方式结束进程的状况。
    结论:这种状况下服务器程序在Recv或Send消息时产生“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)错误。

3. 效果和总结

3.1 总结

TCP发现网络异常(特别是Linux下的104错误或Windows下10054错误)的状况不少,好比网络自己的问题、中间路由器问题、网卡驱动器问题等不可抗拒因素,但下面是应用程序自己可能会致使的问题,也是咱们须要进一步研究和解决的状况,特别是程序崩溃致使问题:

  • 当TCP链接的进程在忘记关闭Socket而退出、程序崩溃、或非正常方式结束进程的状况下
    (Windows客户端),会致使TCP链接的对端进程产生“104: Connection reset by peer”(Linux下)或“10054: An existing connection was forcibly closed by the remote host”(Windows下)错误。

  • 当TCP链接的进程机器发生死机、系统忽然重启、网线松动或网络不通等状况下
    -(Windows客户端),链接的对端进程可能检测不到任何异常,并最后等待“超时”才断开TCP链接。

  • 当TCP链接的进程正常关闭Socket时,对端进程在检查到TCP关闭事件以前仍然向TCP发送消息
    (Windows客户端),则在Send消息时会产生“32: Broken pipe”(Linux下)或“10053: An established connection was aborted by the software in your host machine”(Windows下)错误。

3.2 效果

针对A项目的掉线问题,经过问卷调查和联系个别玩家等方法,发现掉线的状况很大部分是客户端程序直接退出了,所以推进项目组实现了客户端的Qos上报功能,最后经过客户端的Qos上报的统计数据得出客户端程序的崩溃比例比较高,占了总掉线的很大比率,固然其它状况也存在,但比例相对比较小。

所以,A项目首先应该解决客户端程序的崩溃问题,若是该问题解决了,也就解决大部分掉线问题。

二. TCP异常关闭的进一步研究测试

1. 背景

B项目游戏在跨服跳转时的掉线比例比较高,通过分析ProtocalHandler和tconnd的日志,发现掉线出现的状况是:tconnd发送了跨服跳转消息后当即关闭了Socket,客户端进程在接收到跨服跳转消息以前发送消息后收到Windows 10054错误,而后作断线重连失败。

B项目实现跨服跳转的流程是GameSvr给客户端程序下发的跨服跳转命令的同时携带了Stop请求,也就是说tconnd在向客户端转发跨服跳转消息后当即就会关闭当前的Socket链接,并且B项目的客户端程序会按期不断地向服务器上报消息。这又怎么会致使客户端程序收到10054错误而呢?鉴于此,对TCP的链接作进一步的场景测试分析。

2. TCP异常进一步测试研究

2.1 测试方法

客户端和服务器端程序创建TCP链接,服务器程序在TCP缓冲区中有消息或没有消息的状况下关闭Socket,客户端在对端Socket已经关闭的状况下继续Send和Recv消息。

注意:服务器端只测试了Linux版本,但客户端测试了Windows和Linux两个版本。

2.2 测试结果

  • 服务器端已经close了Socket,客户端再发送数据
    目的:测试在TCP对端进程已经关闭Socket时,本端进程还未检测到链接关闭的状况下继续向对端发送消息。
    结论:第一包能够发送成功,但第二包发送失败,错误码为“10053: An established connection was aborted by the software in your host machine”(Windows下)或“32: Broken pipe,同时收到SIGPIPE信号”(Linux下)错误。

  • 服务器端发送数据到TCP后close了Socket,客户端再发送一包数据,而后接收消息
    目的:测试在TCP对端进程发送数据后关闭Socket,本端进程还未检测到链接关闭的状况下发送一包消息,接着接收消息。
    结论:客户端可以成功发送第一包数据(这会致使服务器端发送一个RST包 <已抓包验证>),客户端再去Recv时,对于Windows和Linux程序有以下不一样的表现:
    Windows客户端程序:Recv失败,错误码为“10053: An established connection was aborted by the software in your host machine”。
    Linux客户端程序:能正常接收完全部消息包,最后收到正常的对端关闭消息(这一点与Window下不同,RST包没有被提早接收到)。

  • 服务器端在TCP的接收缓冲区中还有未接收数据的状况下close了Socket,客户端再收包
    目的:测试在TCP的接收缓冲区中还有未接收数据的状况下关闭Socket时,对端进程是否正常。
    结论:这种状况服务器端就会向对端发送RST包,而不是正常的FIN包(已经抓包证实),这就会致使客户端提早(RST包比正常数据包先被收到)收到“10054: An existing connection was forcibly closed by the remote host”(Windows下)或“104: Connection reset by peer”(Linux下)错误。

3 效果和总结

3.1 总结

TCP应用程序某些看是正常的行为下也可能会致使对端接收到异常,好比当TCP接收缓冲区中还有未收数据的状况下关闭Socket,则会致使对端接收到异常关闭而不是正常关闭;反过来讲,当TCP检测到异常关闭时并不必定表示业务上出问题了,由于极可能就是业务正常结束了。下面是本次测试的主要结论:

  • 当TCP链接的对端进程已经关闭了Socket的状况下,本端进程再发送数据时,第一包能够发送成功(但会致使对端发送一个RST包过来):以后若是再继续发送数据会失败,错误码为“10053: An established connection was aborted by the software in your host machine”(Windows下)或“32: Broken pipe,同时收到SIGPIPE信号”(Linux下)错误;以后若是接收数据,则Windows下会报10053的错误,而Linux下则收到正常关闭消息。

  • TCP链接的本端接收缓冲区中还有未接收数据的状况下close了Socket,则本端TCP会向对端发送RST包,而不是正常的FIN包,这就会致使对端进程提早(RST包比正常数据包先被收到)收到“10054: An existing connection was forcibly closed by the remote host”(Windows下)或“104: Connection reset by peer”(Linux下)错误。

3.2 效果

B项目跨服跳转的掉线问题有至关一部分的种状况是tconnd向客户端转发跨服跳转消息后当即关闭Socket链接,而此时恰好客户端向tconnd发送了数据包:

  • 第一种状况:tconnd在关闭Socket的时刻其TCP的接收缓冲区中有未收的消息,这就使得tconnd进程的TCP向客户端发送的是RST包而不是正常结束的FIN包,因此客户端程序就会提早收到RST包(RST包会比正常数据提早收到),而不会先收完跨服跳转消息后再接收到正常结束消息,这就致使客户端收到网络异常断线而作重连,但以前的链接是tconnd主动关闭的,因此不可能重连成功,从而致使掉线。

  • 第二种状况:tconnd已经关闭了Socket后,客户端在接收到跳转消息和检测到TCP关闭以前向tconnd发送了消息,这就会致使客户端程序收到异常断线而作重连并失败。

最后,与B项目项目组一块儿讨论,改进了大部分跨服跳转的业务流程后,掉线比例j减小了不少,固然仍是存在必定比例的掉线,但这应该就是其它一些缘由了(网络异常问题缘由不少,国内当前的网络环境下,掉线问题是不可能彻底避免的)。

三.结束语

一般状况下,向TCP的Socket发送完数据后关闭Socket,你们认为这样很正常的方式确定没有问题,对端应该正确收完数据后收到TCP的关闭消息,但实际上在某些状况下并不是如此:当TCP本端的接收缓冲区中有未收的数据时关闭Socket,这会致使对端收到RST的异常关闭消息;当对端在本端已经关闭Socket的状况下再次发送消息时,也会致使对端收到异常关闭消息;还有为了不TIME_WAIT而设置了SO_LINGER选项的话,也会致使链接提早夭折使对端收到RST异常关闭消息。

有些时候业务流程对是否引发掉线也很重要(特别是链接关闭流程),好比前面的B项目的跨服跳转掉线问题很大部分就是由于GameSvr请求关闭链接致使的。建议各个游戏项目的关闭流程(包括跨服跳转的原链接的关闭)最好都由客户端发起关闭,这样就必定程度上避免上述问题的发生(由于客服端发起关闭的时候,通常业务流程都走完了,服务器端也不会再向客户端发送消息了)。

程序收到网络异常的状况不少(最多的就是Linux下的104错误和Windos下的10054/10053错误):有网络自己的问题、也有应用使用不当的问题;有运营商之间的跨网络问题、网络中间路由器问题、玩家机器硬件(好比网卡及其驱动)问题和操做系统、杀毒软件、防火墙等软件问题,还有玩家的上网设备和路由器等中间设备问题等,但客户端程序崩溃问题有可能会占掉线的很高比例,这也是值得咱们注意和改进的地方。还有种状况值得咱们注意,有些TP-LINK的路由器,当UDP包大小超过其MTU值时会致使用户机器的网络断开,从而引发掉线(这个问题在某些项目的个别玩家中已经出现过)。

网络异常关闭引发掉线是当前游戏中广泛存在的问题,区别只在于掉线的比例多少,特别是国内各运营商之间跨网络访问更是不太顺畅,要将其彻底消除是不可能的,但咱们的目标是将其控制在较小的可接受范围内。

相关文章
相关标签/搜索