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段仅代表对方不再发送数据,但对方还是可以读取数据的,可以让对方可以继续读取缓冲区剩余的数据。

==================================================================================

socket关闭有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

  1. shutdown和close的区别:(1)调用shutdown会马上关闭指定链接, 而close会等到描述符的引用计数器为0时才会开始关闭链接; (2)close会同时关闭两个链接, 而shutdown值关闭指定链接; (3)close后文件描述符不再可用(引用基数为0,释放资源), shutdown后文件描述符是可用的. (Page.172)

  2. 对一个sockeet描述符shutdown了SHUT_RD后, 按照UNPv1的说法是, 如果另一方继续发送数据, 那么这些数据仍然会被接收方确认, 只是接收方会自动删掉这些数据, 不会交给用户进程. 而在linux下面, 如果想这样一个shutdown了SHUT_RD的链接发送数据, 发送方会收到RST. (Page.173)

  3. 对一个socket描述符shutdown SHUT_WR, 那么内核会在发送完缓存中的数据后发送FIN启动断开连接. (Page.173)

  4. 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),套接字才被释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值