传输层协议—UDP协议
文章目录
- 传输层协议—UDP协议
- 传输层
- 再谈端口号
- 端口号范围划分
- pidof
- netstat
- UDP协议端格式
- UDP报文
- UDP特点
- UDP缓冲区
- 基于UDP的应用层协议
传输层
在学习HTTP/HTTPS等应用层协议时,为了方便理解,可以简单认为HTTP将请求和响应直接发送到网络中。实际上HTTP是将数据打包交付给下层传输层,然后传输层协议对该数据进行处理后继续向下交付,该过程贯穿成功网络协议栈,最后才将数据发送到网络中。
传输层负责将数据通过网络发送到对方主机的传输层的接收缓冲区中。因此为了方便理解,在学习传输层协议时可以简单认为传输层是直接将数据发送到网络中。
再谈端口号
端口号(Port)标识了一个主机上进行通信的不同的应用程序
当主机从网络中获取到对方发送过来的数据时,将数据自底向上进行解包交付,交付到传输层时,传输层协议要通过端口号将数据交付给应用层的指定进程(程序)。
- 由于端口号属于传输层概念,因此自底向上交付到传输层的报文的报头内就含有端口号,解包后传输层协议能拿到该端口号,根据该端口号将有效载荷交付给对应的程序。
五元组标识一个通信
在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信。
- 源IP和源端口号标识发来报文的来源主机和来源服务程序,目的IP标识网络中接收数据的主机,目的端口号标识的是传输层向上交付的应用层服务程序。
- 协议号标识的是发送方接收方双方规定所使用的协议。
例如服务器的IP是172.20.100.32,该服务器上有多进程版服务程序。有两个客户端连接上了服务器。因此服务器收到不同的客户端发送来的请求,是根据源IP区别出不同的主机、根据源端口号区别出目标主机上的不同程序。而客户端B发送请求给服务器需要根据目的IP找到服务器主机,目的端口号找到目标主机的服务程序。
- 通过源IP、目标IP、协议号、源端口号、目的端口号这五个数字标识一个通信。
五元组可以通过netstat -n查看
- 假如本地是服务器,那么从服务器的角度查看,Local Address对应的是目的IP和目的端口号,Foreign Address对应的是源IP和源端口号。
端口号范围划分
0—1023:知名端口号,例如HTTP,FTP,SSH等这些广为使用的应用层协议,这些端口号都是固定的。
知名端口号有:
- ssh服务器, 使用22端口
- ftp服务器, 使用21端口
- telnet服务器, 使用23端口
- http服务器, 使用80端口
- https服务器, 使用443
1024—65535:操作系统动态分配的端口号,客户端程序的端口号, 就是由操作系统从这个范围分配的。
可以通过指令查询刀知名端口号
cat /etc/services
因此我们自己写服务器使用端口号时,就需要避开这些知名端口号。
- 一个端口号是否可以被多个进程bind?
数据自底向上交付时,在传输层需要找到数据报头内含的目的端口号对应的进程,并交付给该进程,这注定着一个端口号只能标识一个进程,不能一个端口号标识多个进程。因此一个端口号只能被一个进程bind。
- 一个进程是否可以bind多个端口号?
一个端口号只能bind一个进程,但一个进程可以bind多个端口号。服务器具备多种功能时,客户端就需要根据不同的功能,选择不同的端口号进入同一个服务器,即从不同的端口号进入同一个进程。
pidof
pidof 进程:查询到该进程的pid。
xargs:将管道传输过来的内容尾接到后面的指令后面。例如图中的 pid httpserver | xargs kill -9管道传输过来httpserver的pid,xargs将该pid尾接到kill -9后面即给httpserver进程发送9号命令。
netstat
netstat
是一个用于查看网络连接和网络统计信息的命令行工具。它可以用来显示当前系统上的网络连接、路由表、接口统计信息等等。在 Linux 系统中,netstat
命令的用法如下:
netstat [options]
一些常用的选项包括:
-a
:显示所有的连接,包括监听中和已建立的连接。-t
:显示 TCP 协议的连接。-u
:显示 UDP 协议的连接。-n
:以数字形式显示 IP 地址和端口号,而不是尝试进行 DNS 解析。-p
:显示与连接关联的进程信息。-r
:显示路由表。-l
:仅显示监听中的连接。-atun
:显示所有的TCP和UDP连接
注意一下:这里出现了两个连接,原因在于服务器和客户端在同一台主机上,即服务器和客户端完成了本地环回,因此能看到两个连接。
UDP协议端格式
UDP报文
- 报文=报头+有效载荷。报头长度为8字节,即UDP报头为固定报头,当传输层收到UDP报文时,提取前8字节,剩下的为有效载荷,直接向上交付给应用层即可。
- 报头内含16位源端口号,16位目的端口号,16位UDP长度,16位UDP校验和。当发送UDP报文给对方时,需要对整个UDP报文做检查,16位UDP校验和标识UDP报文的完整性。对方收到UDP报文后,先对整个UDP报文做检查,也形成一个16位UDP校验和,然后将形成的校验和与UDP报头的校验和做比对,若相同则说明UDP报文完整,没有在传输途中发生报文丢失。若校验和出错,就会直接将UDP报文丢弃。
- 源端口号和目的端口号的长度是16位的原因是内核的端口号也是16位的,底层决定了上层数据长度。
- 16位UDP长度, 表示整个数据报(UDP首部+UDP数据)的最大长度。而2的16次方大约是64kb,这意味着UDP报文大小最大为64kb。因此通过UDP通信,报文大小大于64KB时,就需要将一个报文拆解成多个报文进行发送。
- 应用层将数据以UDP协议的方式发送到网络中,其实是将数据自顶向下做封装。传输层拿到应用层交付的数据后,给该数据添加UDP报头,然后继续向下交付。
- 实际上报头是OS层面定制的协议。由于Linux内核是由C语言写的,因此可以把报头看作是一个结构体
struct udp_hdr
,那么传输层收到应用层交付过来的数据时,先开辟一块空间,空间容纳一个报头大小,将报头里面的属性填充,最后加上数据就成为一个报文了。
UDP特点
- 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接。
- 不可靠:没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层 返回任何错误信息。UDP在传输层交付給下层就不关心了,即掉包后没有反应。
- 面向数据报:不能够灵活的控制读写数据的次数和数量,給多少发多少。sendto 几次recvfrom几次。相比于:TCP可能发了很多次,而接收要根据应用层实现。
UDP缓冲区
- UDP没有真正意义上的发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后 续的传输动作。没有发送缓冲区使得上层应用层的send/write函数调用完直接返回,不用阻塞。因为该函数直接将数据拷贝到传输层,由传输层自主决定将数据拷贝到OS的内核缓冲区,拷贝完直接返回,因此函数不关心数据的发送。
- UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致。如果缓冲区满了, 再到达的UDP数据就会被丢弃;
- UDP的socket即能够读也能够写,虽然没有发送缓冲区,但是有接收缓冲区,因此通过UDP协议通信可以完成全双工通信。
基于UDP的应用层协议
- NFS: 网络文件系统
- TFTP: 简单文件传输协议
- DHCP: 动态主机配置协议
- BOOTP: 启动协议(用于无盘设备启动)
- DNS: 域名解析协议
当然, 也包括你自己写UDP程序时自定义的应用层协议。