linux网络编程之shutdown() 与 close()函数详解

参考TCPIP网络编程和UNP;

shutdown函数不能关闭套接字,只能关闭输入和输出流,然后发送EOF,假设套接字为A,那么这个函数会关闭所有和A相关的套接字,包括复制的;而close能直接关闭套接字。

1.close()函数

  1. <span style="font-size:13px;">#include<unistd.h>
  2. int close(int sockfd);     //返回成功为0,出错为-1.</span>

close 一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程,该套接字描述符不能再由调用进程使用,也就是说它不能再作为read或write的第一个参数,然而TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列。

在多进程并发服务器中,父子进程共享着套接字,套接字描述符引用计数记录着共享着的进程个数,当父进程或某一子进程close掉套接字时,描述符引用计数会相应的减一,当引用计数仍大于零时,这个close调用就不会引发TCP的四路握手断连过程。

2.shutdown()函数

  1. <span style="font-size:13px;">#include<sys/socket.h>
  2. int shutdown(int sockfd,int howto);  //返回成功为0,出错为-1.</span>

该函数的行为依赖于howto的值

1.SHUT_RD:值为0,关闭连接的读这一半。

2.SHUT_WR:值为1,关闭连接的写这一半。

3.SHUT_RDWR:值为2,连接的读和写都关闭。

终止网络连接的通用方法是调用close函数。但使用shutdown能更好的控制断连过程(使用第二个参数)。

3.两函数的区别
    close与shutdown的区别主要表现在:
    close函数会关闭套接字ID,如果有其他的进程共享着这个套接字,那么它仍然是打开的,这个连接仍然可以用来读和写,并且有时候这是非常重要的 ,特别是对于多进程并发服务器来说。

而shutdown会切断进程共享的套接字的所有连接,不管这个套接字的引用计数是否为零,那些试图读得进程将会接收到EOF标识,那些试图写的进程将会检测到SIGPIPE信号,同时可利用shutdown的第二个参数选择断连的方式。

下面将展示一个客户端例子片段来说明使用close和shutdown所带来的不同结果:

