转自:http://www.blogjava.net/pandawang/archive/2013/11/28/406922.html
WSAGetLastError可能会返回10053错误,查msdn的解释是:
WSAECONNABORTED 10053
神马?软件原因造成的连接中断,这是什么意思,不跟没说一样的么? Berkeley description: A connection abort was caused internal to your host machine. The software caused a connection abort because there is no space on the socket’s queue and the socket cannot receive further connections.
WinSock description: Partly the same as Berkeley. The error can occur when the local network system aborts a connection. This would occur if WinSock aborts an established connection after data retransmission fails (receiver never acknowledges data sent on a datastream socket).
TCP/IP scenario: A connection will timeout if the local system doesn’t receive an (ACK)nowledgement for data sent. It would also timeout if a (FIN)ish TCP packet is not ACK’d (and even if the FIN is ACK’d, it will eventually timeout if a FIN is not returned).
伯克利说这种连接中断是因为宿主机器的内部原因,因为软件导致的连接中断,可能是因为socket的队列满并且这个socket不能接收更多的连接了。 The Scenario: Meanwhile, the client is still happily writing the remainder of the HTTP request to the socket. (Remember a TCP/IP socket connection needs to be closed from both sides. In this case, the server has closed its side, but the client is still pumping data into the half-open connection.) Go back and re-read the original error explanations. Hopefully, after that explanation, you’ll say "Aha! I understand what they’re talking about!".
啊哈,又有http了,大概意思就是http server收到请求了,但发现有问题,那么回一个http错误码,然后就关闭了socket,但与此同时,client端还在很开心地向socket写数据,注意哦,tcp是全双工的。client写完毕后,实际上数据只是放到了发送方的缓冲区中,不一定已经发出去了,如果写得不好的程序,这个时候就开始从socket读数据了,这时候就会产生一个WSACONNECTABORTED错误,windows上对应的就是10053错误。 但这个解释实际上是不能让人满意的,只是举出了一种场景,但为什么会产生还没有解释。后面又搜到了个参考2,首先解释10053错误是收到fin后client会放弃发送缓冲区中的数据,同时上报错误。虽然说法还有点一头雾水。 不过这两个参考给我们一个思路,重现这个问题。 于是简单写个测试用的c-s程序,大概流程如下 |
这个简单程序演示如何出现10053错误(以及10054错误)。
如果server在收到client发送的数据后立即关闭socket,那么client再读时,会收到10053错误;如果server收到发送数据后,立即crash,那么随后client再读取时会收到10054错误。
ok,能够重现场景了,那么我们来分析一下更细节的方面,网络问题自然是抓包,本问题处理抓包还要看一下tcp的状态以便辅助分析,我们在client端每次操作之前都打印当前的tcp状态。
下面是client端发送记录和对应的netstat情况
client在发送之前tcp状态是established,在发送之后,server会立即关闭,tcp状态也变为close_wait,但这只是单方向的关闭,client可以继续发数据,但client发送后,server立即退出了,导致后续recv会失败并且返回10053。对应抓包情况如下:
整个通信过程如下:
1-3.三次握手建立连接
4.客户端(10.10.86.93)向服务器端(10.10.86.98)发送数据,1字节
5.server 中止 发送fin(同时ack之前那个push)
6.client ack 那个fin
7.client再发送两个字节
8.server此时已经关闭socket,属于非正常情况,回复复位命令
整个过程可以重现10053情况,tcp发送分组数据的情况也一目了然,事情到此就可以了么?显然不是,你也看到了后面还有很多文字,不知此时你心中的问题是否跟我一样,先说我自己的吧,通过抓包发现这里的异常关闭有个reset,但reset一般是10054(Connection reset by peer)的错误,那么10053与10054的区别在哪里。要搞清楚问题也不难,重现场景抓包分析。
以下是修改上面的cs程序,在client发送的1字节包后,立即crash,这导致的问题是操作系统会立即回收所有资源,包括socket资源
可以看到在crash之前这个tcp都是established状态。crash之后,client端接收数据时会收到10054错误,场景重现了,我们再看一下抓包情况
这个抓包情况跟10053很像,1-7也同10053,在8时,client收到server发过来的reset,表示当前连接被强制复位了。
对比10053和10054可以发现,如果srv返回fin标志后再reset那么对应的错误就是10053,如果直接reset就是10054错误。回过头来在看参考2中的说法也就有点感觉了。
总结一下:
1.遇到不了解的问题,google是非常好的方法
2.对于一般问题,重现之很重要,可以反复发现问题并验证问题。自己写程序或者搭环境尽量重现。
3.网络问题抓包是利器,包括各种工具的使用netstat wireshark ping traceroute等。
4.多重问题对比其中的差异,这里对比10053错误和10054错误。
5.理论基础要搭好,本次问题主要是tcp的异常断开问题,熟悉tcp断开的半关闭和复位逻辑,不过理论还是理论,同样是复位在不同场景下的错误码不同。并且实现上也跟具体的操作系统相关。
6.实际工作中,10053错误时,用户主要是处于透明代理情况,那么这一般是又有用户所在的代理服务器异常关闭导致的,可能跟我们的离线文件私有协议被用户所在的代理服务器拒绝掉导致的。
7.回过头来在看一开始的解释,所谓软件原因造成的连接终端,就是本例子中,server端在shoutdown本方向传输时,立即关闭了socket,导致本应该等待对方发送fin来完全结束的正常逻辑被打破,编程单方向强制中止本次tcp,导致client端之后向上报错,就是所谓的10053错误了,这里的软件就是server端的那个程序。(不过也有种说法是,客户端发送错误数据,导致server端保护机制而强制关闭)