一、 传输层与端口号
传输层
传输层的核心任务是负责数据能够从发送端传输到接收端 。为了方便理解,在学习传输层协议时也可以简单的认为传输层协议是将数据直接发送到了网络当中。
而为了区分一台主机上运行的不同应用程序,我们需要引入端口号的概念。
再谈端口号
端口号的本质及作用
端口号标识了一台主机上进行通信的不同的应用程序 。
当主机从网络中获取到数据后,需要自底向上进行数据的交付,而这个数据最终应该交给上层的哪个应用处理程序,就是由该数据当中的目的端口号来决定的。
从网络中获取的数据在进行向上交付时,在传输层就会提取出该数据对应的目的端口号,进而确定该数据应该交付给当前主机上的哪一个服务进程。

因此端口号是属于传输层的概念的,在传输层协议的报头当中就会包含与端口相关的字段。
五元组标识
在 TCP/IP 协议中,使用 {源IP, 源端口号, 目的IP, 目的端口号, 协议号} 这五个信息来唯一识别一个通信 。

比如有多台客户端主机同时访问服务器,这些客户端主机上可能有一个客户端进程,也可能有多个客户端进程,它们都在访问同一台服务器。
而这台服务器就是通过上述的五元组来识别一个通信的。
- 先提取出数据当中的目的IP地址和目的端口号,确定该数据是发送给当前服务进程的。
- 然后提取出数据当中的协议号,为该数据提供对应类型的服务。
- 最后提取出数据当中的源IP地址和源端口号,将其作为响应数据的目的IP地址和目的端口号,将响应结果发送给对应的客户端进程。
通过netstat命令可以查看到这样的五元组信息。

端口号的范围划分
端口号是一个 16 位的整数,主要分为两类 :
知名端口号 (0 - 1023):这些端口分配给广为使用的应用层协议(如 HTTP, SSH 等),是固定的,我们自己写程序时,必须避开这些端口 。
动态端口号 (1024 - 65535):通常由操作系统动态分配,客户端程序的端口号就是从这个范围里拿的 。
常见知名端口号
| 服务名称 | 端口号 | 说明 |
|---|---|---|
| FTP | 21 | 文件传输协议 |
| SSH | 22 | 安全外壳协议 |
| Telnet | 23 | 远程终端协议 |
| SMTP | 25 | 邮件发送协议 |
| HTTP | 80 | 超文本传输协议 |
| HTTPS | 443 | 安全的 HTTP |
我们可以查看/etc/services文件,该文件是记录网络服务名和它们对应使用的端口号及协议。

文件中的每一行对应一种服务,它由4个字段组成,每个字段之间用TAB或空格分隔,分别表示"服务名称"、"使用端口"、"协议名称"以及"别名"。
一个端口号是否可以被多个进程绑定?
一个端口号绝对不能被多个进程绑定,端口号的作用是唯一标识一个进程。如果允许多个进程绑定同一端口,会导致数据接收时的歧义。
一个进程是否可以绑定多个端口号?
这并不违反"端口号唯一标识进程"的原则。比如端口 A 标识进程 X,端口 B 也标识进程 X,两者互不冲突。
也就是说端口号与进程的关系为"多对一"是允许的,"一对多"是禁止的。
netstat命令
在编写网络程序时,我们经常需要查看当前的 socket 状态,netstat 是最常用的命令。
常用选项:
| 选项 | 含义 | 记忆技巧 |
|---|---|---|
| -n | Numeric (拒绝域名解析) | 直接显示 IP 地址和端口号,不解析成域名或服务名(如显示 80 而不是 http)。 |
| -l | Listening (仅显示监听中) | 只显示处于监听状态(Listening)的 socket,常用于检查 Server 是否启动成功。 |
| -p | PID (显示进程信息) | 显示建立相关链接的程序名和 PID。需要 sudo 权限才能看到全部信息。 |
| -a | All (显示所有) | 显示所有连接,包括正在监听的和已建立连接的。 |
| -u | UDP | 仅显示 UDP 相关的连接。 |
| -t | TCP | 仅显示 TCP 相关的连接。 |
(1) 查看所有 UDP 端口绑定情况
如果你写了一个 UDP Server,想看它是否成功 bind 到了指定端口,使用:
bash
netstat -nlpu

(2) 查看特定端口是否被占用
比如你想查 8080 端口被谁占用了,使用:
bash
netstat -nltp | grep 8080