客户端有两个进程,父进程和子进程,子进程是在父进程和服务器建连之后fork出来的,子进程发送标准输入终端键盘输入数据到服务器端,知道接收到EOF标识,父进程则接受来自服务器端的响应数据。

  1. /* First  Sample client fragment,
  2. * 多余的代码及变量的声明已略       */
  3. s=connect(...);
  4. if( fork() ){   /*      The child, it copies its stdin to the socket              */
  5. while( gets(buffer) >0)
  6. write(s,buf,strlen(buffer));
  7. close(s);
  8. exit(0);
  9. }
  10. else {          /* The parent, it receives answers  */
  11. while( (n=read(s,buffer,sizeof(buffer)){
  12. do_something(n,buffer);
  13. /* Connection break from the server is assumed  */
  14. /* ATTENTION: deadlock here                     */
  15. wait(0); /* Wait for the child to exit          */
  16. exit(0);
  17. }

对于这段代码,我们所期望的是子进程获取完标准终端的数据,写入套接字后close套接字,并退出,服务器端接收完数据检测到EOF(表示数据已发送完),也关闭连接,并退出。接着父进程读取完服务器端响应的数据,并退出。然而,事实会是这样子的嘛,其实不然!子进程close套接字后,套接字对于父进程来说仍然是可读和可写的,尽管父进程永远都不会写入数据。因此,此socket的断连过程没有发生,因此,服务器端就不会检测到EOF标识,会一直等待从客户端来的数据。而此时父进程也不会检测到服务器端发来的EOF标识。这样服务器端和客户端陷入了死锁(deadlock)。如果用shutdown代替close,则会避免死锁的发生。

    1. if( fork() ) {  /* The child                    */
    2. while( gets(buffer)
    3. write(s,buffer,strlen(buffer));
    4. shutdown(s,1); /* Break the connection
    5. *for writing, The server will detect EOF now. Note: reading from
    6. *the socket is still allowed. The server may send some more data
    7. *after receiving EOF, why not? */
    8. exit(0);
    9. }

linux网络编程之shutdown() 与 close()函数详解的更多相关文章

  1. 网络编程之TCP/IP各层详解

    网络编程之TCP/IP各层详解 我们将应用层,表示层,会话层并作应用层,从TCP/IP五层协议的角度来阐述每层的由来与功能,搞清楚了每层的主要协议,就理解了整个物联网通信的原理. 首先,用户感知到的只 ...

  2. Android编程之LayoutInflater的inflate方法详解

    LayoutInflater的inflate方法,在fragment的onCreateView方法中经常用到: public View onCreateView(LayoutInflater infl ...

  3. Linux网络配置:Nat和桥接模式详解

    Linux网络配置:Nat和桥接模式详解 一.我们首先说一下VMware的几个虚拟设备: Centos虚拟网络编辑器中的虚拟交换机: VMnet0:用于虚拟桥接网络下的虚拟交换机: VMnet1:用于 ...

  4. (十)Linux 网络编程之ioctl函数

    1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ...

  5. linux网络编程之TCP/IP基础

    (一):TCP/IP协议栈与数据包封装 一.ISO/OSI参考模型 OSI(open system interconnection)开放系统互联模型是由ISO(International Organi ...

  6. linux网络编程之socket编程(四)

    经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...

  7. linux网络编程之socket编程(六)

    经过一个国庆长假,又有一段时间没有写博文了,今天继续对linux网络编程进行学习,如今的北京又全面进入雾霾天气了,让我突然想到了一句名句:“真爱生活,珍惜生命”,好了,言归正传. 回顾一下我们之间实现 ...

  8. linux网络编程之posix条件变量

    今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...

  9. linux网络编程之IO函数

    Linux操作系统中的IO函数主要有read(),write(),recv(),send(),recvmsg(),sendmsg(),readv(),writev(). 接收数据的recv()函数 # ...

随机推荐

  1. springmvc_ajax异步上传文件(基于ajaxfileupload.js)

    引入js <script th:src="@{/js/ajaxfileupload.js}"></script> html <tr> <t ...

  2. git pull 之后怎么找回别覆盖掉的内容

    [半夜吓出冷汗,git这个原理还真得好好学学] 不小心把本地写的东西pull了下,然后,全部覆盖掉了,以为就这样没了. 后面想到有“时光穿梭机”,“历史回滚”,在各大群友的帮助下,终于找回了. git ...

  3. PageObject

    import org.openqa.selenium.WebDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import o ...

  4. day5-2正则表达式

    正则表达式: 正则表达式对象的创建 1,构造函数 var pattern =new RegExp("正则表达式","修饰符") var pattern =new ...

  5. swoole 监控文件改动

    <?php /** * 场景: * 进程监控文件改动 */ date_default_timezone_set('PRC'); echo '进程id:' . posix_getpid() . P ...

  6. [Pytorch数据集下载] 下载MNIST数据缓慢的方案

    步骤一 首先访问下面的网站,手工下载数据集.http://yann.lecun.com/exdb/mnist/ 把四个压缩包下载到任意文件夹,以便之后使用. 步骤二 把自己电脑上已经下载好的数据集的文 ...

  7. XML规范化(DTD)

    无意义的XML 之前说过因为xml没有预设的标签,所以说你怎麽写他一般都不会报错. 所以需要对xml的书写格式进行一些限制,这就引入了DTD 下面的这个xml你可以给book添加各种属性还不会报错,但 ...

  8. Centos7 安装redis及简单使用

    一.redis的介绍 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset( ...

  9. 你知道Verilog HDL程序是如何构成的吗

    本节通过硬件描述语言Verilog HDL对二十进制编码器的描述,介绍Verilog HDL程序的基本结构及特点. 二十进制编码器及Verilog HDL描述 二十进制编码器是数字电路中常用的电路单元 ...

  10. Flask - 上下文管理(核心)

    参考 http://flask.pocoo.org/docs/1.0/advanced_foreword/#thread-locals-in-flask https://zhuanlan.zhihu. ...