第4章:传输层详解

大家好,我是你们的老朋友。今天我们来聊聊传输层,这一层可以说是TCP/IP协议栈里的「心脏」。我做了十几年网络,遇到过太多问题都出在这一层。说白了,传输层就是给上层应用提供「端到端」的通信服务。没有它,你的浏览器、、游戏,全都玩不转。

4.1 端口号概念

先说说端口号。很多人刚学网络时,会把IP地址比作「门牌号」,那端口号就是「房间号」。一台服务器只有一个IP,但可以同时跑Web服务、邮件服务、数据库服务。怎么区分?靠端口号。

端口号是一个16位的数字,范围0~65535。我习惯把它们分成三类:

  • 知名端口(0~1023):HTTP用80,HTTPS用443,SSH用22。这些是固定的,别乱改。
  • 注册端口(1024~49151):比如MySQL用3306,Redis用6379。应用开发者可以申请。
  • 动态/私有端口(49152~65535):客户端临时用。你打开浏览器访问百度,系统会随机分配一个。

重要概念:一个TCP连接由四元组唯一标识——(源IP, 源端口, 目的IP, 目的端口)。这四个元素缺一不可。

我在项目中遇到过一个问题:两台服务器之间建立连接,明明IP和端口都对,就是连不上。查了半天,发现是源端口被防火墙限制了。嗯,端口号不只是「房间号」,它还是防火墙的「通行证」。

4.2 UDP协议特点与报文结构

UDP,全称用户数据报协议。我经常跟新人说:UDP就是个「莽夫」,它只管把数据扔出去,不管对方收没收到。

UDP的特点:

  • 无连接:不需要三次握手,直接发数据。你想想看,这多快。
  • 不可靠:不保证数据到达,不保证顺序,不保证不重复。
  • 面向报文:应用层给多少数据,UDP就原样封装发送,不拆分也不合并。
  • 头部开销小:只有8字节。

UDP报文结构:

字段 长度 说明
源端口 16位 发送方端口号
目的端口 16位 接收方端口号
长度 16位 UDP头部+数据的总长度
校验和 16位 检测数据是否损坏

我的经验:UDP适合实时性要求高的场景,比如视频通话、在线游戏。我曾经调过一个视频会议系统,用TCP时画面卡得不行,换成UDP后流畅多了。代价是偶尔花屏,但用户能接受。

4.3 TCP协议特点与报文结构

TCP和UDP正好相反。TCP是个「老管家」,做事一丝不苟。它要确保每一份数据都准确送达,顺序不乱,不丢不重。

TCP的特点:

  • 面向连接:通信前先建立连接,通信后释放连接。
  • 可靠传输:有确认、重传、排序机制。
  • 面向字节流:应用层数据被看作一串字节流,TCP会按需分段。
  • 全双工通信:双方可以同时收发数据。
  • 流量控制与拥塞控制:后面会细讲。

TCP报文结构(重点):

字段 长度 说明
源端口 16位 发送方端口
目的端口 16位 接收方端口
序列号 32位 本报文段数据的第一个字节序号
确认号 32位 期望收到的下一个字节序号
数据偏移 4位 头部长度,单位是4字节
标志位 6位 URG/ACK/PSH/RST/SYN/FIN
窗口大小 16位 接收方还能接收多少数据
校验和 16位 检测头部和数据
紧急指针 16位 URG=1时有效

注意:TCP头部最小20字节,最大60字节。因为有「选项」字段,可以扩展。我曾经见过一个奇葩问题,某个交换机把带时间戳选项的TCP包给丢了,排查了两天才找到原因。

4.4 三次握手与四次挥手

这是面试必考题,也是实际排障的利器。我建议你不仅要背,还要理解为什么这么设计。

三次握手(建立连接):

  1. 客户端发SYN:seq=x,进入SYN_SENT状态。
  2. 服务端回SYN+ACK:seq=y,ack=x+1,进入SYN_RCVD状态。
  3. 客户端发ACK:seq=x+1,ack=y+1,双方进入ESTABLISHED状态。