iostat命令
主要用于输出 CPU 和 磁盘 I/O 的统计信息。
常用选项:
| 选项 | 含义 | 场景 |
|---|---|---|
| -c | CPU | 仅显示 CPU 统计信息。 |
| -d | Disk | 仅显示磁盘统计信息。 |
| -k / -m | KB / MB | 以 KB 或 MB 为单位显示传输速率(默认是块/Block)。 |
| -x | Extended | 显示扩展的磁盘详细统计信息(主要看 %util)。 |
| t n | Time / Number | 每隔 t 秒刷新一次,共刷新 n 次。例如 iostat 1 5。 |

CPU属性值说明:
- %user:CPU处在用户模式下的时间百分比。
- %nice:CPU处在带NICE值的用户模式下的时间百分比。
- %system:CPU处在系统模式下的时间百分比。
- %iowait:CPU等待输入输出完成时间的百分比。
- %steal:管理程序维护另一个虚拟处理器时,虚拟CPU的无意识等待时间百分比。
- %idle:CPU空闲时间百分比。
pidof 命令
pidof命令可以通过进程名,查看进程id。

于是可以配合 kill命令快速杀死一个进程。


二、 UDP 协议
UDP 协议格式
UDP 的报文结构非常简单,首部只有 8 字节 :

- 16位源端口号:表示数据从哪里来。
- 16位目的端口号:表示数据要到哪里去。
- 16位UDP长度:表示整个数据报(UDP首部+UDP数据)的长度。
- 16位UDP检验和:如果UDP报文的检验和出错,就会直接将报文丢弃。
UDP 的三大核心特点
UDP 的传输过程类似于"寄信" ,具有以下鲜明特点:
(1) 无连接
只要知道对端的 IP 和端口号,就可以直接发送数据,不需要像 TCP 那样先建立连接 。
(2) 不可靠
- 无确认机制:发送端不知道数据是否到达。
- 无重传机制:如果网络故障导致丢包,UDP 协议层不会重传。
- 无错误反馈:如果发送失败,UDP 不会给应用层返回任何错误信息 。
(3)面向数据报
应用层交给 UDP 多长的报文,UDP 就原样发送,既不会拆分,也不会合并 。
例如你用 UDP 发送 100 个字节的数据,接收端必须调用一次 recvfrom 接收 100 个字节。不能循环调用 10 次每次收 10 个字节 。
UDP如何将报头与有效载荷进行分离?
UDP的报头当中只包含四个字段,每个字段的长度都是16位,总共8字节。因此UDP采用的实际上是一种定长报头,UDP在读取报文时读取完前8个字节后剩下的就都是有效载荷了。
UDP如何决定将有效载荷交付给上层的哪一个协议?
UDP上层也有很多应用层协议,因此UDP必须将有效载荷交给对应的上层协议。
应用层的每一个网络进程都会绑定一个端口号,服务端进程必须显示绑定一个端口号,客户端进程则是由系统动态绑定的一个端口号。UDP就是通过报头当中的目的端口号来找到对应的应用层进程的。
说明一下: 内核中用哈希的方式维护了端口号与进程ID之间的映射关系,因此传输层可以通过端口号得到对应的进程ID,进而找到对应的应用层进程。
UDP 的缓冲区与并发
虽然 UDP 是不可靠的,但它在系统层面依然有缓冲区的概念:
发送缓冲区 :UDP没有真正意义上的发送缓冲区。调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。
接收缓冲区:UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃。
全双工:UDP 的 Socket 既能读也能写,支持全双工通信 。
为什么UDP要有接收缓冲区?
如果UDP没有接收缓冲区,那么就要求上层及时将UDP获取到的报文读取上去,如果一个报文在UDP没有被读取,那么此时UDP从底层获取上来的报文数据就会被迫丢弃。
一个报文从一台主机传输到另一台主机,在传输过程中会消耗主机资源和网络资源。如果UDP收到一个报文后仅仅因为上次收到的报文没有被上层读取,而被迫丢弃一个可能并没有错误的报文,这就是在浪费主机资源和网络资源。
UDP的接收缓冲区的作用就是,将接收到的报文暂时的保存起来,供上层读取。
UDP使用注意事项
需要注意的是,UDP协议报头当中的UDP最大长度是16位的,因此一个UDP报文的最大长度是64K(包含UDP报头的大小)。
然而64K在当今的互联网环境下,是一个非常小的数字。如果需要传输的数据超过64K,就需要在应用层进行手动分包,多次发送,并在接收端进行手动拼装。
基于UDP的应用层协议
- NFS:网络文件系统。
- TFTP:简单文件传输协议。
- DHCP:动态主机配置协议。
- BOOTP:启动协议(用于无盘设备启动)。
- DNS:域名解析协议。
当然,也包括你自己写UDP程序时自定义的应用层协议。