UDP协议

本文详细解释了UDP协议在传输层的位置、报文格式、端口号的作用以及与TCP的区别,介绍了netstat、iostat和pidof等工具的使用,讨论了UDP的无连接、不可靠特性以及接收缓冲区的作用。
摘要由CSDN通过智能技术生成

UDP协议

传输层

上一文的HTTP请求和响应并不是直接发送到网络中进行通信,而是由应用层交付给下一层传输层,再由传输层做处理继续向下交付,最终才能把数据发送到网络中。

传输层负责可靠性传输,确保数据能够可靠地传送到目标地址。

为了方便理解,在学习传输层协议时也可以简单的认为传输层协议是将数据直接发送到了网络当中。

端口号

之前我们提到过端口号标识一个主机上进行网络通信的不同应用程序。当主机从网络中获取数据后,要自底向上的进行数据交付,交付给哪个应用程序是由端口号决定的。

所以端口号属于传输层的概念,在传输层协议的报头中就会包含与端口相关的字段。

在TCP/IP协议中,用“源IP地址”、“源端口号”、“目的IP地址”、“目的端口号”、“协议号”这样一个五元组标识一个通信。

比如一个多个客户端访问一个服务器,而且一个客户端上可能有多个进程,假如都在访问同一个服务器。我们怎么区分这些不同的通信呢?

就是用上面说的五元组:“源IP地址”、“源端口号”、“目的IP地址”、“目的端口号”、“协议号”。

具体过程:

  1. 先取出数据中的“目的IP地址”、“目的端口号”,确定是发给服务器哪个进行的。
  2. 然后取出协议号,为该数据提供对应的服务
  3. 最后取出“源IP地址”、“源端口号”,把它们作为响应的“目的IP地址”、“目的端口号”,并把响应发送给对应的客户端进程

image-20240331171402037

使用以下命令,查看本机网络状态信息。

[root@VM-20-2-centos udp]# netstat -nltp

image-20240331171722390

Proto:protocol协议名

Local Address:源IP地址:源端口号

Foreign Address:目的IP地址:目的端口号

协议号 和 端口号

协议号

  1. 协议号存在于IP报头中,长度是8位。协议号指明数据报所携带的是什么协议,便于目的主机IP层知道该将数据交给传输层的哪个协议处理。
  2. 协议号作用于传输层和网络层之间

端口号

  1. 端口号存在于UDP和TCP报头中,长度是16位。端口号作用是标识用台主机上的某个进程。
  2. 端口号作用于应用层和传输层之间

端口号的长度是16位,所以它的范围是0~65535:

  • 0~1023:知名端口号,比如HTTP、HTTPS、FTP、SSH,它们的端口号都是固定的。
  • 1024~65535:操作系统动态分配的端口号。
知名端口号

这些端口号非常常用,一般都是固定的,不会轻易改变。

  1. ftp服务器:21号
  2. ssh服务器:22号
  3. telnet服务器:23号
  4. http服务器:80号
  5. https服务器:443号

我们可以通过以下命令查看知名端口号

[root@VM-20-2-centos udp]# vim /etc/services

image-20240331173347427

端口号 和 进程
  1. 一个端口号能不能被多个进程绑定?

一个端口号绝对不能被多个进程绑定,因为端口号的作用就是唯一标识一个进程,如果绑定一个已经被绑定的端口号,就会出现绑定失败的问题。

  1. 一个进程能不能绑定多个端口号?

一个进程是可以绑定多个端口号的,这与“端口号必须唯一标识一个进程”是不冲突的,只不过现在这多个端口唯一标识的是同一个进程罢了。

由端口号可以找到唯一的进程,并没有固定从进程找到唯一的端口号,所以一个进程可以绑定多个端口号。

netstat 和 iostat

netstat

netstat是一个用来查看网络状态的重要工具

常见的选项有:

  • -n

不显示别名,能显示数字的全部转换成数字

  • -l

仅列出处于LISTEN(监听)状态的服务

  • -t

tcp,仅显示tcp相关的选项

  • u

udp,仅显示udp相关的选项

  • -p

显示建立相关链接的程序名

  • -a

all,显示所有的选项,默认不显示LISTEN相关

查看tcp相关的网络信息一般使用nltp,查看udp相关网络信息一般使用nlup

