From 60609e244223e897f46a359ec9c70e37d538aded Mon Sep 17 00:00:00 2001 From: ashai <496063163@qq.com> Date: Tue, 28 Jan 2025 13:58:12 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=85=E8=AF=BBtcp=20header=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tcpip/tcp_ip协议.md | 93 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tcpip/tcp_ip协议.md b/tcpip/tcp_ip协议.md index a150d11..31c02bf 100644 --- a/tcpip/tcp_ip协议.md +++ b/tcpip/tcp_ip协议.md @@ -294,3 +294,96 @@ tcp通过如下方式来提供可靠性: - 因为ip数据报可能会发生重复,故而tcp需要对重复数据进行丢弃 - tcp还能提供流量控制,tcp的每一方都有大小固定的缓冲空间,tcp接收方`只允许tcp发送方发送接收方缓冲区所能容纳的数据`。 - 这将避免发送方发送过快导致接收方缓冲区溢出,用于协调发送方发送速率 + +#### 字节流服务 +两个应用之间可以通过tcp连接交换8bit字节构成的字节流。`tcp不在字节流中插入任何记录标识符`。 + +故而,当发送方先发送10字节,再发送20字节,最后发送50字节时,`tcp的接收方无法获知tcp发送方发送了几次以及每次发送多少字节`。 + +> 在发送方分3次发送了80字节的场景下,接收方接收数据的次数以及每次接收的字节数并不一定和发送方相同。 +> +> 例如,发送方分三次,每次发送10,20,50字节的数据;但接收方可能分四次,每次接收20字节来接收发送方发送的数据。 +> +> tcp并不保证发送方的发送数据次数以及每次发送数据大小与接收方完全相同,tcp可靠性只保证发送方分多次发送的数据都能被接收方正确接收到,对于接收次数和每次接收字节大小没有限制。 + +此外,tcp对于字节流内容并不做任何解释,tcp不知道传输的数据是二进制数据或文本数据,对于数据内容的解释由tcp连接双方的应用层来进行。 + +### tcp首部 +tcp数据被封装在一个ip数据报中,其格式如下: +``` +ip首部 + tcp首部 + tcp数据 +20字节 20字节 +``` +tcp首部的数据格式如下,如果不考虑选项字段,那么tcp首部的大小为20字节 + + +tcp首部各字段含义如下: + +#### 源端口号,目的端口号 +源端口号和目标端口号长度均为16位,范围为`0~65535`。 + +源端口号和目的端口号用于查找发送方和接收方的应用程序进程,`源端口号 + 目的端口号 + 源ip地址 + 目的ip地址`这个四元组能够唯一确定一个tcp连接。 + +一个ip地址和一个端口号也被成为一个socket,socket pair(源ip+源端口号+目标ip+目标端口号)则也是可以唯一确定一个tcp连接双方。 + +#### 序列号 +序列号长度为32bit,用于标识tcp发送端向tcp接收端发送的数据字节流,其表示在当前报文段中的第一个数据字节。 + +> 如果将字节流是两个应用程序间的单向流动,则tcp则通过序列号对每个字节进行计数。序号是无符号的32bit整数,并且会在达到最大值(2^32-1)后重新从0开始计数。 + +##### tcp连接建立 +当创建一个新的tcp连接时,控制位中的`SYN`标志位为1,序列号字段则包含主机选择的初始序号ISN(initial sequence number)。 + +建立连接后,主机发送数据的第一个字节,其序列号为ISN+1,因为SYN标志会消耗一个序号。 + +#### 确认序列号 +确认序列号长度为32bit。 + +每个传输的字节都会被计数,序列序列号的值则是ack的发送方希望接收到的下一个序列号,`即确认序列号应该为已经接收到的数据字节序列号+1`。 + +发送ack无需任何代价,32bit的确认序列号和ack标志位都被包含在tcp首部中,故而当连接建立后,发送的tcp报文段中总是包含确认序列号字段,ack标志位也总是为1. + +##### 全双工 +tcp为应用层提供了全双工的服务,其意味着数据能够在两个方向上独立的进行传输,连接的双方必须维护两个方向上的传输序列号。 + +##### 选择性确认 +tcp协议并不能进行选择性确认。tcp中的ack只能针对`位于xxx位置之前的数据已经全部被接收`这种场景进行确认,但是对如下场景,tcp协议并不支持: +- `1-1024`字节已经被接收,并且接收到另一个报文段`2049~3072`,此时接收方无法针对新的报文`2049~3072`进行ack,因为`1025~2048`尚未被接收,故而接收方只能发送确认序列号为1025的ack +- tcp也无法执行nack操作,例如,`1025~2048`报文段被接收,但是校验和校验失败,那么接收方也只能发送确认序列号为1025的ack,无法对校验失败的报文段执行nack操作。 + +#### 首部长度 +首部长度字段代表tcp首部32bit字的长度,即单位为4字节。首部长度字段占4bit,即代表tcp首部长度最多只能为60字节。 + +当没有选项时,正常tcp首部长度为20字节。 + + +#### 标志位 +tcp首部中存在6个标志位,其中多个标志位可以同时被设置为1,标志位的简介如下。 +- URG: 紧急指针有效 +- ACK: 确认序列号有效 +- PSH: 接收方应该尽快将该报文段交给应用层 +- RST: 重新建立连接 +- SYN: 同步序列号,用于发起一个连接 +- FIN: 发送端完成发送任务 + +#### 窗口大小 +窗口大小用于进行tcp的流量控制,窗口大小字段的长度为16bit,故而窗口大小最大为65535字节。 + +tcp由每一端通过声明窗口的大小来提供流量控制。窗口大小为字节数,开始位置为确认序列号字段指明的值。 + +#### 校验和 +校验和字段为16bit,覆盖了整个tcp报文段,包含tcp首部和tcp数据。 + +校验和字段由发送方进行计算和存储,并且由接收方进行校验。 + +#### 紧急指针 +紧急指针长度为16bit,仅当URG标志位置位时才有效。紧急指针代表一个正的偏移量,和序列号字段相加后的值表示紧急数据最后一个字节的序列号。 + +tcp的紧急方式是发送方向另一方发送紧急数据的方式。 + +#### 可选字段 +最常见的可选字段为最长报文大小(MMS, Max Segement Size),每个连接方通常都在通信的第一个报文段(SYN置位的那个报文段)中指明了MMS选项。 + +#### 数据部分 +在tcp报文段中,数据部分是可选的,如果一方没有数据需要发送,那么tcp报文段中并不包含数据部分,只包含tcp的首部。 +