Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1645827
  • 博文数量: 1493
  • 博客积分: 38
  • 博客等级: 民兵
  • 技术积分: 5834
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-19 17:28
文章分类

全部博文(1493)

文章存档

2016年(11)

2015年(38)

2014年(137)

2013年(253)

2012年(1054)

2011年(1)

分类: 架构设计与优化

2013-05-24 08:42:02

原文地址:socket之close与shutdown 作者:scq2099yt

一、close
        close函数原型如下:
        int close(int sockfd);
        参数sockfd为套接字描述符,成功返回0,失败返回-1,错误码errno:EBADF表示一个非有效描述符;EINTER表示被信号中断;EIO表示一个IO错误。
        该函数的功能是关闭套接字描述符引用计数,当计数大于0时什么都不干,当计数等于0时触发TCP/IP的四次挥手,即主动关闭方发送FIN。
        比如:在多进程服务器中,父子进程共享套接字描述符,其引用计数为父进程数+子进程数的和,当父进程或其中某个子进程调用close函数时,描述符计数减一,当所有进程都调用close函数后,引用计数减到0,触发TCP/IP四次挥手过程。
        如果在调用close以前,TCP协议栈的发送队列中有已排队等候发送的数据,则协议栈尝试将数据发送出去,发送完毕后根据套接字描述引用计数来决定是否关闭连接。
        如果在调用close以后,且套接字描述符引用计数为0,则在其上调用write或者read函数则会产生错误码为9即EBADF的错误

        需要注意的是:调用close函数时,TCP协议栈对发送队列中已排队等候发送数据的处理流程受SO_LINGER选项的影响,该选项关联的数据结构如下:
        struct linger{
            int l_onoff;    //0=off,nonzero=on
            int l_linger;    //linger time
        };
        l_onoff是选项开关,如果是0则关闭选项并且忽略参数l_linger,如果是非零则打开选项,默认是0;l_linger是延迟关闭连接时间,只有l_onoff打开时即为非零时,该参数的值才有效。这几个参数与close时TCP协议栈对待发数据的处理流程如下表:
表1 待发数据处理流程

l_onoff

l_linger

close行为

发送队列

TCP协议栈

忽略

立即返回

保持直至发送完成

接管套接字并保证将数据发送至对端

非零

立即返回

立即放弃

直接发送RST,自身立即复位,不用经过2MSL状态,对端收到复位错误码

非零

非零

阻塞直到l_linger时间超时或数据发送完成(套接字必须设置为阻塞)

在超时时间段内保持尝试发送,若超时则立即放弃

超时则同第二种情况,若发送完成则皆大欢喜


二、shutdown
        shutdown函数原型如下:
        int shutdown(int sockfd, int howto);
        参数sockfd为套接字描述符,howto取值如下:
        (1)SHUT_RD:值为0,关闭连接的读功能。
        (2)SHUT_WR:值为1,关闭连接的写功能。
        (3)SHUT_RDWR:值为2,先关闭连接的读功能,再关闭连接的写功能。
        成功返回0,错误返回-1,错误码errno:EBADF表示一个非有效描述符;ENOTCONN表示在该描述符上未连接;ENOTSOCK表示是一个文件描述符而非套接字描述符。
        shutdown提供了将四次挥手的过程拆分开的可能,需要注意的是,如果调用shutdown时填参数SHUT_WR或者SHUT_RDWR,然后调用write函数则会引发EPIPE/SIGPIPE,因为shutdown以这两个为参数时会发送FIN。


三、区别
1、是否触发四次挥手
close:只是减少套接字描述符的计数,如果计数为0,则触发四次挥手。
shutdown:拆分四次挥手过程,在设置howto参数为SHUT_WR或者SHUT_RDWR时,会立即发送FIN。
2、多进程共享描述符
close:只要描述符计数不为0,没有调用过该函数的进程仍然可以正常收发数据。
shutdown:无论描述符计数是多少,只要任一进程调用该函数都会破坏所有进程的连接,任一进程在该描述符上读取数据都会收到EOF结束符,写数据时会收到SIGPIPE信号。



阅读(570) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~