目录
在博主之前的文章中曾经详细介绍过OSI协议的七层分层方式Linux网络:协议分层/OSI七层模型,而在宏观概念中,通常将应用层、表示层、会话层,这三层,统称为应用层。而我们熟知的UDP、TCP则是传输层的协议,例如http这样的应用层协议,其底层传输层就是用TCP协议。而TCP协议也叫面向字节流的协议,其内部构成非常复杂,本文就先从结构相对简单的UDP协议分析理解。
一、端口号
有些服务器是非常常用的, 为了使用方便, 人们约定一些常用的服务器, 都是用以下这些 固定的端口号:
• ssh 服务器, 使用 22 端口
• ftp 服务器, 使用 21 端口
• telnet 服务器, 使用 23 端口
• http 服务器, 使用 80 端口
• https 服务器, 使用 443
执行下面的命令, 可以看到知名端口号
C
cat /etc/services
我们自己写一个程序使用端口号时, 要避开这些知名端口号.
1. 一个进程是否可以 bind 多个端口号?(可以,只要保证端口号所映射的进程唯一就可以)
2. 一个端口号是否可以被多个进程 bind?(不可以)
二、UDP
UDP 协议端格式
• 16 位 UDP 长度, 表示整个数据报(UDP 首部+UDP 数据)的最大长度;
• 如果校验和出错, 就会直接丢弃;
UDP 的特点
UDP 传输的过程类似于寄信.
• 无连接: 知道对端的 IP 和端口号就直接进行传输, 不需要建立连接;
• 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP 协议层也不会给应用层返回任何错误信息;
• 面向数据报: 不能够灵活的控制读写数据的次数和数量;
注意:博主认为,这里的不可靠并不是说UDP不好,只是其一种特点而已,每种协议都有自己适合的应用场景,所谓的不可靠只是前辈设计师们在设计时为了提升效率从而摒弃了可靠性这一特点,如果要保证一个协议具有非常强的可靠性(如TCP)那注定这个协议就会变得很复杂,从效率上来讲也注定会有降低。
例如日常我们收看直播,其底层传输协议用的大多都是UDP,人们看直播就是为了更好的看到当下同步发生的内容,如果传输时发生丢包,相比于看到刚刚发生了什么,大多数人更在意现在事情进行到哪一步了,此时传输实时数据的优先级肯定是比丢包内容要更重要的。
面向数据报
应用层交给 UDP 多长的报文, UDP 原样发送, 既不会拆分, 也不会合并;
用 UDP 传输 100 个字节的数据:
• 如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节;
UDP缓冲区
• UDP 没有真正意义上的发送缓冲区. 调用 sendto 会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作;
• UDP 具有接收缓冲区. 但是这个接收缓冲区不能保证收到的 UDP 报的顺序和 发送 UDP 报的顺序一致; 如果缓冲区满了, 再到达的 UDP 数据就会被丢弃;
• UDP 的 socket 既能读, 也能写, 这个概念叫做 全双工
三、使用UDP的注意事项/基于UDP的应用层协议
UDP 使用注意事项
我们注意到, UDP 协议首部中有一个 16 位的最大长度. 也就是说一个 UDP 能传输的数 据最大长度是 64K(包含 UDP 首部).
然而 64K 在当今的互联网环境下, 是一个非常小的数字. 如果我们需要传输的数据超过 64K, 就需要在应用层手动的分包, 多次发送, 并在接收端 手动拼装;
基于 UDP 的应用层协议
• NFS: 网络文件系统
• TFTP: 简单文件传输协议
• DHCP: 动态主机配置协议
• BOOTP: 启动协议(用于无盘设备启动)
• DNS: 域名解析协议 当然, 也包括你自己写 UDP 程序时自定义的应用层协议;