一.TCP简介
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接。
客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。
TCP建立连接时要传输三个数据包,俗称三次握手(Three-way Handshaking)
二.TCP数据报结构
- ①序号:Seq(Sequence Number)序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。
- ②确认号:Ack(Acknowledge Number)确认号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。
- ③标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
- URG:紧急指针(urgent pointer)有效,为1,说明某一位需要被优先处理。
- ACK:确认序号有效,为1为有效。
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:重置连接。
- SYN:建立一个新连接,并在其序列号字段进行序列号的初始值设定。建立连接,设置为1。
- FIN:断开一个连接。
三.TCP的三次握手
过程描述
- ①首先 Client 端发送连接请求报文,
- ②Server 段接受连接后回复 ACK 报文,并为这次连接分配资源。
- ③Client 端接收到 ACK 报文后也向 Server 段发生 ACK 报文,并分配资源,这样 TCP 连接就建立了。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
用谈恋爱的方式理解TCP的三次握手,一分钟秒懂。
一、TCP三次握手成功情况
男:你吃饭了么?(第一次握手)
女:我吃了,你呢?(第二次握手)
男:我也吃了。(第三次握手)
------沟通可以继续,约会开始。
失败情况举例1
男:你吃饭了么?(第一次握手)
女:我吃了。(第二次有应答但无报文)
男想:尼玛没了?直女无疑,离远点。
------男的觉得女的并不想说话,握手失败。
失败情况举例2
男:你吃饭了么?(第一次握手)
女:我吃了,你呢?(第二次握手)
男:……(第三次无应答,握手失败)
女想:没了??装高冷么,渣男只管撩
------沟通无法继续,握手失败
小结:
三次握手的关键是要确认对方收到了自己的数据包,这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,看Ack = Seq + 1是否成立,如果成立说明对方正确收到了自己的数据包。
如果只有两次握手 这个时候客户端没有回应,这样会浪费服务端的资源
那你是否思考过为什么需要第三次通信 ?
在第一次通信过程中,A向B发送信息之后,B收到信息后可以确认自己的收信能力和A的发信能力没有问题。
在第二次通信中,B向A发送信息之后,A可以确认自己的发信能力和B的收信能力没有问题,但是B不知道自己的发信能力到底如何,所以就需要第三次通信。
在第三次通信中,A向B发送信息之后,B就可以确认自己的发信能力没有问题。
小结:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始信息进行协商,这个信息在握手过程中被发送和确认。
四.TCP的四次挥手
建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。
四次挥手过程
1、第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态;
2、第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态;
3、第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态;
4、第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到的序号+1,Server进入CLOSED状态,完成四次挥手;
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。
为什么会有TIME_WAIT状态:
1、确保有足够的时间让对方收到ACK包,一来一去就是2MSL;
2、避免新旧连接混,即不会跟后面的新连接混淆;
服务器出现大量CLOSE_WAIT状态的原因:
原因:没有及时关闭连接
解决方案:
1、检查代码,特别是释放资源的代码;
2、检查配置,特别是处理请求的线程配置;
为什么连接的时候是三次握手,关闭的时候却是四次握手?
①因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
②但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。
③只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
再次用谈恋爱的方式理解TCP四次挥手
TCP四次挥手(双方都可发起)
成功情况
男:我想分手了(第一次挥手)
女:唉……我知道了(第二次挥手)
女:呜呜呜呜呜呜……那等下我还有几句话要说(还有数据未发完),银行卡的密码是奥巴马身份证号后六位,我送你的那顶帽子是前前男友的。(数据传送结束) 好了我说完了。(第三次挥手)
男:好的我知道了(第四次挥手),此时女的立即处于分手状态此时男的还不知道女的是否真正明白自己意思,因此等待了一段时间,到时间后默认女的已经明白。此时男的处于分手状态。------分手成功。
失败情况举例
男:我想分手了(第一次挥手)
女:唉……我知道了(第二次挥手)
女:呜呜呜呜呜呜……那等下我还有几句话要说(还有数据未发完),我们还没一起去新疆玩,我们还没一起看过电影。(数据传送结束) 好了我说完了。(第三次挥手)
男:……
女:你怎么不说话?
男……
女:你是不是不想分手?
男:……
女:嗯?
男:我记得咱家好像衣服还没晒,我去把他晒了,晚上我们去看电影吧?(第三次挥手失败)------由于男的转移话题,第三次挥手手失败,分手失败
补充问题
TCP的三次握手一定能保证传输可靠吗?不能
三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。
世界上不存在完全可靠的通信协议。从通信时间成本空间成本以及可靠度来讲,选择了“三次握手”作为点对点通信的一般规则。