Chinaunix首页 | 论坛 | 博客
  • 博客访问: 168371
  • 博文数量: 43
  • 博客积分: 95
  • 博客等级: 民兵
  • 技术积分: 215
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-24 17:23
文章分类

全部博文(43)

文章存档

2016年(1)

2015年(5)

2014年(10)

2013年(24)

2012年(3)

我的朋友

分类: LINUX

2013-05-24 17:54:39

 

一、close

    close函数原型如下:

    int close(int sockfd);

参数sockfd为套接字描述符,成功返回0,失败返回-1

错误码errnoEBADF表示一个非有效描述符;EINTER表示被信号中断;EIO表示一个IO错误。

    该函数的功能是关闭套接字描述符引用计数,当计数大于0时什么都不干,当计数等于0时触发TCP/IP的四次挥手,即主动关闭方发送FIN

     比如:在多进程服务器中,父子进程共享套接字描述符,其引用计数为父进程数+子进程数的和,当父进程或其中某个子进程调用close函数时,描述符计数减一,当所有进程都调用close函数后,引用计数减到0,触发TCP/IP四次挥手过程。描述符计数c = 父进程数+子进程数,当c==0TCP/IP触发四次挥手过程,每一个父进程或子进程调用一次close,描述符计数减1.

    如果在调用close以前,TCP协议栈的发送队列中有已排队等候发送的数据,则协议栈尝试将数据发送出去,发送完毕后根据套接字描述引用计数来决定是否关闭连接。

    如果在调用close以后,且套接字描述符引用计数c==0,则在其上调用write或者read函数则会产生错误码为9EBADF的错误

        需要注意的是:调用close函数时,TCP协议栈对发送队列中已排队等候发送数据的处理流程受SO_LINGER选项的影响,该选项关联的数据结构如下:

        struct linger{

            int l_onoff;    //0=offnonzero=on

            int l_linger;    //linger time

        };

    l_onoff是选项开关,如果是0则关闭选项并且忽略参数l_linger,如果是非零则打开选项,默认是0l_linger是延迟关闭连接时间,只有l_onoff打开时即为非零时,该参数的值才有效。这几个参数与closeTCP协议栈对待发数据的处理流程如下表:

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

错误码errnoEBADF表示一个非有效描述符;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信号。

四、使用场景

服务器上要建立很多子进程,不能用shutdown()只能用close(),客户端可以用shutdown(),也可以用close()。服务器端,每侦听到一个连接就会创建一个子进程,因此是多个子进程的,shutdown会关闭服务器侦听工作,也会关闭其他正在通信的客户端。客户端可以使用shutdown(),因为客户端和服务器端一般只有一条连接,可以使用shutdown()。当客户端与服务器端有多条连接且是在同一个进程中,最好用close(),以免影响到其他连接通信。

 

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