socket shutdown 与 close 函数 的区别
假设server和client 已经建立了连接,server调用了close, 发送FIN 段给client(其实不一定会发送FIN段,后面再说),此时server不能再通过socket发送和接收数据,此时client调用read,如果接收到FIN 段会返回0,但client此时还是可以write 给server的,write调用只负责把数据交给TCP发送缓冲区就可以成功返回了,所以不会出错,而server收到数据后应答一个RST段,表示服务器已经不能接收数据,连接重置,client收到RST段后无法立刻通知应用层,只把这个状态保存在TCP协议层。如果client再次调用write发数据给server,由于TCP协议层已经处于RST状态了,因此不会将数据发出,而是发一个SIGPIPE信号给应用层,SIGPIPE信号的缺省处理动作是终止程序。
有时候代码中需要连续多次调用write,可能还来不及调用read得知对方已关闭了连接就被SIGPIPE信号终止掉了,这就需要在初始化时调用sigaction处理SIGPIPE信号,对于这个信号的处理我们通常忽略即可,signal(SIGPIPE, SIG_IGN); 如果SIGPIPE信号没有导致进程异常退出(捕捉信号/忽略信号),write返回-1并且errno为EPIPE(Broken pipe)。
#include <unistd.h>
int close(int fd);
close 关闭了自身数据传输的两个方向。
#include <sys/socket.h>
int shutdown(int sockfd, int how);
shutdown 可以选择关闭某个方向或者同时关闭两个方向,shutdown how = 0 or how = 1 or how = 2 (SHUT_RD or SHUT_WR or SHUT_RDWR),后两者可以保证对等方接收到一个EOF字符(即发送了一个FIN段),而不管其他进程是否已经打开了这个套接字。而close不能保证,只有当某个sockfd的引用计数为0,close 才会发送FIN段,否则只是将引用计数减1而已。也就是说只有当所有进程(可能fork多个子进程都打开了这个套接字)都关闭了这个套接字,close 才会发送FIN 段。
所以说,如果是调用shutdown how = 1 ,则意味着往一个已经发送出FIN的套接字中写是允许的,接收到FIN段仅代表对方不再发送数据,但对方还是可以读取数据的,可以让对方可以继续读取缓冲区剩余的数据。
==================================================================================
ocket关闭有2个close,shutdown
他们之间的区别:
close-----关闭本进程的socket id,但链接还是开着的,用这个socket id的其它进程还能用这个链接,能读或写这个socket id
shutdown--则破坏了socket 链接,读的时候可能侦探到EOF结束符,写的时候可能会收到一个SIGPIPE信号,这个信号可能直到
socket buffer被填充了才收到,shutdown还有一个关闭方式的参数,0 不能再读,1不能再写,2 读写都不能。
===============================================================================================================
socket 多进程中的shutdown, close使用
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
close(sockfd);
你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继
续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。
int shutdown(int sockfd,int how);
Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:
SHUT_RD:关闭连接的读端。也就是该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被丢弃。进程将不能对该
套接字发出任何读操作。对TCP套接字该调用之后接受到的任何数据将被确认然后无声的丢弃掉。
SHUT_WR:关闭连接的写端,进程不能在对此套接字发出写操作
SHUT_RDWR:相当于调用shutdown两次:首先是以SHUT_RD,然后以SHUT_WR
使用close中止一个连接,但它只是减少描述符的参考数,并不直接关闭连接,只有当描述符的参考数为0时才关闭连接。
shutdown可直接关闭描述符,不考虑描述符的参考数,可选择中止一个方向的连接。
注意:
1>. 如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套
接字将被释放。
2>. 在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会
A <--------------------------->B
1 A、B通信,A给B发送FIN包后,A就不能给B发送数据了,但是B还可以个A发数据,且A要接受。
2 A、B 通信,A调用close后,如果套接字引用计数为0,A会发出一个FIN包 给B, A不能发送数据给B,且A不能接受来自B的数据。此时B调用read,如果接收到FIN 段会返回0,但B此时还是可以write 给A的,write调用只负责把数据交给TCP发送缓冲区就可以成功返回了,所以不会出错,而A收到数据后应答一个RST段,表示A已经不能接收数据
A.B 通信, A调用shutdown,不管套接字引用计数,如果是SHUT_WR,则A发送给B一个FIN包,表示A不在发送数据给B,但B可以发送数据给A,且A可以接受。
如果是SHUT_WRRD,A 发FIN给B,A不发送数据给B, 若B发送数据给A,由于socket已经关闭,B给A应当RST。
如果是SHUT_RD,A 不在读取数据,若B任然给A发送数据,那么A给给B发送RST
转载一段 http://www.haogongju.net/art/158060
-
shutdown和close的区别:(1)调用shutdown会马上关闭指定链接, 而close会等到描述符的引用计数器为0时才会开始关闭链接; (2)close会同时关闭两个链接, 而shutdown值关闭指定链接; (3)close后文件描述符不再可用(引用基数为0,释放资源), shutdown后文件描述符是可用的. (Page.172)
-
对一个sockeet描述符shutdown了SHUT_RD后, 按照UNPv1的说法是, 如果另一方继续发送数据, 那么这些数据仍然会被接收方确认, 只是接收方会自动删掉这些数据, 不会交给用户进程. 而在linux下面, 如果想这样一个shutdown了SHUT_RD的链接发送数据, 发送方会收到RST. (Page.173)
-
对一个socket描述符shutdown SHUT_WR, 那么内核会在发送完缓存中的数据后发送FIN启动断开连接. (Page.173)
-
SHUT_RDWR相当于先shutdown SHUT_RD, 再shutdown SHUT_WR. (Page.173)
即使使用SHUT_RDWR,函数shutdown(2)也不会释放文件描述符。只有最后一个close(2)调用才会释放文件描述符,否则在这之前,它都保持可用状态。shutdown(2)可以被调用多次,只要这期间套接字仍然是连接状态。
使用close(2)中止一个连接,只是减少描述符的引用计数器(references),并不直接关闭连接,只有当描述符引用计数器为0时才关闭连接,释放套接字。比如有多个进程共享一个套接字,close(2)每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close(2),套接字才被释放。