zhmg23

我们是如此的不同
资深运维工程师互荐群: 102123162

通过wireshark分析Sockets连接错误问题

问题:客户端连接我的服务端接口,客户端日志经常会报错,显示socket连接问题,日志如下

操作异常-System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: 

通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 x.x.x.105:80\r\n   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)\r\n   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout, Exception& exception)\r\n   --- End of inner exception stack trace ---\r\n   at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)\r\n   at System.Net.HttpWebRequest.GetRequestStream()\r\n   at KuYin.Base.Core.HttpRequestClient.SendPostRequest(String url, Byte[] postdata, String& responeContent, String& operResult)


分析:遇到这种问题,首先想到的是服务端的ulimit优化,但是优化过之后,这种现象仍然存在,那么下面就开始抓包分析

因为我们服务端是linux,客户端是windows,所以用tcpdump在服务端抓包,然后下载到本地,用wireshark来分析,下面截图,是我在服务端的抓包截图

通过wireshark分析Sockets连接错误问题 - zhm - 合肥运维

 通过上图,可知,包1、包2、包3为客户端55与服务端105的三次握手建立连接情况

包1 2015-10-25 09:13:42.582325 x.x.x.55 x.x.x.105 TCP 62 0 3645→80 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1

包2 2015-10-25 09:13:42.582350 x.x.x.105 x.x.x.55 TCP 62 0 80→3645 [SYN, ACK] Seq=0 Ack=1 Win=14600 Len=0 MSS=1460 SACK_PERM=1

包3 2015-10-25 09:13:42.583300 x.x.x.55 x.x.x.105 TCP 60 0 3645→80 [ACK] Seq=1 Ack=1 Win=65535 Len=0

分析:

第一个包:9点13分42.582325秒  55的3645端口向105的80端口发送SYN握手包,发送序列号Seq标记为0,并且说明,如果你答应,就ACk=seq+1(0+1)

第二个包:9点13分42.582350秒  105的80端口向55的3645端口发送ACK握手回应包,并标记Ack=1(55的Seq+1,因为55的seq为0,所以这里的ack为1),并且把自己的初始序列号Seq告诉了55,说:如果你答应,就Ack=Seq+1

第三个包:9点13分42.583300秒 55通过3645端口告诉105的80端口,说收到了,确认建立连接,Ack=1 

通过wireshark分析Sockets连接错误问题 - zhm - 合肥运维


55与105的三次握手的socket层执行逻辑:

105调用socket的listen函数进入监听状态;55调用connect函数连接105:[SYN],105调用accept函数接受55的连接并发起与55方向上的连接:[SYN,ACK]。55发送[ACK]完成三次握手,connect函数返回;105收到55发送的[ACK]后,accept函数返回。


但是我们发现,在抓取的包中,有很多RST标志,这些标志,就可能是造成socket连接问题的原因

通过wireshark分析Sockets连接错误问题 - zhm - 合肥运维


注:

SYN:携带此标志的包表示正在发起连接请求。因连接是双向的,所以建立连接时,需要双方都发一个SYN

Seq: Sequence Number,为源端(source)的发送序列号

Ack:  Acknowledgment Number,为目的端(destination)的接收确认序列

Fin:  携带此标志的包表示正在请求终止连接。因连接是双向的,所以彻底关闭一个连接时,也要双方都要发一个Fin

RST:  用于重置一个混乱的连接,或者拒绝一个无效的请求


而正常的断开连接,应该像如下截图的第283包至第286包之间这样

通过wireshark分析Sockets连接错误问题 - zhm - 合肥运维

第283帧:10点0分20.085283秒 105发了一个fin的标志给55,说:我们断开吧,seq=735 ack=1323

第284帧:10点0分20.086231秒 55回了105个ack确认断开,ack=736

第285帧:10点0分38.478808秒 55给105回了包,说:我这边的连接也想断开,同时发送了一个fin标志

第286帧:10点0分38.478821秒 105与55达成共识,确认断开,ack=1324  seq=736


结论: 通过抓包,可以判断,是客户端55上的问题,因55是其他人负责,所以建议调整

1、打开注册表(运行命令:regedit)

2、找到注册表节点:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

3、新增2项(如果已存在就修改项值),值对应的都是10进制数字

MaxUserPort=65534 (端口数设到最大)

TcpTimedWaitDelay=5 (超时等待是5秒,根据个人需要)

4、重启服务器


后续问题,在保持观察!


参考链接:

http://blog.csdn.net/phunxm/article/details/5836034 TCP通信流程解析

http://www.cnblogs.com/snake-hand/archive/2013/06/09/3130076.html [解决]通常每个套接字地址只允许使用一次

http://network.51cto.com/art/201408/449186_all.htm TCP连接的状态详解以及故障排查

http://www.cnblogs.com/ylan2009/articles/4326012.html TCP/IP状态变迁图和TCP三次握手与四次挥手

http://hackerxu.com/2014/11/16/TCP.html TCP三次握手和四次挥手


 

评论