TCP主动关闭连接 
appl: close(),  --> FIN     FIN_WAIT_1 //主动关闭socket方,调用close关闭socket,发FIN                         
                <-- ACK     FIN_WAIT_2 //对方操作系统的TCP层,给ACK响应。然后给FIN                  
                <-- FIN                  
                --> ACK     "TIME_WAIT"   -- 2MSL timeout -->CLOSED
                                        //TIME_WAIT,防止ACK没有给到对方。
注意:close时,如果TCP发送队列中还有数据,那么将会发送RST包而不是FIN包。
参看:http://rdc.taobao.com/blog/cs/?p=1055
另外:对于Linux下来说,无论是FIN还是RST,应用层read将会返回0,可以认为对方请求关闭链接,调用close关闭fd即可。
TCP被动关闭连接 
            <-- FIN     "CLOSE_WAIT"   //被动方,收到对方的FIN,处于CLOSE_WAIT状态                  
                --> ACK                    //被动方的TCP层,给ACK响应  
                appl: close(),  --> FIN     LAST_ACK      
                                         //被动方调用close,从CLOSE_WAIT转到LAST_ACK
                                         不调close,将一直在CLOSE_WAIT状态。                 
                 <-- ACK         --> CLOSED  
tcp是全双工::
   close()会关闭读写。
   shutdown()可以选择性的关闭读、写或读写。 
 
  主动关系SOCKET链接的一方,会进入TIME_WAIT(作用是防止最后一个ACK包丢失)
   TIME_WAIT的时间会非常长,因此server尽量减少主动关闭连接。
 
close和shutdown的区别:
   int close(int sockfd);   

close(fd)调用会将描述字的引用计数减1,只有当socket描述符的引用计数为0时,才关闭socket,即发送FIN包,因此,在fork()模式中,父进程在accept()返回后,fork()子进程,由子进程处理connfd,而父进程将close(connfd);由于connfd这个socket描述符的引用计数不为0,因此并不引发FIN,所以就没有关闭和客户端的连接。

  int shutdown(int sockfd, int howto);    
  // howto: SHUT_RD, SHUT_WR, SHUT_RDWR  
  shutdown()则不管socket描述符的引用计数,而直接发生FIN,因此会直接关闭链接。 
  shutdown()可控制read/write两个方向的管道。 
   SHUT_RD     shutdown(sockfd, SHUT_RD);后,来自对端的数据都被确认,然后悄然丢弃。       
   SHUT_WR     half close状态。  
close()引发的4次交互:(这里的close是client发起的) 
            client                             server  
               FIN_WAIT_1   ---- FIN M ------>       
                                       //(Server端操作系统的TCP层(网络协议栈)响应ACK包)           
               FIN_WAIT_2   <---- ACK M+1----   CLOSE_WAIT
                                       //(这里必须调用close,才能从CLOSE_WAIT到LAST_ACK)                  
               TIME_WAIT    <------ FIN N -----  LAST_ACK 
                                        //(TIME_WAIT有一个重要的作用就是防止最后一个ACK丢失)           
                            ------- ACK N+1 ---->  CLOSE  
 

2020/2/27更新

最近又理解了一下,close是linux中关闭文件的命令,根据linux中任何皆为文件的特性,调用shutdown后还要调用close才能消除操作系统对这个socket的管理

关于shutdown和close的一些说明:

1. 如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
2. 在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程. 得自己理解引用计数的用法了. 有Kernel编程知识的更好理解了.
3. 只要TCP栈的读缓冲里还有未读取(read)数据,则调用close时会直接向对端发送RST。
4. shutdown与socket描述符没有关系,即使调用shutdown(fd, SHUT_RDWR)也不会关闭fd,最终还需close(fd)。
5. 可以认为shutdown(fd, SHUT_RD)是空操作,因为shutdown后还可以继续从该socket读取数据,这点也许还需要进一步证实。
6.

对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送). 但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据. 所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出

7. 当有多个socket描述符指向同一socket对象时,调用close时首先会递减该对象的引用计数,计数为0时才会发送FIN包结束TCP连接。shutdown不同,只要以SHUT_WR/SHUT_RDWR方式调用即发送FIN包。
8. SO_LINGER与close,当SO_LINGER选项开启但超时值为0时,调用close直接发送RST(这样可以避免进入TIME_WAIT状态,但破坏了TCP协议的正常工作方式),SO_LINGER对shutdown无影响。
9. TCP连接上出现RST与随后可能的TIME_WAIT状态没有直接关系,主动发FIN包方必然会进入TIME_WAIT状态,除非不发送FIN而直接以发送RST结束连接。
 
SO_LINGER

这个参数对应大量短链接的服务器很有必要!

 
  1. shutdown(fd, SHUT_RDWR);

  2. struct linger linger;

  3. linger.l_onoff = 1;

  4. linger.l_linger = 0;

  5. setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));

  6. close(fd);

linger.l_linger = 0;
            setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));
            close(fd);

