很久很久以前

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  34 随笔 :: 4 文章 :: 17 评论 :: 0 Trackbacks

2013年11月13日 #

Winsock 10053错误分析

 WSAGetLastError可能会返回10053错误,查msdn的解释是:

WSAECONNABORTED 10053

Software caused connection abort.

An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error.

神马?软件原因造成的连接中断,这是什么意思,不跟没说一样的么?
google一下呗

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不能接收更多的连接了。
这还不如不说,越说越糊涂了。
winsocket的描述,似乎还靠谱一些,这种错误一般发生在一个建立的连接被重发失败的情况下产生,接收方没有响应数据发回来。但还是比较模糊。
再看看tcp ip标准文档的说法,如果本地系统没有收到发送数据的响应(ack)那么这连接就会超时。如果tcp的fin包没有被ack(或者fin包被ack了但fin没有返回)那么也会超时。但是,但是,超时跟这个10053有神马关系?
再看后续的解释:
从参考1中找到如下的描述:

The Scenario: 
An HTTP POST is to be sent to an HTTP server.
The server begins reading the POST and notices that the HTTP request header is invalid.
It immediately sends an HTTP response (with an error status, perhaps status=400) and closes the connection without trying to continue reading the remainder of the HTTP request that is forthcoming.

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.)
The client finishes writing the HTTP POST to the socket — meaning that data has been buffered to Winsock. The client application then tries to read the HTTP response, but it cannot because the outgoing retransmission (of the buffered data by WinSock) failed and the socket connection was shutdown on the client side (by Winsock). Even though the HTTP server sent the response, it is lost and cannot be retrieved. The error your application will receive when
trying to read the HTTP response on the socket is WSAECONNABORTED. The word "software" in any of the above error messages refers to "WinSock".

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程序,大概流程如下

 

 

图1 CS程序简化流程图

这个简单程序演示如何出现10053错误(以及10054错误)。

如果server在收到client发送的数据后立即关闭socket,那么client再读时,会收到10053错误;如果server收到发送数据后,立即crash,那么随后client再读取时会收到10054错误。

ok,能够重现场景了,那么我们来分析一下更细节的方面,网络问题自然是抓包,本问题处理抓包还要看一下tcp的状态以便辅助分析,我们在client端每次操作之前都打印当前的tcp状态。

下面是client端发送记录和对应的netstat情况

图2 10053错误client端tcp状态流转

client在发送之前tcp状态是established,在发送之后,server会立即关闭,tcp状态也变为close_wait,但这只是单方向的关闭,client可以继续发数据,但client发送后,server立即退出了,导致后续recv会失败并且返回10053。对应抓包情况如下:



图3 10053错误client端tcp抓包

整个通信过程如下:
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资源。




图4 10054错误client端tcp状态流转

可以看到在crash之前这个tcp都是established状态。crash之后,client端接收数据时会收到10054错误,场景重现了,我们再看一下抓包情况



图5 10054错误client端tcp抓包

这个抓包情况跟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端保护机制而强制关闭)


参考:

  1. http://www.chilkatsoft.com/p/p_299.asp   
  2. http://bbs.csdn.net/topics/360024280#post-361829232
  3. 《TCP/IP详解(卷一)》18章 TCP连接的建立和中止

 

 

posted @ 2013-11-28 11:22 Long Long Ago 阅读(29094) | 评论 (1)编辑 收藏

最近改造文件传输,参考libcurl,考虑到他支持那么多协议,但我只关心http的,所以考虑是否可以只生成http支持的版本,查了一下,果然可以。
下载,如果不需要最新的,那么只要下载个zip包就好了。
通过download wizard可以指引你下载不同的版本:http://curl.haxx.se/dlwiz/
选择
source code - 平台无关- 找到最新版本下载,解压缩
编译比较简单有build指令
不过我从vs目录下找到一个2005版本的vcproj文件,用这个也可以编译,不过要设置一下include目录为../../../include
 上面是废话了,关键的怎么值生成对http的支持呢
只要在编译指令中增加定义HTTP_ONLY宏就可以了,就这么简单。
详细说明在这里http://curl.haxx.se/docs/install.html
posted @ 2013-11-21 20:40 Long Long Ago 阅读(682) | 评论 (0)编辑 收藏

路由器软件部分的几个概念:CFE、固件(Firmware)、NVRAM
CFE的作用跟PC的BIOS一样是负责引导操作系统的;固件就是路由器的操作系统,就像PC上的Windows一样;NVRAM则用于存储路由器的设置,相当于PC的CMOS。
当路由器插上电后自动进入CFE,CFE进行类似PC的BIOS那样进行自检,自检通过后就引导路由器的固件了(相当于的PC的Windows了),正常情况下最多一分钟路由器的固件就会引导完毕,并且Power灯是常亮的。如果Power灯一闪一闪,那一般是CFE没有引导成功路由器的固件(固件不存在、不正确、已损坏等等)。
那么我们平常刷固件会把CFE也刷了吗?呵呵,不会的,就像你平时装Windows一样,不管你是装XP也好,Vista也好,Win7也好,都不会对你的BIOS进行更新。那我想刷CFE该用什么方法?一般用户用路由器原厂的CFE即可,如果要玩的深入一些想刷CFE,那么可以通过JTAG或者telnet方式来刷(比较危险,而且受固件限制,有些固件不支持)。
主要是对硬件环境进行初始化,image的更新,加载kernel等
posted @ 2013-11-13 20:34 Long Long Ago 阅读(238) | 评论 (0)编辑 收藏