现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

socket常见问题(4)

2013-04-03 03:27 工业·编程 ⁄ 共 2643字 ⁄ 字号 暂无评论

1)客户端处在FIN_WAIT_1状态,服务器处在SYN_RECV状态;

这个问题也是我最近在实际中碰到的问题,socket连接和断开流程已经前面的几节中讲到了,大家可以参考前面的内容;

怎么出现这样的问题呢?原因是客户端连接服务器,但是服务器限制了客户端的接入数,它只listen没有accept动作,造成客户端每次connect是成功的,但是连接就是建立不起来,客户端又做了,如果发送数据不成功,马上closesocket,然后在新建socket重连,这样造成了上面的现象,在socket常见问题《四》,我们看到了socket的建立流程,当服务器listen到客户端的连接,就进入SYN_RECV状态,然后listen后,如果给客户端发送了应答,客户端的连接就有可能建立了,但是客户端发送数据不成功后,就closesocket,客户端就进入了FIN_WAIT1状态,此时服务器由于没有accept,所以没有对应的socket,就没有给客户端发送应答,及closesocket信息;这样客户端一直重连,客户端就有很多FIN_WAIT_1,而服务器有很多SYN_RECV;这样可能造成其它客户端也连不上,比如将我这边的客户端关掉;让其它客户端连接,也连不上;

解决方法:

   服务器accept客户端的连接,根据连接数,如果超过连接的个数,就Close这个socket,这样就不会造成这样的问题了。

2) 在线程中碰到socket阻塞怎么办?

比如socket服务器accept阻塞了,造成线程不能顺利退出?

解决办法通过socket的KeepAlive机制;

3) 如何检测socket连接是否断开或异常?

1)通过心跳机制;

  2)KeepAlive机制;

3)Socket 常用的属性

SO_REUSEADDR:

1、 当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。

2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。 
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。 
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。

SO_RECVBUF/SO_SNDBUF

设置socket的接收和发送缓冲;

SO_RCVTIMEO/ SO_SNDTIMEO

设置socket的发送超时和接收超时,在阻塞socket中非常有用,避免一直阻塞;

SO_LINGER:

linger,顾名思义是延迟延缓的意思,这里是延缓面向连接的socket的close操作。默认,close立即返回,但是当发送缓冲区中还有一部分数据的时候,系统将会尝试将数据发送给对端。SO_LINGER可以改变close的行为。避免socket进入TIME_WAIT状态;

SO_KEEPALIVE

SO_KEEPALIVE/TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL
如果一方已经关闭或异常终止连接,而另一方却不知道,我们将这样的TCP连接称为半打开的。TCP通过保活定时器(KeepAlive)来检测半打开连接。
在高并发的网络服务器中,经常会出现漏掉socket的情况,对应的结果有一种情况就是出现大量的CLOSE_WAIT状态的连接。这个时候,可以通过设置KEEPALIVE选项来解决这个问题,当然还有其他的方法可以解决这个问题。

TCP_DEFER_ACCEPT

defer accept,从字面上理解是推迟accept,实际上是当接收到第一个数据之后,才会创建连接。对于像HTTP等非交互式的服务器,这个很有意义,可以用来防御空连接攻击(只是建立连接,但是不发送任何数据)。
使用方法如下:
val = 5;
setsockopt(srv_socket->fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val)); 里面 val 的单位是秒,注意如果打开这个功能,kernel 在val 秒之内还没有收到数据,不会继续唤醒进程,而是直接丢弃连接。如果服务器设置TCP_DEFER_ACCEPT选项后,服务器受到一个CONNECT请求后,三次握手之后,新的socket状态依然为SYN_RECV,而不是ESTABLISHED,操作系统不会Accept。
由于设置TCP_DEFER_ACCEPT选项之后,三次握手后状态没有达到ESTABLISHED,而是SYN_RECV。这个时候,如果客户端一直没有发送"数据"报文,服务器将重传SYN/ACK报文,重传次数受net.ipv4.tcp_synack_retries参数控制,达到重传次数之后,才会再次进行setsockopt中设置的超时值,因此会出现SYN_RECV生存时间比设置值大一些的情况。

TCP_NODELAY/TCP_CHORK:

CP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。TCP_NODELAY和TCP_CORK都禁掉了Nagle算法,只不过他们的行为不同而已。
TCP_NODELAY 不使用Nagle算法,不会将小包进行拼接成大包再进行发送,直接将小包发送出去,会使得小包时候用户体验非常好。
当在传送大量数据的时候,为了提高TCP发送效率,可以设置TCP_CORK,CORK顾名思义,就是"塞子"的意思,它会尽量在每次发送最大的数据量。当设置了TCP_CORK后,会有阻塞200ms,当阻塞时间过后,数据就会自动传送。

4) socket 连接状态

CLOSED:无连接是活动的或正在进行;
LISTEN:服务器在等待进入呼叫;
SYN_RECV:一个连接请求已经到达,等待确认;
SYN_SENT:应用已经开始,打开一个连接;
ESTABLISHED:正常数据传输状态;
FIN_WAIT1:应用说它已经完成;
FIN_WAIT2:另一边已同意释放;
ITMED_WAIT:等待所有分组死掉;
CLOSING:两边同时尝试关闭;
TIME_WAIT:另一边已初始化一个释放;
LAST_ACK:等待所有分组死掉;

给我留言

留言无头像?