[root@VM-20-2-centos udp]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1258/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1336/master         
tcp6       0      0 :::22                   :::*                    LISTEN      1258/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      1336/master         
[root@VM-20-2-centos udp]# netstat -nlup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
udp        0      0 0.0.0.0:68              0.0.0.0:*                           956/dhclient        
udp        0      0 10.0.20.2:123           0.0.0.0:*                           688/ntpd            
udp        0      0 127.0.0.1:123           0.0.0.0:*                           688/ntpd            
udp6       0      0 fe80::5054:ff:fe6b::123 :::*                                688/ntpd            
udp6       0      0 ::1:123                 :::*                                688/ntpd    

image-20240331174255511

iostat

iostat主要用于输出磁盘IO和CPU的统计信息

常见的选项有:

  • c:显示CPU的使用情况。
  • d:显示磁盘的使用情况。
  • N:显示磁盘列阵(LVM)信息。
  • n:显示NFS使用情况。
  • k:以KB为单位显示。
  • m:以M为单位显示。
  • t:报告每秒向终端读取和写入的字符数和CPU的信息。
  • V:显示版本信息。
  • x:显示详细信息。
  • p:显示磁盘分区的情况。
[root@VM-20-2-centos udp]# iostat 
Linux 3.10.0-957.el7.x86_64 (fbc)  	_x86_64_	(1 CPU)
 
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.33    0.00    0.77    0.01    0.00   98.89
 
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
scd0              0.00         0.01         0.00       1050          0
sda               0.21         8.90         0.63     781839      55649
dm-0              0.21         8.53         0.61     749490      53564
dm-1              0.00         0.03         0.00       2460          0

[%user]:CPU处在用户模式下的时间百分比

[%nice]:CPU处在带NICE值的用户模式下的时间百分比

[%system]:CPU处在系统模式下的时间百分比

[%iowait]:CPU等待输入输出完成时间的百分比

[%steal]:管理程序维护另一个虚拟处理器时,虚拟CPU的无意识等待时间百分比

[%idle]:CPU空闲时间百分比

pidof

pidof命令可以通过进程名,查看进程id

例如:

我们编写一个死循环进程,通过pidof查看它的对应进程id,并使用kill命令杀死这个进程。

image-20240331175556066

[root@VM-20-2-centos udp]# ps -ajx | head -1 && ps -ajx | grep test
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28129  8411  8411 28129 pts/0     8411 S+       0   0:00 ./test
 6918  8679  8678  6918 pts/1     8678 S+       0   0:00 grep --color=auto test
[root@VM-20-2-centos udp]# pidof test
8411
[root@VM-20-2-centos udp]# kill -9 8411
//
[root@VM-20-2-centos udp]# ./test 
Killed
//
[root@VM-20-2-centos udp]# ps -ajx | head -1 && ps -ajx | grep test
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
 6918  8856  8855  6918 pts/1     8855 S+       0   0:00 grep --color=auto test

image-20240331175756327

UDP协议

UDP协议的位置

网络套接字编程时用到的各种接口,是位于应用层和传输层之间的一层系统调用接口,这些接口是系统提供的,我们可以通过这些接口搭建上层应用,比如HTTP。我们经常说HTTP是基于TCP的,实际就是因为HTTP在TCP套接字编程上搭建的。

而socket接口往下的传输层实际就是由操作系统管理的,因此UDP是属于内核当中的,是操作系统本身协议栈自带的,其代码不是由上层用户编写的,UDP的所有功能都是由操作系统完成,因此网络也是操作系统的一部分。

UDP报文格式

image-20240331180239019

  • 16位源端口号:数据从哪里来
  • 16位目的端口号:数据到哪去
  • 包长度(16位UDP长度):表示整个数据报(UDP首部+UDP数据)的长度
  • 校验和(16位UDP检验和):如果UDP报文的检验和出错,就会直接将报文丢弃
  • 数据部分:可以有数据也可以没有数据

我们在应用层看到的端口号大部分都是16位的,原因就是因为传输层协议当中的端口号就是16位的

如何把报头和有效载荷分离

UDP的报头当中只包含四个字段,每个字段的长度都是16位,总共8字节。

因此UDP采用的实际上是一种定长报头,UDP在读取报文时读取完前8个字节后剩下的就都是有效载荷了。

