tcp 选项:SO_LINGER祥解(转)

来源:互联网 发布:徐州市邳州市知乎 编辑:程序博客网 时间:2024/05/22 12:38

SO_LINGER

   此选项指定函数close对面向连接的协议如何操作(如TCP)。缺省close操作是立即返回,如果有数据残留在套接口缓冲区中则系统将试着将这些数据发送给对方。

 

SO_LINGER选项用来改变此缺省设置。使用如下结构:

struct linger {

     int l_onoff;

     int l_linger;

};

 

有下列三种情况:

l_onoff为0,则该选项关闭,l_linger的值被忽略,等于缺省情况,close立即返回;

l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;

l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完 成。

 

l_linger的单位依赖于实现,4.4BSD假设其单位是时钟滴答(百分之一秒),但Posix规定单位为秒。

 

测试发现:

客户端connect之后,set linger,模拟一个夭折的连接(是不是set linger,并没有导致客户端发送RST?也就是不存在夭折连接?),linux服务器段照样会accept接受下来,再监听该端口,会产生读取EOF的行为。这个和steven描述的其他系统的处理不一致!

如果通过设置SO_LINGER,close时会发出RST,而不是上面的正常结束.网上都说不推荐使用.原因有二: (a)有些系统未实现;(b)TIME_WAIT很重要,因为网络上可能还有数据在传送,而若此sock的替身出现,会收到不该收的包.

apche 实现关闭,不用设置SO_LINGER实现,如下:

是否应该在这先setsockopt(linger)?这个应该先设置?以便后面超时调用close时产生RST?去掉TIME_WAIT状态?

参见lamp.linux.gov.cn/Apache/ApacheMenu/misc/perf-tuning.html

shutdown(s,1);关闭写端,产生FIN的发送,(正常对方会读取到EOF),进入FIN_WAIT2状态

alarm(2);设置2s的超时,等待读取客户端数据,

read数据;读到0字节,表示对方放送FIN,

close;超时,强制关闭,否则,正常关闭。

 

 

以下为另外一篇文章:

setsockopt的调用将依上面结构的两个值产生三种情况的某一种
1。如果l_onoff是0,选项被关闭。l_linger的值被忽略且前面讨论的TCP缺省设置生效,close立即返回。
2。如果l_onoff非0,且l_linger为0,那么当套接口关闭时TCP夭折连接。TCP将丢弃保留的套接口发送缓冲区的任何数据并发送一个 RST给对方,而不是通常的四分组连接终止序列。这避免了TCP的TIME_WAIT状态,但这样做也会有以下可能性。但这样做也会有以下可能性:在 2MSL妙内创建此连接的令一个化身,并使得老的来自刚被终止的连接上的重复分节不正确地传递到新的化身上。
     有些实现,尤其是solaris。不实现SO_LINGER选项的这个特性。TIME_WAIT状态是我们的朋友,它是有助于我们的(也就是说,使旧的重复分节在网络中超时消失)。不要试图避免这个状态。
3,如果l_onoff和l_linger都为非0。那么当套接口关闭时内核将拖延一段时间。也就是说,如果在发送缓冲区中仍有数据。进程将处于睡眠状 态,一直到(a)所有数据都已发送完且均被对方确认或(b)延滞时间到。如果套接口被设置为非阻塞型。它将不等待close完成,即使延滞时间为非0也是 如此。当使用SO_LINGER选项的这个特性时,应用进程检查close的返回值是非常重要的,因为,如果在数据发送完并被确认前延滞时间到的话, close将返回EWOULDBLOCK 错误且套接口发送缓冲区中的任何数据都丢失。
      第三种情况中对成员l_linger非0的解释是依赖不同的实现的。4.4BSD假设其单位是时钟滴答(一百分之一秒),但posix.1g规定其单位为 秒。现有的源自Berkeley的实现的另一个问题是成员l_linger(一个整数)是拷贝到16位的带符号整数内核变量so_linger上的,这就 限制了延滞时间最大为32767时钟滴答即327.67秒。

 

在HTTP应用中,存在一个问题,SERVER由于某种原因关闭连接,如KEEPALIVE的超时,这样,作为主动关闭的SERVER一方就会进入 FIN_WAIT2状态,但TCP/IP协议栈有个问题,FIN_WAIT2状态是没有超时的(不象TIME_WAIT状态),所以如果CLIENT不关 闭,这个FIN_WAIT_2状态将保持到系统重新启动,越来越多的FIN_WAIT_2状态会致使内核crash

chdonald 回复于:2003-07-11 12:30:51

产生原因: 
1。常连接并且当连接一直处于IDLE状态导致SERVER CLOSE时,CLIENT编程缺陷,没有向SERVER 发出FIN和ACK包 
2。APACHE1.1和APACHE1.2增加了linger_close()函数,前面的帖子有介绍,这个函数可能引起了这个问题(为什么我也不清楚) 

解决办法: 
1。对FIN_WAIT_2状态增加超时机制,这个特性在协议里没有体现,但在一些OS中已经实现 
如:LINUX、SOLARIS、FREEBSD、HP-UNIX、IRIX等 
2。不要用linger_close()编译 
3。用SO_LINGER代替,这个在某些系统中还能很好地处理 
4。增加用于存储网络连接状态的内存mbuf,以防止内核crash 
5。DISABLE KEEPALIVE