题目描述

1.什么是三次握手,四次挥手?为什么分别要三次与四次?

2.tcp协议中,close_wait与time_wait状态分别代表什么含义,为什么要设计这两种状态,解决了什么问题?

3.time_wait为什么要等待2MSL

4.平时排查问题中遇见大量close_wait应该如何处理?

 

参考答案

1.首先要理解TCP协议的定位,从wikipedia上抄一下定义:传输控制协议英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流传输层通信协议,由IETFRFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。用户数据报协议(UDP)是同一层内另一个重要的传输协议。

 

并且TCP是一个双向全双工的传输协议,这个后面再详细解释。

 

然后再聊一下一下tcp的6个标志位:

  • SYN(synchronous) Synchronize sequence numbers to initiate a connection
  • ACK(acknowledgement) The ackowledgement number is valid
  • PSH(传送) The receiver should pass this data to the application as soon as possible
  • FIN(finish结束) The sender is finished sending data.
  • RST(reset重置) Reset the connection
  • URG(urgent) The URGENT POINTER field contains valid data

image.png

 

image.png

 

step1:client端尝试建立连接,发送了一个tcp报文,这个tcp报文header里的SYN标志位是1,同时会随机生成ISN(initial sequence number)作为sequence number塞到报文的header里,这时候client端进入SYN-SENT状态

step2:server端接受到client端发送的请求,返回报文表示已经收到建立连接的请求,并同时尝试建立server端到客户端的连接。所以这时候header里的SYN与ACK标志位同时被置为1,且server端生成自己的ISN作为sequence number,而ack number则为client端的seq number+1。

step3:client端收到报文,这是client->server端的连接已经被建立,意味着已经可以从client端向server端发送数据,但ciient端同时也要发送ack消息给server端,这时候ack标志位为1,ack number为server端的seq number+1,当server端接受到这条消息表示连接建立成功。

 

然后回答为什么需要三次握手:首先tcp协议是可靠的,所以通过ack机制保证发送方可以确认接收方是否接收到了消息。其次,我们前面提到了tcp是双向全双工的,这意味着什么?意味着一旦建立连接后,client和server都可以主动像对方主动发送消息,且发送数据的时候同时也能够接受数据。所以step1+step2其实是建议client->server端的连接,而step2+step3建立的是server->client的连接。其实到这里我们已经理解了,step2其实是出于效率方面的考虑把2步并为1步,在返回ack的时候同时合并了一个建立连接的报文,所以由4步并为了3步。

 

image.png

step1:client主动发送fin包给server,此时的seq number为u,client端进入fin_wait_1状态

step2:server端接受到消息,发送ack包给client,此时的seq number为v,server端进入close_wait状态(一般这个时候会通知应用层进行相关的操作),client此时进入fin_wait_2状态,client->server的连接已经被close

step3:在等待应用层完成相关操作后,server端也发送fin包,尝试关闭server->client的连接,此时server端进入last_ack状态(看到很多地方说这个时候会带上一个client端中断的ack,这个我理解没什么必要?不知道有没有人可以帮我解释一下)

step4:client端返回ack给server端,并进入time_wait状态,持续2msl

 

为什么要四次挥手:其实大致流程跟三次握手差不多,唯一的差别只是中间两步并没有并成一步,之所以没有并成一步应该是给应用层一点时间来做close的准备工作。

 

2.close_wait与time_wait在上面应该已经都说了,close_wait表示接受到了对方申请关闭连接的请求,但是这个时候可能你的应用层还有事情需要处理,否则这2步就可以合并成一步,直接进入last-ack状态了。而当完成step4之后,server端可能因为网络原因没有接受到ack,这个时候会重复step3,如果client端没有进入time_wait状态而是直接关闭,将会导致server端无法正常关闭。同时,由于网络中的消息传递是存在延时的,如果发送完ack之后立即进入closed状态,然后在相同的port上立即建立新的连接,则有可能接受到上一次连接的残存消息,可能会导各种不可预知的致异常出现。

 

3.考虑最坏的情况,step4client发送给server,这个时候消息丢了,这一步骤最长占用1msl,server端判断消息丢失后,重复step3重新发送fin给client,这一步最长占用1msl,所以加起来就是2msl。

 

