目录
传输层
负责数据能够从发送端传输到接收端。
再谈端口号
端口号(Port)标识了一个主机上进行通信的不同应用程序。

在 TCP/IP 协议中,用"源 IP""源端口号""目的 IP""目的端口号""协议号"这样一个五元组来标识一个通信(可以通过 netstat -n 查看)。

端口号范围划分
- 0~1023:系统端口号(也称知名端口号),其中 0 为保留端口;HTTP、FTP、SSH 等广泛使用的应用层协议在此范围内有约定的默认端口。
- 1024~49151:用户端口号(也称注册端口号)。
- 49152~65535:动态或私有端口号,通常可供客户端临时使用;操作系统实际采用的临时端口范围可以配置。
认识知名端口号(Well-Known Port Number)
有些服务器非常常用。为了使用方便,人们约定一些常用的服务器使用以下固定端口号:
- SSH 服务器:22 端口
- FTP 服务器:21 端口
- Telnet 服务器:23 端口
- HTTP 服务器:80 端口
- HTTPS 服务器:443 端口
执行下面的命令,可以看到知名端口号:
bash
cat /etc/services
我们自己写程序使用端口号时,要避开这些知名端口号。
两个问题
- 一个进程是否可以
bind()多个端口号? - 一个端口号是否可以被多个进程
bind()?
UDP 协议
UDP 协议报文格式

- 16 位 UDP 长度字段表示整个数据报(UDP 首部 + UDP 数据)的长度;
- 如果校验和出错,就会直接丢弃。
UDP 的特点
UDP 传输的过程类似于寄信。
- 无连接:知道对端的 IP 和端口号就直接进行传输,不需要建立连接;
- 不可靠:没有确认机制,也没有重传机制;UDP 本身不向应用层提供远端送达确认;
- 面向数据报:不能灵活地控制读写数据的次数和数量。
面向数据报
UDP 会保留应用层报文的边界,既不会在 UDP 层拆分,也不会合并;较大的 IP 数据报仍可能在网络层被分片。
用 UDP 传输 100 个字节的数据:
- 如果发送端调用一次
sendto()发送 100 个字节,接收端的一次recvfrom()就会消费这个数据报;只要接收缓冲区足够大,就会得到这 100 个字节。不能循环调用 10 次recvfrom()、每次读取同一数据报的 10 个字节;如果缓冲区不足,超出的部分会被截断,而不会留给下一次调用。
UDP 的缓冲区
- UDP 不像 TCP 那样维护用于确认和重传的可靠字节流发送缓冲区 。调用
sendto()会将数据交给内核,由内核交给网络层协议进行后续传输;调用成功并不表示对端已经收到数据; - UDP 具有接收缓冲区,但是这个接收缓冲区不能保证收到 UDP 报的顺序和发送 UDP 报的顺序一致;如果缓冲区满了,再到达的 UDP 数据就会被丢弃。
UDP 的 socket 既能读,也能写,这个概念叫做全双工。
UDP 使用注意事项
UDP 协议首部中有一个 16 位的长度字段,记录 UDP 首部与数据的总字节数,最大可表示 65,535 字节。对于普通 IPv4 数据报,扣除最小 20 字节的 IP 首部和 8 字节的 UDP 首部后,应用数据最大通常为 65,507 字节。
然而,64K 在当今的互联网环境下是一个非常小的数字。
如果需要传输的数据超过 64K,就需要在应用层手动分包、多次发送,并在接收端手动拼装。
基于 UDP 的应用层协议
- NFS:网络文件系统(可使用 UDP)
- TFTP:简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议(用于无盘设备启动)
- DNS:域名解析协议(通常查询使用 UDP,必要时也会使用 TCP)
当然,也包括自己编写 UDP 程序时自定义的应用层协议。