欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  php教程

linux网络编程--shut_down和close()函数的区别

程序员文章站 2022-04-25 13:39:09
...
在Linux C网络编程中,一共有两种方法来关闭一个已经连接好的网络通信,它们就是close函数和shutdown函数,它们的函数原型分别为:

1 #include<unistd.h>

2 int close(intsockfd)

3 //返回:0——成功, 1——失败

4

5 #include<sys/socket.h>

6 int shutdown(intsockfd,inthowto)

7 //返回:0——成功, 1——失败

对一个tcp socket调用close()的默认动作是将该socket标记为已关闭并立即返回到调用该api进程中。此时,从应用层来看,该socket fd不能再被进程使用,即不能再作为read或write的参数。而从传输层来看,TCP会尝试将目前send buffer中积压的数据发到链路上,然后才会发起TCP的4次挥手以彻底关闭TCP连接。
调用close()是关闭TCP连接的正常方式,但这种方式存在两个限制,而这正是引入shutdown()的原因:
1)close()其实只是将socket fd的引用计数减1,只有当该socket fd的引用计数减至0时,TCP传输层才会发起4次握手从而真正关闭连接。而shutdown则可以直接发起关闭连接所需的4次握手,而不用受到引用计数的限制;
2)close()会终止TCP的双工链路。由于TCP连接的全双工特性,可能会存在这样的应用场景:local peer不会再向remote peer发送数据,而remote peer可能还有数据需要发送过来,在这种情况下,如果local peer想要通知remote peer自己不会再发送数据但还会继续收数据这个事实,用close()是不行的,而shutdown()可以完成这个任务。


close函数和shutdown函数的第一个参数都是代表的是一个文件描述符。我们知道,在Linux操作系统中,一切东西都是当作文件来对待,所有的东西,诸如设备、内存都模拟成文件;当然,网络之间的通信也不例外。每一个通信对话都有一个文件描述符对应着,你对它们之间的操作就像在操作本地的文件一样。在shutdown函数当中,还有一个参数howto,它有一下三种值

SHUT_RD:关闭读这一半,此时用户不能再从这个套接字读数据,这个套接口接收到的数据都会被丢弃,对等方不知道这个过程。关闭连接的读端。也就是该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被丢弃。进程将不能对该套接字发出任何读操作。对TCP套接字该调用之后接受到的任何数据将被确认然后无声的丢弃掉。

SHUT_WR:相应地关闭写这一半,此时用户不能再向套接字中写数据,内核会把缓存中的数据发送出去,接着不会再发送数据,对等端将会知道这一点。当对等端试图去读的时候,可能会发生错误。

SHUT_RDWR:关闭读与写两半,此时用户不能从套接字中读或写。它相当于再次调用shutdown函数,并且一次指定SHUT_RD,一次指定SHUT_WR。

SHUT_**在函数库里面都是由宏定义的;由于shutdown提供了第二个,它可以精确的控制一个套接字描述符的关闭,这对close函数来说是无法实现的。在多线程环境中,一个描述符可能是被好几个线程复制了,它们与一个文件关联,并且内核维护一个文件引用计数,只有在引用计数为零的情况下close才可以关闭掉这个文件描述符。
使用close函数有两个限制,却可以使用shutdown来避免:

close函数把描述符的引用计数减一,仅仅在该计数变为0的时候,才真正的关闭套接字,而使用shutdown函数可以不管引用计数就激发了TCP的正常连接终止序列;

close函数终止读和写两个方向的数据传输。既然TCP连接是全双工的,有时候我们需要告知对端我们已经完成了数据发送,我们仅仅需要关闭数据发送的一个通道,但是我们还是可以接收到对端发送过来的数据,这种控制只有利用shutdown函数才能实现。

1>.如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。

2>. 在多进程中如果一个进程中shutdown(sfd,SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程.

相关标签: shut down