此选项指定函数close对面向连接的协议如何操作(如TCP)。内核缺省close操作是立即返回,如果有数据残留在套接口缓冲区中则系统将试着将这些数据发送给对方。

SO_LINGER选项用来改变此缺省设置。使用如下结构:

struct linger {

int l_onoff; /* 0 = off, nozero = on */

int l_linger; /* linger time */

};

有下列三种情况:

1、设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;

2、设置 l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;

3、设置 l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完成。

socket链接的关闭连接与close和shutdown的区别的更多相关文章

  1. com.microsoft.sqlserver.jdbc.SQLServerException: Socket closed 或者 该连接已关闭

    com.microsoft.sqlserver.jdbc.SQLServerException: Socket closed 或者 该连接已关闭 解决方案: DBUtil公共方法如下: package ...

  2. 记录 serverSocket socket 输入,输出流,关闭顺序,阻塞,PrintWriter的一些问题.

    关于socket.getOutputStream() 的一些问题, OutputStream的flush是一个空方法,所以需要另一个实现了Flush的流来包装一下 这里为什么使用PrintWriter ...

  3. Python之异常处理和socket套接字连接7

    一.异常处理 1)异常处理的使用意义 什么是异常处理 异常是程序发生错误的信号,即程序一旦出错就会立刻产生一个异常,如果该异常没有被处理 那么异常就抛出来,程序的运行也随之终止 异常分为三部分: 异常 ...

  4. TCP关闭连接(为什么会能Time_wait,Close_wait?)

    版权声明:本文由胡文斌原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/102 来源:腾云阁 https://www.qclo ...

  5. HttpClient如何 关闭连接(转)

    ava代码 HttpClient client = new HttpClient(); HttpMethod method = new GetMethod("http://www.apach ...

  6. php socket如何实现长连接

    长连接是什么? 朋友们应该都见过很多在线聊天工具和网页在线聊天的工具.学校内有一种熟悉的功能,如果有人回复你了,网站会马上出现提示,此时你并没有刷新页面:Gmail也有此功能,如果邮箱里收到了新的邮件 ...

  7. TCP的三次握手(建立连接)和四次挥手(关闭连接)

    参照: http://course.ccniit.com/CSTD/Linux/reference/files/018.PDF http://hi.baidu.com/raycomer/item/94 ...

  8. 关于TCP主动关闭连接中的wait_timeout

    首先我们先来回顾一下tcp关闭连接的过程: 假设A和B连接状态为EST,A需要主动关闭: A发送FIN给B,并将状态更改为FIN_WAIT1, B接收到FIN将状态更改为CLOSE_WAIT,并回复A ...

  9. TCP建立连接的3次握手和关闭连接的4次挥手

    #.3次握手过程状态 第一次握手:建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到SYN包,必须确认客户的SYN(ack=j+ ...

随机推荐

  1. 如何查看linux系统安装时间

    第一种方法: 先查看系统盘挂到哪个分区上,然后用 dumpe2fs  查看这个磁盘分区 创建的时间,即可查出此 服务器 系统安装的时间.() # dumpe2fs /dev/sda3|grep -i ...

  2. kubeadm安装集群系列(kubeadm 1.15.1)

    kubeadm已经进入GA阶段,所以尝试使用kubeadm从零开始安装高可用的Kubernetes集群,并记录下过程和所有坑 本文基于kubeadm 1.15.1 目录 kubeadm安装集群系列-1 ...

  3. Nginx 配置文件解释及简单配置

    Nginx配置文件大致分为以下几个块 1.全局块:配置影响nginx全局的指令.一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker pr ...

  4. RDP爆破方式攻击防控思路梳理

  5. 2019牛客暑期多校训练营(第六场)-D Move

    题目链接:https://ac.nowcoder.com/acm/contest/886/D 题意:给n个物品,每个物品有一个体积值,K个箱子,问箱子的最小体积为多少可将物品全部装下. 思路:比赛时一 ...

  6. Mac下安装SecureCRT客户端并激活

    1. 先下载SecureCRT和破解文件 默认下载到了当前用户的”下载”目录中 2. 在”Finder”中 打开 “scrt-7.3.0-657.osx_x64.dmg” 并将 SecureCRT复制 ...

  7. 查找担保圈-step5-比较各组之间的成员,对组的包含性进行查询,具体见程序的注释-版本2

    USE [test] GO /****** Object: StoredProcedure [dbo].[p03_get_groupno_e2] Script Date: 2019/7/8 15:01 ...

  8. RabbitMQ 的安装配置

    环境:Ubuntu16 linux系统,ERlang语言的源码包 :otp_src_22.0.tar.gz,rabbitMQ安装包:rabbitmq-server-generic-unix-3.7.1 ...

  9. 剑指offer2:C++实现的替换空格(字符中的空格替换为“%20”)

    1. 题目描述 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 2. 思路和方法: 2.1 ...

  10. python------模块基础【第二部分-time】------

    一.time UTC/GMT:世界时间 本地时间:本地时区时间 python中时间日期格式化符号: %y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999) %m 月份(01- ...