UDP如何决定将有效载荷交付给上层的哪一个协议

UDP上层也有很多应用层协议,因此UDP必须想办法将有效载荷交给对应的上层协议,也就是交给应用层对应的进程。

应用层的每一个网络进程都会绑定一个端口号,服务端进程必须显示绑定一个端口号,客户端进程则是由系统动态绑定的一个端口号。UDP就是通过报头当中的目的端口号来找到对应的应用层进程的。

注意:

内核中用哈希的方式维护了端口号与进程ID之间的映射关系,因此传输层可以通过端口号得到对应的进程ID,进而找到对应的应用层进程。

数据报头

传输层和网络层都是在linux内核中实现的,而linux内核是用C语言实现的,那UDP报头实际就是一个结构体,结构体成员变量实际就是UDP报头中的各个字段值,所以在分用时,只需要让指针指向数据包的前8个字节,然后将指针类型强转成结构体类型,然后读取里面成员变量的值,以此来实现分用。
在C语言中,即使是结构体数据,他其实也是二进制的字节流,如果想要将报头和有效载荷粘连在一块,我们可以开辟一大块char数组,然后将结构体数据按照字节流的方式拷贝到char数组中,然后紧接着再将有效载荷拷贝到里面,想要读取UDP报头进行分用时,可以直接将指针强转成结构体类型,然后进行成员选择,读取UDP报头的内容。

struct udp_header {
  	unsigned int src_port:16;// 源端口号
  	unsigned int dst_port:16;// 目的端口号  
  	unsigned int udp_len:16;// UDP长度  
  	unsigned int udp_chk:16;// 校验和  
};

UDP数据封装

  • 当应用层将数据交给传输层后,在传输层就会创建一个UDP报头类型的变量,然后填充报头当中的各个字段,此时就得到了一个UDP报头。
  • 此时操作系统再在内核当中开辟一块空间,将UDP报头和有效载荷拷贝到一起,此时就形成了UDP报文。

UDP数据分用

  • 当传输层从下层获取到一个报文后,就会读取该报文的钱8个字节,提取出对应的目的端口号。
  • 通过目的端口号找到对应的上层应用层进程,然后将剩下的有效载荷向上交付给对应的应用层进程。
UDP协议特点
  • 无连接:知道对端的IP和端口号就直接进行数据传输,不需要建立连接。
  • 不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。(也就是尽力而为)
  • 面向数据报:不能够灵活的控制读写数据的次数和数量。
UDP的缓冲区

UDP没有真正意义上的发送缓冲区。调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。
UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP数据报的顺序和发送UDP数据报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃。
UDP的socket既能读,也能写,因此UDP是全双工的。

为什么有UDP的接收缓冲区

如果UDP没有接收缓冲区,那么就要求上层及时将UDP获取到的报文读取上去,如果一个报文在UDP没有被读取,那么此时UDP从底层获取上来的报文数据就会被迫丢弃。

一个报文从一台主机传输到另一台主机,在传输过程中会消耗主机资源和网络资源。如果UDP收到一个报文后仅仅因为上次收到的报文没有被上层读取,而被迫丢弃一个可能并没有错误的报文,这就是在浪费主机资源和网络资源。

所以UDP本身是会维护一个接收缓冲区的,当有新的UDP报文到来时就会把这个报文放到接收缓冲区当中,当上层空闲时读数据的时候就直接从这个接收缓冲区当中进行读取就行了,而如果UDP接收缓冲区当中没有数据那上层在读取时就会被阻塞。

因此UDP的接收缓冲区的作用就是,将接收到的报文暂时的保存起来,供上层读取。

UDP使用注意事项
UDP协议报头当中的UDP最大长度是16位的,因此一个UDP报文的最大长度是64K(包含UDP报头的大小)。

然而64K在当今的互联网环境下,是一个非常小的数字。如果需要传输的数据超过64K,就需要在应用层进行手动分包,多次发送,并在接收端进行手动拼装。

基于UDP的应用层协议

  • NFS:网络文件系统。
  • TFTP:简单文件传输协议。
  • DHCP:动态主机配置协议。
  • BOOTP:启动协议(用于无盘设备启动)。
  • DNS:域名解析协议。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值