【Linux】网络--传输层--TCP协议基础
个人主页~
TCP协议基础
- 一、TCP协议格式
- TCP与UDP的对比
- 二、TCP协议机制
- 三、确认应答机制
- 四、捎带应答
- 五、三次握手和四次挥手
- 1、应用层行为
- 2、三次握手---建立连接
- 3、四次挥手---断开连接
一、TCP协议格式
TCP(传输控制协议)报文结构是网络通信中重要的基础概念,用于实现可靠的数据传输
-
源端口与目的端口
- 作用:标识通信的两端进程(范围:0~65535)
- 示例:HTTP默认使用80端口,HTTPS使用443端口
-
序号
- 作用:标记本报文段中数据的第一个字节在整个数据流中的位置,用于保证数据有序传输
- 特点:SYN标志位为1时,序号为初始序号(ISN),后续序号递增
-
确认序号
- 作用:期望收到的下一个字节的序号,表示已成功接收该序号之前的数据
- 规则:确认号 = 已接收数据的最后一个字节序号 + 1
-
首部长度
- 作用:指示TCP头部的长度(以4字节为单位),最大值为60字节(默认20字节)
- 原因:由于选项字段的存在,头部长度可能变化
-
标志位
用来区分TCP报文的类型
- URG:紧急指针有效,通知接收方优先处理紧急数据
- ACK:确认号是否有效
- PSH:通知接收方立即将数据提交给上层应用,即从TCP缓冲区读走
- RST:重置连接,用于异常中断
- SYN:同步序号,用于请求建立连接
- FIN:终止连接,用于断开连接
-
窗口大小
- 作用:告知发送方当前接收方的可用缓冲区大小,用于流量控制
- 单位:字节数,范围0~65535(通过窗口扩大因子可扩展)
-
校验和
- 作用:验证TCP报文段(包括头部和数据)在传输过程中是否损坏
- 计算范围:TCP头部、数据部分,以及伪首部(包含IP地址和协议号)
-
紧急指针
- 作用:当URG标志位为1时,若当前段起始序列号为
seq
,紧急指针为ptr
,则紧急数据的范围就是seq
到seq + ptr - 1
- 注意:紧急数据会被识别并提前处理,但紧急数据是TCP中的一种特殊机制,实际中较少使用
- 作用:当URG标志位为1时,若当前段起始序列号为
-
选项与填充
- 常见选项:
- 最大段长度:协商每次传输的最大数据量
- 时间戳选项:用于计算往返时间和防止序号回绕
- 填充:确保头部长度为4字节的整数倍
- 常见选项:
-
数据部分
- 内容:封装上层协议(如HTTP、FTP)的数据
- 注意:TCP头部不含长度字段,数据长度通过IP头部的总长度减去IP头部长度和TCP头部长度计算得出
TCP与UDP的对比
特性 | TCP | UDP |
---|---|---|
连接性 | 面向连接(需三次握手) | 无连接(直接发送) |
可靠性 | 可靠(重传、校验) | 不可靠(尽力而为) |
首部开销 | 20~60字节(含选项) | 8字节 |
适用场景 | 文件传输、HTTP等 | 视频流、DNS查询等 |
通过以上结构,TCP能够实现可靠、有序、流量可控的数据传输,是互联网核心协议之一
二、TCP协议机制
- TCP拥有发送缓冲区和接收缓冲区两个缓冲区,发送信息的流程是:
- 写入缓冲区:应用程序需要发送信息时,将信息写入用户缓冲区
- 写入内核:调用
wirte
函数,将信息从用户缓冲区复制到发送缓冲区 - 发送数据:通过网卡和内核TCP模块处理将数据存入另一用户的接受缓冲区
- 写入用户区:调用
read
函数,将信息从接收缓冲区拷贝到用户缓冲区中 - 应用程序获取数据:应用程序从用户缓冲区读取数据
这里发送和接收的数据就是上面我们提到的协议格式下的报文
三、确认应答机制
TCP确认应答机制是确保数据可靠传输的核心机制之一,也是区别于UDP的核心特点之一,在保证可靠性的同时,尽可能优化传输效率
-
基本概念
- 作用:接收方通过发送确认消息,告知发送方数据已成功接收,避免数据丢失
- 可靠性保证:发送方在超时未收到确认消息时,会重传数据,叫做超时重传
-
工作流程
-
序号
- 每个TCP报文段都会携带一个序号,标识该段数据在数据流中的位置
-
确认号
- 接收方通过确认消息返回确认号,表示下一个期望接收的数据序号
- 规则:确认号 = 已成功接收的最后一个字节序号 + 1
- 示例:若接收方成功接收序号1000~1999的数据段,确认号为2000,表示期望接收后续数据
-
确认应答机制
- 单次确认:发送方发送数据后,等待接收方的确认消息
- 批量确认:滑动窗口技术允许发送方连续发送多个数据段,接收方只需确认最后一个连续收到的序号,也叫累积确认
-
-
确认类型
-
累积确认
- 特点:接收方仅确认最后一个连续收到的数据段,忽略中间丢失的段
- 优点:实现简单,减少确认消息数量
- 缺点:若中间某个段丢失,发送方需重传后续所有段,这也叫做线头阻塞
-
选择性确认
- 机制:接收方通过选择性确认选项告知发送方哪些段已接收,哪些段丢失
- 优点:发送方仅重传丢失的段,避免冗余重传
- 适用场景:高带宽延迟网络,如卫星链路
-
-
优化策略
-
延迟确认
- 机制:接收方延迟发送确认消息(通常最多200ms),合并多个确认以减少网络流量
- 适用场景:批量数据传输,如文件下载
-
确认应答压缩
- 机制:在高速网络中,减少冗余确认消息的发送频率
-
-
示例说明
- 发送方发送数据段:序号1000(1000字节) → 序号2000(1000字节) → 序号3000(1000字节),接收方收到序号1000和3000的段:
- 发送确认应答 2000(累积确认,仅确认连续段),那序号2000和序号3000的数据段都会重传
- 若支持选择性确认,额外告知序号3000已接收,发送方根据确认应答和选择性确认,仅重传序号2000的段
- 发送方发送数据段:序号1000(1000字节) → 序号2000(1000字节) → 序号3000(1000字节),接收方收到序号1000和3000的段:
这个确认应答呢我有一个小技巧来记忆,发送方发送数据段之后,比如说发送了序号1000,它代表着1000~1999,那我下一个是不是就要要2000了,那么我们确认应答发送的就是2000
四、捎带应答
我们将捎带应答这个解释过程简化为两张图,黑色斜线表示通信双方,正常情况下如下图所示,左边给右边发送一个报文,右边要给左边一个应答,表示已经收到数据,当然这里的应答也是严格按照TCP报文结构来的,发送的也是一个完整的TCP报文(至少有报头),之后右边再给左边发送报文,左边再给右边发送一个应答
但是这样的效率会很低,在正常情况下,双方不会这样进行通信,而是将应答和要发送的TCP数据整合成一条报文,此时发送的这条报文既是应答又是数据,减少开支
五、三次握手和四次挥手
1、应用层行为
这边我们举一个客户端和服务端的例子
- 三次握手
- ① 服务端应用层行为(服务器初始化):服务端是要先开启的,应用层通过调用
socket
分配一个文件描述符,然后调用bind
函数将这个文件描述符与服务器地址端口绑定,然后调用listen
函数进入监听状态,然后调用accept
函数阻塞等待客户端的连接,此时服务端开启完毕 - ② 客户端应用层行为(建立连接):客户端后开启,应用层通过调用
socket
分配一个文件描述符,然后调用connect
函数向服务器发起将文件描述符与服务器地址端口连接请求,connect
函数会发出SYN段并阻塞等待服务器应答(第一次握手) - ③ 服务器收到客户端SYN,会应答一个SYN-ACK段表示同意建立连接(第二次握手)
- ④ 客户端收到SYN-ACK后会从
connect
函数返回,同时应答一个ACK段(第三次握手)
- ① 服务端应用层行为(服务器初始化):服务端是要先开启的,应用层通过调用
- 数据传输
- ① 建立连接后,TCP协议会提供全双工的通信服务,即同一条连接同一时刻,通信双方可以同时写同时读
- ② 服务器从
accept
函数返回后立刻调用read
函数,读socket
就和读管道一样,没有数据就阻塞等待 - ③ 这时客户端调用
write
发送请求给服务器,服务器收到后从read
返回,对客户端的请求进行处理,在此期间客户端调用read
函数阻塞等待服务器的应答 - ④ 服务器调用
write
函数将处理结果发回客户端,再次调用read
函数阻塞等待下一条请求 - ⑤ 客户端收到后从
read
函数返回,发送下一条请求 - ⑥ 以①~⑤循环
- 四次挥手
- ① 客户端调用
close
关闭连接,此时客户端会向服务器发送FIN段(第一次挥手) - ② 服务器收到FIN后,回应一个ACK,同时
read
返回0(第二次挥手) - ③
read
返回之后,服务器就知道客户端关闭了连接,也调用close
关闭连接,这个时候服务器会向客户端发送一个FIN(第三次挥手) - ④ 客户端收到FIN,返回一个ACK给服务器(第四次挥手)
- ① 客户端调用
2、三次握手—建立连接
三次握手的机制就是建立在捎带应答上的,捎带应答不仅是通信时的一种策略,并且是建立连接时的策略
三次握手也可以是四次握手,理由和上面一样,这里的第二次握手本来也是两条消息合并发送而已
-
对于客户端来说,当我们将ACK发出了,我们就认为连接已经建立成功了,此时客户端的状态就是上上图的ESTABLISHED,建立描述该连接的客户端属性结构体就被建立了,我们TCP协议对于连接的管理当然也是先描述后组织的,此时客户端连接的属性结构体就通过指针被队列组织管理了
-
对于服务器来说,在开启监听状态LISTEN后,收到建立连接报文SYN,会对客户端进行确认并请求建立连接ACK+SYN,然后在收到客户端确认报文ACK之后建立描述该连接的服务器属性结构体,然后这个结构体也会被管理起来
3、四次挥手—断开连接
-
对于客户端来说,当没有数据要读取或发送的时候,发送结束报文FIN,进入等待状态1,FIN_WAIT1,然后一直等待,在接收到服务器的应答ACK后进入等待状态2,FIN_WAIT2,然后一直等待,在收到服务器FIN报文时,发送应答ACK并转为TIME_WAIT状态,等待一个2MSL(报文最大生存时间)的时间,然后进入CLOSED状态
-
对于服务器来说,在接收到客户端发来的结束报文FIN之后,如果自己也没有啥要发给客户端的,那么发送应答ACK并转为等待状态CLOSE_WAIT,处理之前的数据,处理完后向客户端发送结束报文FIN,并转为最终回应状态LAST_ACK,在接收到客户端的ACK的报文后,关闭连接
今日分享就到这里了~