网络编程中的shutdown和close

close

close一个TCP套接字的默认行为是把该套接字标记为关闭,然后立即返回到调用进程。该套接字描述符不能再由调用进程使用,也就是说它不能再作为read或write的的第一个参数,然而TCP将尝试发生已排队等待发生到对端的任何数据,发生完毕后发生的是正常的TCP连接终止序列。
如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
TCP套接字的SO_LINGER选项可以改变close函数的行为,其数据结构为
在这里插入图片描述
(1)如果l_onoff被设置为0,则其和close的默认情况一样,默认情况下,close会先把发送缓冲区中的数据先发送出去,然后直接返回。close返回后正常的四次挥手会交给系统去完成。close的默认行为只能保证发送缓冲区中的数据正常发送出去,不保证对方能收到。
在这里插入图片描述
(2) l_onoff设置为非0, l_linger也被设置为非0,并且足够大
此时会先把发送缓冲区中的数据先发送出去,然后再调用close函数,此时close不会立即返回而是先block一段时间,直到对方TCP的ACK信息才能返回。这种情况下只能保证对方已经接收到数据,但不能保证对方应用程序已经读到数据,因为ACK是TCP层发送的信息,不是应用层。
在这里插入图片描述
(3) l_onoff设置为非0, l_linger也被设置为非0,并且不足够大 ,这种情况下,close会在对方的ACK信息到来之前返回,并返回-1和设置errorn为EWOULDBLOCK
在这里插入图片描述
(4)意思三种情况都能经历TCP断开连接的四次挥手阶段。当l_onoff设置为非0,l_linger设置为0时,close不被阻塞立即执行,丢弃socket发送缓冲区中的数据,并向对方发送一个RST报文。
值得注意的是RST报文段不会导致另一端产生任何响应,另一端根本不进行确认。收到RST的一方将终止该连接。程序行为如下:
阻塞模型下,内核无法主动通知应用层出错,只有应用层主动调用read()或者write()这样的IO系统调用时,内核才会利用出错来通知应用层对端RST。
非阻塞模型下,select或者epoll会返回sockfd可读,应用层对其进行读取时,read()会报错RST。

shutdown

使用close中止一个连接,但它只是减少描述符的参考数,并不直接关闭连接,只有当描述符的参考数为0时才关闭连接。
shutdown可直接关闭描述符,不考虑描述符的参考数,可选择中止一个方向的连接。
(1)shutdown + SHUT_RD
利用shutdown的SHUT_RD参数,可以关闭连接中本段的读,本段不能再从套接字中读数据,而且套接字中接受缓冲区中的数据都将被丢弃,但是对方仍然可以发送数据,只是数据到达本段后都会被悄然丢弃。另外SHUT_RD参数不会对TCP的连接造成任何影响。后面如果再从该套接字调用read会直接返回0。
(2)shutdown+SHUT_WR
SHUT_WR可以关闭连接中本段写的这一半,对于TCP套接字又称为半关闭。当前留在套接字发送缓冲区的数据都被发送掉,后面紧跟TCP的正常连接终止序列。 该选项可以保证在断开连接过程中,本方的数据被对方应用程序收到,具体做法是:
1)调用shutdown + SHUT_WR,此时本方的TCP会把发送缓冲区中的数据发送出去,然后发送FIN序列来正常终止连接。
2)然后调用read,此时read会被阻塞,直到接收到对方发送FIN序列,然后read返回0,因为FIN序列是由对方应用程序调用close或者shutdown产生的,因此可以保证缓冲区中的数据已经被对方应用程序收到。
(3) shutdown+SHUT_RDWR
连接的读半部和写半部都关闭,这与调用shutdown两次等效,第一次调用指定SHUT_RD,第二次调用指定SHUT_WR。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值