为什么会是三次?不是两次?我刚开始学的时候也困惑。其实很简单:两次握手无法防止「已失效的连接请求」到达服务器。你想想看,如果客户端发了个SYN,网络延迟了,客户端超时重发,结果第一个SYN又到了。两次握手的话,服务器就直接建立连接了,白白浪费资源。三次握手让服务器等客户端的确认,就能避免这个问题。

四次挥手(释放连接):

  1. 客户端发FIN:seq=u,进入FIN_WAIT_1。
  2. 服务端回ACK:ack=u+1,进入CLOSE_WAIT。客户端收到后进入FIN_WAIT_2。
  3. 服务端发FIN:seq=v,进入LAST_ACK。
  4. 客户端回ACK:ack=v+1,进入TIME_WAIT,等待2MSL后关闭。

避坑指南:我曾经在生产环境遇到大量TIME_WAIT连接,导致端口耗尽。原因是短连接太多,客户端主动关闭。解决方案:要么用长连接,要么调整tcp_tw_reuse参数。记住,TIME_WAIT是为了保证最后一个ACK能到达,防止旧连接干扰新连接。

4.5 滑动窗口与流量控制

滑动窗口是TCP实现可靠传输和流量控制的核心机制。说白了,就是接收方告诉发送方:「你慢点,我快吃不消了」。

工作原理:

  • 接收方在ACK中携带自己的「窗口大小」。
  • 发送方根据窗口大小,决定发送多少数据。
  • 窗口是动态变化的,接收方处理完数据,窗口就变大。

我习惯把滑动窗口想象成一条流水线。接收方就是流水线末端的工人,他处理得快,就喊「再来一箱」;处理得慢,就喊「先停停」。发送方必须听他的。

我的经验:有一次调优一个文件传输系统,发现速度上不去。抓包一看,接收方的窗口经常变成0。原来是接收方的应用程序读取太慢,导致缓冲区满了。优化了应用层的读取逻辑,速度直接翻倍。

4.6 拥塞控制

流量控制是「点对点」的,拥塞控制是「全局」的。它要防止太多数据注入网络,导致路由器、交换机过载。

TCP拥塞控制有四个算法:

  1. 慢启动:刚开始拥塞窗口cwnd=1,每收到一个ACK,cwnd翻倍。指数增长,直到慢启动阈值ssthresh。
  2. 拥塞避免:超过ssthresh后,每收到一个ACK,cwnd增加1/cwnd。线性增长,比较温和。
  3. 快重传:收到3个重复ACK,立即重传丢失的报文,不等超时。
  4. 快恢复:快重传后,ssthresh设为cwnd/2,cwnd设为ssthresh+3,然后进入拥塞避免。

为什么会这样设计?你想想看,网络拥塞就像高速公路堵车。慢启动是刚上高速时慢慢加速,拥塞避免是到了限速后匀速行驶,快重传是发现前面有事故立刻刹车,快恢复是绕过事故后重新提速。

注意:拥塞控制和流量控制是两个不同的概念。流量控制是接收方管发送方,拥塞控制是网络管发送方。我曾经见过有人把这两个搞混,调了半天参数,问题根本没解决。

传输层核心知识体系 传输层 UDP协议 无连接 · 不可靠 · 面向报文 头部8字节 · 适合实时应用 TCP协议 面向连接 · 可靠 · 面向字节流 头部20-60字节 三次握手 · 四次挥手 滑动窗口 · 流量控制 拥塞控制(慢启动/拥塞避免/快重传/快恢复) 端口号(0-65535)

好了,传输层的内容就讲到这里。端口号是入口,UDP和TCP是两种截然不同的传输方式,三次握手和四次挥手是连接管理的核心,滑动窗口和拥塞控制保证了传输的效率和公平性。这些知识点在实际工作中天天都会用到,建议你多抓包看看,理解会更深刻。

可可精品资料库