SO_LINGER选项用来设置延迟关闭的时间,等待套接字发送缓冲区中的数据发送完成。

没有设置该选项时,在调用close()后,在发送完FIN后会立即进行一些清理工作并返回。如果设置了SO_LINGER选项,并且等待时间为正值,则在清理之前会等待一段时间。

以调用close()主动关闭为例,在发送完FIN包后,会进入FIN_WAIT_1状态。如果没有延迟关闭(即设置SO_LINGER选项),在调用tcp_send_fin()发送FIN后会立即调用sock_orphan()将sock结构从进程上下文中分离。分离后,用户层进程不会再接收到套接字的读写事件,也不知道套接字发送缓冲区中的数据是否被对端接收。如果设置了SO_LINGER选项,并且等待时间为大于0的值,会等待套接字的状态从FIN_WAIT_1迁移到FIN_WAIT_2状态。我们知道套接字进入FIN_WAIT_2状态是在发送的FIN包被确认后,而FIN包肯定是在发送缓冲区中的最后一个字节,所以FIN包的确认就表明发送缓冲区中的数据已经全部被接收。当然,如果等待超过SO_LINGER选项设置的时间后,还是没有收到FIN的确认,则继续进行正常的清理工作,Linux下也没有返回错误。从这里看来,SO_LINGER选项的作用是等待发送缓冲区中的数据发送完成,但是并不保证发送缓冲区中的数据一定被对端接收(对端宕机或线路问题),只是说会等待一段时间让这个过程完成。如果在等待的这段时间里接收到了带数据的包,还是会给对端发送RST包,并且会reset掉套接字,因为此时已经关闭了接收通道。
在使用这个选项来延迟关闭连接的时候有两个地方需要注意:
1. 进程会睡眠,直到状态不为FIN_WAIT_1、CLOSING、LAST_ACK(也就是接收到对FIN的ACK包),或者等待超时
2. 在等待的过程中如果接收到带数据的包还是会发送RST包
3.消耗更多的额外资源
  TCP协议是一个通用的传输层协议,不关心上层具体的业务,如果要延迟关闭连接,最好是结合自己的业务和场景自己来管理,不要依赖这个选项。nginx的延迟关闭就是自己来管理的,觉得要比直接使用SO_LINGER选项好一些,并且不会导致进程阻塞。 ngxin在发送错误信息后,会等待一段时间,让用户把所有的数据都发送完。超过等待时间后,会直接关闭连接。通过lingering_close,nginx可以保持更好的客户端兼容性,避免客户端被reset掉。
  SO_LINGER还有一个作用就是用来减少TIME_WAIT套接字的数量。在设置SO_LINGER选项时,指定等待时间为0,此时调用主动关闭时不会发送FIN来结束连接,而是直接将连接设置为CLOSE状态,清除套接字中的发送和接收缓冲区,直接对对端发送RST包。

setsockopt 设置 SO_LINGER 选项

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

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

struct linger {

int l_onoff; /* 0 = off, nozero = on */

int l_linger; /* linger time */

};

有下列三种情况:

1、设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;

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

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

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

下面的代码是一个使用SO_LINGER选项的例子,使用30秒的超时时限:

#define TRUE     1

#define FALSE    0
int z; //Status code int s; //Socket s
struct linger so_linger;
...
so_linger.l_onoff = TRUE;
so_linger.l_linger = 30;
z = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
if ( z )
perror("setsockopt(2)");

下面的例子显示了如何设置SO_LINGER的值来中止套接口s上的当前连接:

#define TRUE     1
#define FALSE 0
int z; /* Status code */
int s; /* Socket s */
struct linger so_linger;
...
so_linger.l_onoff = TRUE;
so_linger.l_linger = 0;
z = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
if ( z )
perror("setsockopt(2)");
close(s); /* Abort connection */

在上面的这个例子中,当调用close函数时,套接口s会立即中止。中止的语义是通过将超时值设置为0来实现的。

/********** WINDOWS **********/

/* 当连接中断时,需要延迟关闭(linger)以保证所有数据都被传输,所以需要打开SO_LINGER这个选项;  
 * //注:大致意思就是说SO_LINGER选项用来设置当调用closesocket时是否马上关闭socket; 
 * linger的结构在/usr/include/Linux/socket.h中定义://注:这个结构就是SetSocketOpt中的Data的数据结构 
 *  struct linger 
 *  { 
 *   int l_onoff;  /* Linger active */       //低字节,0和非0,用来表示是否延时关闭socket
 *   int l_linger; /* How long to linger */   //高字节,延时的时间数,单位为秒
 *  }; 
 *  如果l_onoff为0,则延迟关闭特性就被取消。

*   如果非零,则允许套接口延迟关闭; l_linger字段则指明延迟关闭的时间 
 */

更具体的描述如下:
1、若设置了SO_LINGER(亦即linger结构中的l_onoff域设为非零),并设置了零超时间隔,则closesocket()不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式称为“强制”或“失效”关闭,因为套接口的虚电路立即被复位,且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。

2、若设置了SO_LINGER并确定了非零的超时间隔,则closesocket()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅”或“从容”关闭。请注意如果套接口置为非阻塞且SO_LINGER设为非零超时,则closesocket()调用将以WSAEWOULDBLOCK错误返回。

