金周荣失误:【转】SO_LINGER 选项 与 shutdown 函数

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 02:33:57

UNPv1笔记10 -- SO_LINGER 选项 与shutdown 函数

tcpipsocket2009-06-22 17:50:44阅读118评论0  字号:大中小 订阅


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_onoff 字段设为 0 时, 选项被关闭,close 时为默认行为。

2. l_onoff非 0 , 而 l_linger 设为 0 时,close 清空发送缓冲区的数据,并向缓冲区中写入 RST ,然后返回。 这样可以避免进入TIME_WAIT 状态。

3. l_onoff 和 l_linger 均不为 0 ,close 阻塞直到:
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); /* data 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 data from client */
Write(sockfd, "", 1); /* server's ACK back to client */

这样,我们就可以保证,当客户端 read 返回时,服务进程已经读到了客户端发送的数据。(这里假定服务进程知道客户端一次发送多少数据)


shutdown函数、close 函数、以及 SO_LINGER 总结