一.TCP基础入门
1、TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接。
2、客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道(也就是确认连接的可靠性和安全性)。
3、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)有效。
ACK:确认序号有效。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:建立一个新连接。
FIN:断开一个连接。
三.TCP的三次握手
所谓的三次握手即TCP连接的建立。这个连接必须是一方主动打开,另一方被动打开的。
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
-
①首先客户端向服务端发送一段TCP报文
- 标记位为SYN,表示“请求建立新连接”;
- 序号为Seq=x(x一般为1);
- 随后客户端进入SYN-SENT阶段。
-
②服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文
- 标志位为SYN和ACK:表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
- 序号为Seq=y
- 确认号为Ack=x+1:表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。
-
③客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:
-
标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
-
序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;
-
确认号为Ack=x+2,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;
-
随后客户端进入ESTABLISHED阶段。
小结:三次握手的关键是要确认对方收到了自己的数据包,这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,看Ack = Seq + 1是否成立,如果成立说明对方正确收到了自己的数据包。
问题一:为什么需要第三次通信 ?-
第一次握手:客户端向服务器发送信息之后,服务器收到信息后可以确认自己的收信能力和客户端的发信能力没有问题
-
第二次握手:服务器向客户端发送信息之后,客户端收到信息后可以确认自己的收信能力和服务器的发信、收信能力没有问题
-
第三次握手:客户端向服务器发送信息之后,服务器收到信息后可以确认自己发信能力没有问题
小结:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
问题二:TCP的三次握手一定能保证传输可靠吗?
- 三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。
- 世界上不存在完全可靠的通信协议。从通信时间成本空间成本以及可靠度来讲,选择了“三次握手”作为点对点通信的一般规则。
-
-
四.TCP的四次挥手
建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。
-
第一次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态。
-
第二次挥手:服务端收到FIN后,发送一个ACK给客户端,服务端进入CLOSE_WAIT状态。
-
第三次挥手: 服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态。
-
第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,发送ACK给服务端,服务端进入CLOSED状态,完成四次挥手。
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。问题一:为什么连接的时候是三次握手,关闭的时候却是四次挥手 ?
- 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
- 但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
问题二:为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态 ?
虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在客户端发送出最后的ACK回复,但该ACK可能丢失。服务端如果没有收到ACK,将不断重复发送FIN片段。所以客户端不能立即关闭,它必须确认服务端接收到了该ACK。客户端会在发送出ACK之后进入到TIME_WAIT状态。客户端会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么客户端会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,客户端都没有再次收到FIN,那么客户端推断ACK已经被成功接收,则结束TCP连接。
版权声明:本文为CSDN博主「辰兮要努力」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45393094/article/details/104965561