3、若在一个流类套接口上设置了SO_DONTLINGER(也就是说将linger结构的l_onoff域设为零),则closesocket()调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。请注意,在这种情况下WINDOWS套接口实现将在一段不确定的时间内保留套接口以及其他资源,这对于想用所以套接口的应用程序来说有一定影响。

SO_DONTLINGER 若为真,则SO_LINGER选项被禁止。
SO_LINGER延迟关闭连接 struct linger上面这两个选项影响close行为;

选项                            间隔    关闭方式  等待关闭与否
  SO_DONTLINGER   不关心     优雅          否
  SO_LINGER             零            强制          否
  SO_LINGER            非零         优雅          是

http://blog.csdn.net/fullsail/article/details/4424324

setsockopt 设置TCP的选项SO_LINGER的更多相关文章

  1. setsockopt 设置 SO_LINGER 选项

    setsockopt 设置 SO_LINGER 选项 最近和后台的server通信 server发现在读数据的时候  客户端已经关闭连接 ,也就是 没有等服务器读完数据,客户端已经fclose了, 联 ...

  2. setsockopt设置socket状态

    setsockopt设置socket状态 1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsoc ...

  3. setsockopt 设置socket 详细用法

    1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsockopt(s,SOL_SOCKET ,SO ...

  4. UDP10040 和 setsockopt设置大全

    今天无意之中碰到 UDP 10040 错误  原来是缓冲区不够,以下转载的解决方法以供不时之需.   1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该sock ...

  5. setsockopt 设置socket 详细用法(转载)

    转自:http://www.cppblog.com/killsound/archive/2009/01/16/72138.html 1.closesocket(一般不会立即关闭而经历TIME_WAIT ...

  6. setsockopt 设置socket

    1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsockopt(s,SOL_SOCKET ,SO ...

  7. tcp keepalive选项

    之前一直对tcp keepalive选项理解有误, 以为通过setsockopt函数设置SO_KEEPALIVE和相关参数后该socket则使用设置的keepalive相关参数 否则使用系统默认的:k ...

  8. Socket: Java Socket 几个重要的TCP/IP选项解析(转)

    Socket选择可以指定Socket类发送和接受数据的方式.在JDK1.4中共有8个Socket选择可以设置.这8个选项都定义在java.net.SocketOptions接口中.定义如下: publ ...

  9. curl_setopt — 设置 cURL 传输选项

    curl_setopt (PHP 4 >= 4.0.2, PHP 5, PHP 7) curl_setopt — 设置 cURL 传输选项 bool curl_setopt ( resource ...

随机推荐

  1. Oracle PLSql配置

    1.安装Oracle客户端或者服务端 2.配置环境变量 <1>.一般如果安装了Oracle客户端或者服务端的话,在环境变种的Path中有Oracle的安装路径(计算机-属性-高级系统设置- ...

  2. mysql+mycat压力测试一例【转】

    前言 有很多人担心生产系统上新东西的程序怕压力跟不上和稳定性不行,是的,大家都怕,所以领导要求做一次压力测试,我个人也觉得是有必要的. 如果按原理来说,mycat如果不做分片,纯粹只是代理的话,他所做 ...

  3. [转]使用 mitmproxy + python 做拦截代理

    使用 mitmproxy + python 做拦截代理   本文是一个较为完整的 mitmproxy 教程,侧重于介绍如何开发拦截脚本,帮助读者能够快速得到一个自定义的代理工具. 本文假设读者有基本的 ...

  4. C# UDP广播消息

    首先是发送端: /// <summary> /// 发送UDP消息 /// </summary> /// <param name="msg">消 ...

  5. Android网络框架之Retrofit + RxJava + OkHttp 变化的时代

    1.什么是Retrofit框架? 它是Square公司开发的现在非常流行的网络框架,所以我们在导入它的包的时候都可以看到这个公司的名字,目前的版本是2. 特点: 性能好,处理快,使用简单,Retrof ...

  6. DOM事件阶段以及事件捕获与事件冒泡先后执行顺序

    平时浏览这么多技术文章,如过不去实践.深入弄透它,这个技术点很快就会在脑海里模糊.要加深印象,就得好好过一遍.重要的事情说三遍,重要的知识写一遍. 开发过程中我们都希望使用别人成熟的框架,因为站在巨人 ...

  7. JAVA 反射用法

    1.获得Class对象 Class<?>  classType  =  Class.forName() 可以通过传入一个全限定类名(包含包名)返回一个该类的Class类对象引用 . Cla ...

  8. springMVC源码分析--视图View(一)

    之前的博客springMVC源码分析--HttpMessageConverter数据转化(一)中我们已经介绍了数据返回值的处理,在博客springMVC源码分析--ViewResolver视图解析器( ...

  9. How to return plain text from AWS Lambda & API Gateway

    With limited experience in AWS Lambda & API Gateway, it's struggling to find the correct way to ...

  10. Selenium Webdriver概述(转)

    Selenium Webdriver https://www.yiibai.com/selenium/selenium_overview.html# webdriver自动化俗称Selenium 2. ...