TCP数据报
三次握手(Three-Way Handshake)
是 TCP 协议中用于建立可靠连接的过程。通过三次握手,客户端和服务器能够确认彼此的存在,并且同步各自的初始序列号,为后续的数据传输做好准备。三次握手确保了双方在正式传输数据前能够建立一个可靠的连接。
三次握手的步骤:
-
第一次握手(客户端 -> 服务器):
-
客户端发送一个 SYN(同步)请求数据包,表示希望与服务器建立连接。客户端选择一个初始序列号(ISN,Initial Sequence Number),并将其附带在请求包中。
-
数据包内容:
-
SYN = 1:表示请求建立连接。
-
seq = x:表示客户端选择的初始序列号。
-
这时,客户端的状态为 SYN_SENT(已发送连接请求)。
-
-
第二次握手(服务器 -> 客户端):
-
服务器收到客户端的 SYN 包后,如果同意连接,会发送一个带有 SYN 和 ACK(确认)标志的数据包作为响应。服务器也会选择自己的初始序列号,并将客户端的序列号加1作为 ACK 值,确认收到客户端的请求。
-
数据包内容:
-
SYN = 1:表示服务器同意建立连接。
-
ACK = 1:表示确认客户端的请求。
-
seq = y:表示服务器选择的初始序列号。
-
ack = x + 1:表示确认收到客户端的序列号(客户端的初始序列号加 1)。
-
服务器的状态变为 SYN_RECEIVED(接收到连接请求)。
-
-
第三次握手(客户端 -> 服务器):
-
客户端收到服务器的 SYN+ACK 包后,向服务器发送一个确认包,表示自己已准备好数据传输。客户端将服务器的序列号加1作为 ACK 值,确认服务器的序列号。
-
数据包内容:
-
ACK = 1:表示确认服务器的响应。
-
seq = x + 1:表示客户端的序列号加 1。
-
ack = y + 1:表示确认收到服务器的序列号(服务器的初始序列号加 1)。
-
客户端的状态变为 ESTABLISHED(连接已建立)。
-
-
连接建立完毕:
-
在第三次握手完成后,客户端和服务器之间的连接建立成功,双方可以开始数据传输。
-
三次握手的目的:
-
确保双方都能接收到对方的序列号:三次握手的过程确保了客户端和服务器都知道彼此的初始序列号,从而可以确保后续数据传输的顺序正确。
-
确认双方都准备好进行数据传输:通过交换同步信号(SYN)和确认信号(ACK),双方确认都已经准备好开始数据传输。
-
防止旧连接数据的干扰:三次握手通过序列号和确认号的机制,确保旧的连接数据不会干扰新连接的建立。
举个例子:
假设你想和朋友通过电话建立通话,三次握手可以类比为:
-
第一次握手:你拨通电话,告诉朋友“我想和你通话”,这就是你发出的 SYN 请求。
-
第二次握手:朋友接到电话,确认可以和你通话并说“我也准备好了”,这是朋友发出的 SYN+ACK 响应。
-
第三次握手:你听到朋友的回复后确认“好的,我也准备好了,现在开始通话”,这就是你发出的 ACK 确认。
在三次确认后,电话通话就正式开始了,类似于 TCP 连接的建立完成,双方可以开始交换数据。
0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 源端口号(16位) | 目标端口号(16位) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 序列号(32位) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 确认号(32位) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 数据偏移 |保留|URG|ACK|PSH|RST|SYN|FIN| 窗口大小(16位) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 校验和(16位) | 紧急指针(16位) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 可选项(可变) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| 数据(可变) |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段 | 长度(位) | 说明 |
---|---|---|
源端口号(Source Port) | 16 | 发送方应用程序的端口号 |
目的端口号(Destination Port) | 16 | 接收方应用程序的端口号 |
序列号(Sequence Number) | 32 | 本段数据的第一个字节在整个字节流中的编号 |
确认号(Acknowledgment Number) | 32 | 期望接收的下一个字节的序号(如果ACK标志置位) |
数据偏移(Data Offset) | 4 | TCP首部长度(以4字节为单位) |
保留(Reserved) | 3 | 保留,置0 |
控制位(Flags) | 9 | 标志位(URG, ACK, PSH, RST, SYN, FIN等) |
窗口大小(Window Size) | 16 | 告诉对方自己还能接收多少字节 |
校验和(Checksum) | 16 | 用于检验数据在传输过程中是否出错 |
紧急指针(Urgent Pointer) | 16 | 如果URG位为1,表示紧急数据的结束位置 |
选项(Options) | 可变 | 可选字段,比如窗口扩大因子、时间戳等 |
填充(Padding) | 可变 | 为了保证TCP首部是32位(4字节)对齐 |
序列号
假设发送方的初始序列号是 1000,发送了以下 4 个数据段:
-
第一个数据段,发送字节 1 到字节 1000,序列号为 1000。
-
第二个数据段,发送字节 1001 到字节 2000,序列号为 1001。
-
第三个数据段,发送字节 2001 到字节 3000,序列号为 2001。
-
第四个数据段,发送字节 3001 到字节 4000,序列号为 3001。
确认号
确认号的作用:
-
确认数据接收:接收方通过确认号告诉发送方,它已经成功接收了哪些数据。比如,如果接收方成功接收到序列号为 1000 到 1007 的数据,接收方会返回一个确认号 1008,表示它希望接收下一个序列号为 1008 的数据。
-
丢包检测:如果发送方在一定时间内没有收到确认号,它就知道可能发生了数据丢失,会重新发送数据。比如,如果发送方在规定时间内没收到确认号 1008,它就会重发序列号为 1000 到 1007 的数据。
-
确保数据顺序:即使数据包乱序到达,接收方也能通过确认号告诉发送方下一个期望的字节序列号,让发送方知道数据是否按顺序到达。
举个例子:
假设你发送的数据的序列号是从 1000 开始:
-
你发送了字节 1000 到 1007 的数据,接收方收到这些数据后,它会返回一个确认号 1008,表示接收方已经成功接收了序列号小于 1008 的数据,期待下一个序列号为 1008。
-
如果接收方只收到字节 1000 到 1003,未收到字节 1004 到 1007,它会继续等待并不会返回 1008,而是会继续要求重传缺失的部分,直到接收到完整的数据。
数据偏移(Data Offset)
是 TCP 头部中的一个字段,用来指示 TCP 头部的长度,即数据部分从哪里开始 。数据偏移字段是一个 4 位的数,表示 TCP 头部的长度,单位是 32 位(4 字节)。
假设你有一个 TCP 数据包,它的 数据偏移 值为 5,表示 TCP 头部的长度是 5 × 4 = 20 字节。这意味着接收方应该从数据包的第 21 字节开始读取实际的数据部分。
如果数据偏移值为 6,表示 TCP 头部的长度是 6 × 4 = 24 字节,那么数据就从数据包的第 25 字节开始。
SYN
是 TCP 报文头中的一个标志位,全称是 Synchronize(同步),它用于 建立连接时同步双方的初始序列号,是 TCP 三次握手 中的重要部分。
✅ 通俗解释:
你可以把 SYN 理解为:“你好,我想和你建立连接,这是我的号码(初始序列号)。”
当两台设备通过 TCP 通信时,它们必须先通过 三次握手 确认彼此都准备好了,并知道对方的“起始编号”,这个编号就是通过 SYN 标志的报文来传递的。
🔁 SYN 在三次握手中的作用:
-
第一次握手:客户端发送一个 SYN=1 的报文,告诉服务器:“我想建立连接,我的初始序列号是 X。”
-
第二次握手:服务器回复一个 SYN=1 + ACK=1 的报文,说:“我同意连接,我的初始序列号是 Y,同时确认你的是 X+1。”
-
第三次握手:客户端再发送一个 ACK=1 报文,确认服务器的序列号 Y+1,连接建立。
URG(Urgent Pointer)
是 TCP 头部中的一个标志位,表示该数据段包含紧急数据。它与 紧急指针(Urgent Pointer) 一起使用,用来告知接收方数据中的某一部分是紧急的,需要优先处理。
假设一个 TCP 数据段的 URG 标志位 为 1,紧急指针为 500。这个意味着接收方应该优先处理从数据段开始到第 500 字节之间的数据(包含第 500 字节)。然后,接收方可以继续处理剩下的普通数据。
FIN
是 TCP 协议中的一个控制标志位,全称是 Finish(结束),表示“我已经没有数据要发送了,但我还可以接收你的数据”。
它用于 TCP连接的释放阶段,也就是我们常说的 “四次挥手” 中,FIN 标志就是“挥手”的信号。
TCP 四次挥手中 FIN 的使用过程:
-
第一次挥手(客户端发送 FIN):
客户端想关闭连接,向服务器发送一个带 FIN=1 的数据包,告诉服务器“我已经发完了,你可以关我这边的发送通道”。 -
第二次挥手(服务器回 ACK):
服务器收到 FIN 后,发送一个 ACK 包,表示“我知道了,但我可能还有数据要发,等我发完再说”。 -
第三次挥手(服务器发送 FIN):
等服务器也没有数据可发了,就发送一个带 FIN=1 的数据包给客户端,请求关闭它的发送通道。 -
第四次挥手(客户端回 ACK):
客户端收到后回复 ACK,连接彻底断开。客户端会进入一个叫 TIME_WAIT 的状态,等一段时间确保服务器收到了 ACK,才真正关闭连接。
📌 举个例子:
你和朋友打电话,说完自己的话后,你说:“我说完了(FIN)。”
朋友听到后回答:“我知道了(ACK)。”
然后朋友继续说他的内容,说完后他说:“我也说完了(FIN)。”
你听到后说:“好的,我也知道了(ACK)。”
这时你们才挂掉电话。
窗口大小(Window Size)
是 TCP 协议中一个非常关键的概念,它表示接收方能够一次接收、缓存但尚未确认的数据量,单位是字节(Bytes)。
✅ 通俗解释:
你可以把窗口大小想象成水杯的容量,而发送方的数据就像水。发送方可以往水杯里倒水(发数据),但不能超过杯子的容量(窗口大小),否则水会溢出(接收方缓存不下)。
所以,窗口大小的作用是:
-
告诉发送方:“我现在还能接收这么多数据,请别一下子发太多。”
-
控制数据发送速率,防止接收方来不及处理,造成数据丢失。
-
实现 TCP 的 流量控制(Flow Control)。
📦 举例说明:
假设你是接收方,你告诉对方:“我的窗口大小是 3000 字节。”
发送方就知道:“好,那我最多能连续发 3000 字节的数据,不等确认。”
一旦你确认了收到一部分数据,比如确认了 1000 字节,窗口就又打开了 1000 字节,发送方就可以继续发。
校验和(Checksum)
是 TCP/IP 协议中用于检验数据在传输过程中是否出错的一种机制。它的主要作用是:接收方可以通过计算校验和,判断收到的数据有没有在网络中被损坏。
✅ 通俗解释:
你可以把校验和想象成是“打包清单的总和”。
比如你寄一个包裹给朋友,里面有10样东西,你在单子上写:“这10样东西的总价值是100元”。
朋友收到包裹后,把每件物品的价格加起来,如果加出来也是100元,就知道东西没少;如果不是,就说明包裹中途出了问题。
TCP/UDP/IPv4 中的校验和也是这个道理。
🔧 在 TCP 中怎么用?
-
发送方在发数据前,会对整个 TCP 头部 + 数据 做一个运算,得出一个 16 位的校验值,填入 TCP 头部的“校验和字段”中。
-
接收方收到数据后,用相同的算法重新计算一遍校验和:
-
如果和报文中的校验和一致,说明数据是完整的;
-
如果不一致,说明数据在传输过程中发生了错误(如被干扰、电磁噪声破坏等),就会丢弃这个包。
-
✍️ 校验和的特点:
-
属于一种 差错检测机制,但不能纠正错误(不是纠错码)。
-
IPv4、TCP、UDP 都使用校验和;IPv6 中 IP 层没有校验和,但 TCP/UDP 仍使用。
-
TCP 校验和还包括一个“伪首部”(Pseudo Header),包含源 IP、目标 IP、协议号、数据长度等,用于增强安全性。
📌 举个例子(简化):
-
数据部分是:
0x1234
,0x5678
,0x9abc
-
发送方加起来得到:
0x1234 + 0x5678 + 0x9abc = 0x10168
-
把这个结果“反码取反”,得出校验和
0xFE97
,放进报文中。 -
接收方收到数据后再加一遍,再加上
0xFE97
,结果应该是0xFFFF
(这是正确的标志)。
ACK
是 TCP 报文头中的一个标志位,全称是 Acknowledgment(确认),表示**“确认收到数据”**或“确认连接建立”。
✅ 通俗解释:
你可以把 ACK 理解成:“我收到了你发的数据/请求,这是我的确认回应。”
在 TCP 通信中,每当一方收到数据后,都会用 ACK 来告诉对方:“我收到了,从这个序号之后你可以继续发。”
🧩 ACK 的作用包括:
-
三次握手中用于确认连接请求
-
客户端发送 SYN,服务器回复 SYN + ACK,表示“我同意并确认你的请求”。
-
-
数据传输中确认收到
-
每当一段数据被成功接收,接收方就会发出 ACK 报文,告诉发送方:“你前面发的数据我收到了,请继续。”
-
-
用于可靠传输机制
-
TCP 是可靠协议,靠 ACK 来保证“发的每一段数据都能被确认”,丢了就会重发。
-
🔁 举个例子:
-
客户端发送数据,序列号为 100;
-
服务器收到后,回复一个 ACK=101,意思是:“我已经收到100这个字节,接下来从101开始继续发。”