4.其实这个问题问得不太好,我们先要了解大量close_wait有什么危害。因为linux分配给一个用户的文件句柄是有限的(一般是1024),如果time_wait或者colse_wait两种状态被一直保持,这些通道会被一直占有,很快就会报出too many open files in system(这个是os层面的报错),然后就gg了。所以首先有有意识大量的close_wait是有危险的,然后根据上面所说的,close_wait是由对象主动发起断开,而你一直没有返回ack,那么你就会一直维持在close_wait状态(一般来说都是client端与server端建立了连接,然后client端忘记close,server端开始主动断开连接,但是client端没有响应,然后就挂起在那了)。然后平时发生问题首先可以等到机器上netstat -na | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}',看看连接的情况(不过有monitor的话一般这一步可以省略)。然后netstat -an,看一下都是哪些连接在time_wait状态,根据server端的ip理论上可以判断出来是哪个连接,再然后就是去看这一块的代码,有没有忘记释放连接的地方。

 

后记:现实场景中可能会更加复杂,比如消息的乱序,丢失等种种情况,上面只讨论了正向流程,想再深入的话可能还需要考虑更多的异常流程。

 

参考文献:

1.https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE

2.http://telescript.denayer.wenk.be/~hcr/cn/idoceo/tcp_header.html

 

posted @ 2019-08-02 11:05 siyed 阅读(2115) 评论(1) 推荐(0) Edit
@Override标签的作用@Override是伪代码,所以是可写可不写的.它表示方法重写,写上会给我们带来好处. 1.可以当注释用,方便阅读. 2.告诉阅读你代码的人,这是方法的复写. 3.编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错. Java注解又称为标 Read More
posted @ 2018-04-23 15:40 siyed 阅读(141) 评论(0) 推荐(0) Edit
一、Redis集群的使用 我们在使用Redis的时候,为了保证Redis的高可用,提高Redis的读写性能,最简单的方式我们会做主从复制,组成Master-Master或者Master-Slave的形式,或者搭建Redis集群,进行数据的读写分离,类似于数据库的主从复制和读写分离。如下所示: 同样类 Read More
posted @ 2018-04-19 20:02 siyed 阅读(409) 评论(0) 推荐(0) Edit
在项目开发最初的时候,他也有过一段狂欢般的快乐时光,不久之后,事情就越来越艰难。 项目的代码越来越难以维护,工作越来越像是一种煎熬,合作的同事对他越来越不满。 “该是与这个项目,与这个公司说 bye bye 的时候了”,他想。他换了一家公司,涨了一点工资,开始了另一段狂欢。 周而复始,一年又一年过去 Read More
posted @ 2018-04-19 16:24 siyed 阅读(197) 评论(0) 推荐(0) Edit
摘要 聚合范围限定还有一个自然的扩展就是过滤。因为聚合是在查询结果范围内操作的,任何可以适用于查询的过滤器也可以应用在聚合上。 版本 elasticsearch版本: elasticsearch-2.x 内容 聚合范围限定还有一个自然的扩展就是过滤。因为聚合是在查询结果范围内操作的,任何可以适用于查 Read More
posted @ 2018-04-19 16:01 siyed 阅读(624) 评论(0) 推荐(0) Edit
celery 官网帮助文档 http://docs.celeryproject.org/en/latest/index.html前言自从发了上次的文章使用celery之深入celery配置, 有一些网友再问我怎么让celery跑起来. 其实说来也是,celery在新手眼里真的是比较重量级,不好懂,今... Read More
posted @ 2015-11-13 17:16 siyed 阅读(305) 评论(0) 推荐(0) Edit
默认python2.6切换成python27 Read More
posted @ 2015-07-22 16:18 siyed 阅读(337) 评论(0) 推荐(0) Edit
只有注册用户登录后才能阅读该文。 Read More
posted @ 2015-05-18 16:42 siyed 阅读(4) 评论(0) 推荐(0) Edit
一:多线程的创建threading库创建线程有两种方式,函数式和继承式1)函数式deffunc():print'Starting'print'Ending't=threading.Thread(name='func',target=func)t.start()2)继承式classThreadClas... Read More
posted @ 2015-04-22 18:07 siyed 阅读(317) 评论(0) 推荐(0) Edit
golang 之 bson 与 struct 转换 Read More
posted @ 2015-03-12 18:13 siyed 阅读(7367) 评论(0) 推荐(1) Edit
点击右上角即可分享
微信分享提示