http://www.360doc.com/content/14/0214/15/9490170_352463397.shtml
SO_LINGER 选项用来指明关闭基于连接的 socket 时的行为。默认,close 函数会立即返回,但当 socket 发送缓冲区残留数据时,close 函数向缓冲区中写入 FIN 后,同样会立即返回,但 TCP 将会尽力发送完这些数据。

如果要改变 close 函数的默认行为,就需要 SO_LINGER 选项。相关的数据结构如下:
struct linger { int l_onoff; /* 0=off, nonzero=on */ int l_linger; /* linger time, POSIX specifies units as seconds */ };
1. l_on
2. l_on
3. l_on
1) 缓冲区中的数据以及 FIN 发送出去,并得到对等端的确认。(图 7.8)
2)l_linger 设置的时间超时。(图 7.9)
而 后,close 返回。(当然非阻塞模式下,close并不等待数据发送完成或者超时,而是立即返回)


这种情况下需要注意的是,要检查 close 函数的返回值,在数据以及FIN得到确认之前如果超时的话,close 返回 EWOULDBLOCK ,并清空缓冲区。另外 TCP 向对等端发送一个 RST 。
当然·,close 成功返回只是告诉我们对等端 TCP 成功接收到数据,并不能告诉我们对等端 应用进程 是否成功接收到数据。 (如果不设置 SO_LINGER 选项, 我们无法知道发出的数据是否被对等端确认)
接着上面的话题,如果想知道对等端 应用进程 是否接收到数据,可以调用 shutdown 函数(参数为 SHUT_WR),代替 close 。然后调用 read 函数。 正常情况下,read 应该读到 对等端发过来的 FIN,并返回 0 。

另外一种确认对等端 应用进程 接受到数据的方法是 “应用程序级别的确认”, 如下,客户进程发送数据之后,并读取 1 个字节的确认数据。
char ack; Write(sockfd, data, nbytes); /* da ta from client to server */ n = Read(sockfd, &ack, 1); /* wait for application-level ACK */
服 务进程读到客户端发来的数据后,写回一个 “应用程序级别的确认” 。
nbytes = Read(sockfd, buff, sizeof(buff)); /* data from client */ /* server verifies it received correct amount of da ta from client */ Write(sockfd, "", 1); /* server's ACK back to client */
这 样,我们就可以保证,当客户端 read 返回时,服务进程已经读到了客户端发送的数据。(这里假定服务进程知道客户端一次发送多少数据)
shutdown 函数、close 函数、以及 SO_LINGER 总结
