此图为TCP 4次握手图,当引用层调用close()关闭sockfd时,会发送FIN给对方。默认情况下,Close会立即返回,并由TCP模块负责将发送缓冲区中的残留数据发送出去。应用层无法知道缓冲区中的数据是否成功发送完成。
SO_LINGER 选项可以用来控制调用close函数关闭socket后的行为。

Linux Socket SO_LINGER选项

SO_LINGER选项有如下结构:
struct linger {
     int l_onoff; /* 0 = off, nozero = on */
     int l_linger; /* linger time */
};

有下列三种情况:
1、设置 l_onoff为0,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,TCP模块负责尝试发送残留的缓冲区数据。

2、设置 l_onoff为1,l_linger为0,则连接立即终止,TCP将丢弃残留在发送缓冲区中的数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;在远端的recv()调用将以WSAECONNRESET出错。

3、设置 l_onoff 为1,l_linger > 0:

  • 如果socket为阻塞的,则close将阻塞等待l_linger 秒的时间,如果在l_linger秒时间内,TCP模块成功发送完残留的缓冲区数据,则close返回0,表示成功。如果l_linger时间内,TCP模块没有成功发送完残留的缓冲区数据,则close返回-1,表示失败,并将errno设置为EWOULDBLOCK。
  • 如果socket为非阻塞,close立即返回,此时需要根据close返回值以及errno来判断TCP模块是否成功发送残留的缓冲区数据。
//使用举例
struct linger so_linger;
so_linger.l_onoff = TRUE;
so_linger.l_linger = 30;
setsockopt(s,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger));