☰
Linux:传输层 UDP TCP 协议
2026/10/14 3:26:08 网站建设 项目流程

传输层位于OSI七层模型第四层,核心作用:端到端进程通信,通过端口号区分主机上不同应用进程,向上层应用提供通信服务。传输层两大核心协议:UDP、TCP。

一、UDP 协议(用户数据报协议)

1. UDP报文头部格式(8字节固定头部)

UDP头部一共8字节,没有可选字段:

字段长度说明
源端口2字节发送方进程端口号
目的端口2字节接收方进程端口号
数据报长度2字节整个UDP报文总长度(头部+数据),最小8字节,最大65535字节,UDP最大报文64K,数据部分最大 64K‑8字节
校验和2字节校验报文是否损坏,二进制反码求和算法,可置0不校验

校验和计算流程:

  1. 填充伪报文头部,把校验和字段置0;
  2. 对报文所有数据按16bit逐字取反相加求和;
  3. 结果填入校验和字段;
  4. 接收方同样做反码求和,结果为0代表数据未损坏。

2. UDP核心特性

  1. 无连接:通信前不需要建立连接,不需要维护对方连接状态,只需要知道IP+端口就直接发数据。
  2. 不可靠传输:不保证报文一定到达、不保证顺序、不保证不重复,没有确认、重传机制,丢包不会重发。
  3. 面向数据报:应用层给多少数据,UDP就打包一个报文发送;接收方必须一次性读取完整报文,不存在读半个包、粘包问题,但是存在数据报分片问题。

    重点:UDP是整块打包,你sendto一次就是一个UDP数据包,recvfrom必须一次收完整包,不能分次读取。

3. UDP编程要点

  1. 可靠性需要应用层自己实现:序号、ack确认、丢包重传、超时处理都要代码自己写,内核UDP本身不管可靠。
  2. 报文长度限制:单包最大64K;如果业务数据大于64K,应用层手动分包,切割成小块发送。
  3. 支持广播、组播:无连接特性,可以一次sendto发给局域网所有主机(广播),也支持组播。
  4. 不会产生粘包,但是会丢包、乱序。

4. UDP适用场景

适合对实时性要求高,可以容忍少量丢包场景:直播、语音通话、视频会议、DNS查询。


二、TCP协议(传输控制协议)

1. TCP报文头部格式

TCP头部最小20字节,最大60字节,有40字节可选选项。

字段长度说明
源端口2字节发送进程端口
目的端口2字节接收进程端口
序列号 seq4字节当前报文数据第一个字节的编号,实现有序传输
确认号 ack4字节期望收到下一字节的序列号,ack = 对方seq + 数据长度
头部长度4bit以4字节为单位,代表TCP头部总长度;值*4才是真实字节数
保留位6bit保留,默认0
6位标志位6bitURG、ACK、PSH、RST、SYN、FIN
窗口大小2字节滑动窗口大小,流量控制,我方还能接收多少字节数据
校验和2字节校验整个TCP报文(伪头部+头部+数据)
紧急指针2字节URG有效时,偏移量,标记紧急数据末尾位置
选项0‑40字节MSS、窗口扩大、时间戳等协商信息
TCP 6个标志位详解
  1. URG:紧急指针有效,带外紧急数据,不用等待缓冲区读完。
  2. ACK:确认标志,除三次握手第一个SYN包,几乎所有报文ACK=1。
  3. PSH:推送,接收方收到立刻交给应用层,不要缓存等待。
  4. RST:重置连接,异常强制断开,拒绝非法报文。
  5. SYN:同步序列号,建立连接,握手报文。
  6. FIN:结束,代表本方不再发送数据(还可以接收对方数据,半关闭)。

2. TCP核心特性

  1. 面向连接:通信必须先建立连接,结束要释放连接;内核维护连接状态。
  2. 可靠传输:保证数据完整、有序、不重复到达;依靠:序列号+ACK确认、超时重传、校验和。
  3. 面向字节流:应用层数据看作一串无边界字节流;存在粘包问题,内核缓冲区合并数据,接收端不知道原始消息边界。
  4. 流量控制:滑动窗口:接收方通过窗口大小告诉发送方自己缓冲区剩余容量,防止发送方发太快淹没接收端。
  5. 拥塞控制:慢启动、拥塞避免、快重传、快恢复,防止网络过载。

粘包:TCP没有消息边界,多次write的数据在内核缓冲区合并,读出来分不清哪次是哪条消息,需要应用层处理:定长、分隔符、头部+长度。

3. TCP三次握手(建立连接)

客户端主动发起连接,服务端listen等待连接。

  1. 第一次握手:客户端发送SYN=1,seq=x → 客户端状态:SYN_SENT。
  2. 第二次握手:服务端回复SYN=1,ACK=1,seq=y,ack=x+1 → 服务端状态:SYN_RCVD。
  3. 第三次握手:客户端回复ACK=1,ack=y+1 → 双方进入ESTABLISHED,正式可以收发数据。

为什么是三次握手,不是两次?

两次握手无法解决历史延迟的旧SYN报文问题。旧延迟SYN到达服务器,服务器回复SYN+ACK,如果两次握手就直接建立连接,但是客户端根本没有发起这次连接,会造成无效连接占用服务器资源。第三次握手客户端回复ACK,服务端收到ACK才真正建立连接,过滤过期报文。

4. TCP四次挥手(断开连接)

TCP是全双工,双方可以独立关闭自己的发送方向,可以半关闭。

  1. 第一次挥手:客户端发送FIN=1,seq=m,客户端不再发送数据,进入FIN_WAIT_1。
  2. 第二次挥手:服务端回复ACK=1,ack=m+1,状态变为CLOSE_WAIT。此时服务端还可以向客户端发送数据(半关闭);客户端收到ACK进入FIN_WAIT_2。
  3. 第三次挥手:服务端数据发送完毕,发送FIN=1,seq=n,进入LAST_ACK。
  4. 第四次挥手:客户端回复ACK=1,ack=n+1,进入TIME_WAIT;等待2MSL时间后,客户端彻底close。服务端收到ACK立刻CLOSED。

TCP连接和断开过程中,为什么ACK报文回复的时候需要将刚刚接收接收到的报文中的序列号+1通过ACK报文传送给对方?

这个序列号+1在下一次传输的时候,组要作为下一次TCP传输的第一个序列号,给其标号。

注意:FIN只代表“我不再发送”,不等于不再接收;第二次的ACK和第三次的FIN可以合并,如果服务端没有剩余数据,就变成看上去像三次挥手。

图片详解:

TIME_WAIT状态

主动关闭连接那一方才会出现TIME_WAIT,等待2MSL。

MSL:报文最大生存时间,IP报文在网络最大存活时间

为什么等待2MSL?

  1. 保证我方最后发送的ACK报文能到达对方;如果ACK丢失,对方会重传FIN,我方TIME_WAIT状态还可以回复ACK。
  2. 等待网络上本连接残留的旧数据包全部消失,避免新复用端口的连接收到旧连接残留数据。

大量TIME_WAIT怎么处理? TIME_WAIT出现在主动关闭方。出现这个问题可能是我们的电脑上存在爬虫程序。

解决办法:

  1. 开启地址端口重用(setsockopt,SO_REUSEADDR);
  2. 内核调小tcp_tw_wait等待时间。

大量CLOSE_WAIT是什么原因?CLOSE_WAIT是被动关闭方,收到对方FIN,回复ACK,但是应用层没有调用close关闭自己socket。

原因:代码忘记close套接字,线程阻塞卡住,没有执行关闭,大量堆积CLOSE_WAIT,耗尽文件描述符。解决方案:代码保证及时close(fd)。

被动关闭方,收到Fin报文并回复ACK报文后会进入close_wait状态,等待上层调用close(fd),来关闭连接TCP连接。

如果出现大量的close_wait状态就说明此时可能存在很多程序作为被动关闭连接的一方,在程序结束前没有调用close()。

解决办法:及时调用close即可。

连接断开在程序中的表现:

recv取完所有的数据后,返回0,不再阻塞。

send触发异常SIG_PIPE,让程序直接退出,为了避免让程序直接退出可以忽略该信号。

5. TCP可靠性实现四大机制

  1. 序列号 + ACK确认应答:每个字节编号,接收方回复确认号,确认已经收到哪些字节。
  2. 超时重传:发送报文之后启动计时器,超时没收到ACK,重新发送报文。
  3. 校验和:校验报文损坏,损坏报文直接丢弃等待重传。
  4. 去重:收到重复序列号报文直接丢弃。

6. TCP流量控制 vs 拥塞控制

  • 流量控制(滑动接收窗口):控制发送方不要超过接收端缓冲区能力,解决收发两端速率不匹配。窗口字段来自接收方返回报文。
  • 拥塞控制(拥塞窗口 cwnd):控制发送方不要超过网络链路承载能力,防止网络拥堵,内核算法动态计算。

    发送窗口 = min(接收窗口rwnd,拥塞窗口cwnd)

7. TCP适用场景

文件传输、网页HTTP、数据库访问,需要数据完整准确,可接受一定延迟。

三、UDP vs TCP 对比表

对比项UDPTCP
连接无连接面向连接,三次握手、四次挥手
可靠性不可靠,无确认重传可靠传输,ack、重传、去重
传输模式面向数据报,消息有边界,无粘包面向字节流,无消息边界,会粘包
头部大小固定8字节,开销小20‑60字节,头部更大
控制机制无流量、拥塞控制滑动窗口流量控制 + 拥塞控制
实时性高,延迟低相对高延迟
广播组播支持不支持
适用场景直播、语音、DNSHTTP、文件下载、数据库

四、重点

  1. 为什么UDP不可靠还要用?

    TCP为可靠性带来握手、重传、拥塞控制开销;实时业务宁愿丢少量包,也不要等待重传造成卡顿,比如视频通话,丢几帧画面可以接受,卡顿无法接受。

  2. 什么是半关闭?

    调用shutdown(fd,SHUT_WR),本方不再发送数据,但是还可以接收对方数据,对应四次挥手前半段。

  3. RST复位报文什么时候出现? 访问一个没有监听的端口;socket已经关闭还收到数据;异常强制断开连接。
  4. MSS 最大分段大小 TCP选项,每个报文应用层数据最大字节,不包含TCP+IP头部,协商MSS避免IP分片。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询