Linux网络:UDP

文章目录

  • [1. 传输层](#1. 传输层)
  • [2. 端口](#2. 端口)
  • [3. UDP](#3. UDP)
    • [3.1 UDP报文](#3.1 UDP报文)
    • [3.2 UDP特点](#3.2 UDP特点)
    • [3.3 UDP应用场景](#3.3 UDP应用场景)
    • [3.4 Linux UDP接口](#3.4 Linux UDP接口)

1. 传输层

tcp/ip协议栈中,应用层之下是传输层。

传输层中的很多行为都是内核帮我们完成,但是用户程序中也要调用一些接口进行设置。

传输层的协议有两个:UDP和TCP

本篇博客中介绍UDP.

2. 端口

端口本质上是一个unsigned short类型的无符号短整数,范围是0~65535

在tcp/ip协议中,端口号作为源IP,源端口,目的IP,目的端口,协议号中的重要组成部分,共同标识一个通信。

IP用于定位具体的机器,而端口用于定位到这台机器上的具体进程。

关于进程和端口的关系,一般来说,一个进程可以绑定多个端口,但是一个端口只能被一个进程绑定,对于后者,在没有对socket进行额外设置时,是正确的,但如果设置了某些属性,情况会有所不同。

自己的程序有些端口号是不能绑定的,通常内核也不会允许我们绑定,这些端口号是知名端口号,对应了一些知名应用层协议------即使用这些协议访问服务器时,访问的服务器端口号已经确定了。

3. UDP

3.1 UDP报文

上图是UDP的报文结构。

其中,源端口号和目的端口号,这些不必多说。

16位UDP长度表示整个UDP报文的长度,可见,UDP报文的最大长度是65535字节,这个长度包括报头(报头总共8字节)和有效载荷,如果超过这个长度,那么对于有效载荷,就需要在应用层手动分包。

16位UDP检验和,这个数据可用于验证该UDP报文在网络传输的过程中,内容是否发生更改。

检验和有其自身计算逻辑,发送端在发送时计算一次,接收端在接收时计算一次,二者进行比对,即可确认内容是否改变。

3.2 UDP特点

UDP网络通信有三个最大特点:无连接,不可靠,面向数据报。

什么是无连接呢?

相对于TCP,UDP网络通信,通信双方完全没有建立连接的机制,即便UDP使用connect,本质上无连接,只不过将对端IP和端口记录到内核中,后续通信接口由使用sendto/recvfrom,改为使用send/recv罢了。

什么是不可靠呢?

UDP网络通信没有确认应答机制,即接收端是否正常受到UDP报文,发送端是无法得知的。

UDP网络通信没有超时重传机制,用户层写入的发送数据,封装为UDP报文后,永远只会发送一次。

同时,UDP通信中,由于实际网络问题,先发送的UDP报文,可能后到达,而UDP内核中并不会维护这个顺序,谁先到就都谁,而实际上这个信息可能是后发的,并不是最先应该读取的信息。
而由于UDP是无连接,不维护连接状态,所以即便通信的一方彻底关闭,另一方也不会有任何感知,读写行为仍照旧,只不过此时通信已没有任何意义。

什么是面向数据报呢?

面向数据报是指UDP报文有明确的数据边界。TCP报文是字节流传输的,一次写入的数据可能被分批发送,也可能和一些其它数据一起发送,读取时,可能一次性无法读到完整数据,需要多次读取。 但UDP不一样,UDP报文发送,要么完整,要么不发送 ;UDP报文读取,要么不读,读就读到完整的UDP报文

因此,UDP报文明确的数据边界,使得UDP网络通信时,不需要在用户层处理粘包问题

3.3 UDP应用场景

性质决定用途,UDP无连接,不可靠,面向数据报的性质,使得UDP的应用场景如何呢?

UDP不用维护连接,网络通信不可靠,即不需要维护超时重传,确认应答等各种复杂机制,这就使得UDP在不考虑通信质量的情况下,通信效率是非常高的。

因此,对于那些对通信效率要求高,即实时性要求高,而允许一定程度的通信数据丢失场景下,UDP应用非常多,比如实时视频通话,或者网络直播等等。

除了上述场景外,在简单的网络通信场景中,比如DNS域名解析场景,总共就一问一答,非常简单,使用UDP即可,不必使用TCP,否则反倒因为TCP复杂机制,带来不必要的额外消耗。

3.4 Linux UDP接口

网络通信接口使用分为客户端和服务端。

客户端:

  1. 使用socket创建用于通信的网络套接字,返回相应文件描述符。

    int fd = socket(AF_INET,SOCK_DGRAM,0);//指定协议号为0,让内核自动判别即可

  2. 客户端一般不显式绑定,而是在sendto发送数据时,由内核完成绑定。

  3. 使用sendto进行数据发送。

    size_t n = sendto(fd,buffer,len,0,(struct sockaddr*)dest_addr,addrlen);//一般flag标志位给0即可,取默认情况

  4. 使用recvfrom进行数据接收。

    size_t n = recvfrom(fd,buffer,len,0,(struct sockaddr*)src_addr,&addrlen);//注意这里的addrlen是取地址,因为要实际拿到写入src_addr的字节数

服务端:

  1. 使用socket创建网络套接字进行通信,与客户端相同。

  2. 服务端必须使用bind显式绑定。

    int ret = bind(sockfd,addr,addrlen)

那么在第二个参数,即类型为struct sockaddr这个结构体中,我们需要手动填入什么呢?
在网络通信中,实际使用的是struct sockaddr_in这个类型,传参时需要做类型转化。

在这个结构体中,我们需要初始化三个变量:sin_family初始化为AF_INET,表示是网络通信,使用IpV4;sin_addr对应的是ip地址,需要使用相关接口进行主机字节序到网络大端字节序的转换sin_port对应的是具体端口,与ip地址相同,需用相关接口完成字节序的转换。

  1. 服务端使用recvfrom接收数据,接口和参数均同上。
  2. 服务端使用sendto发送数据,接口和参数也同上。
    服务端使用sendto发送数据时,可能会有疑惑:服务端如何知道客户端的IP+PORT呢?这本质上是逻辑顺序的问题。因为,客户端和服务端之间的通信,通常都是客户端已知服务端IP+PORT,然后客户端先给服务端发信息,此时服务端通过recvfrom的相关参数,即可得到客户端地址,然后再向此地址客户端发送消息,而客户端虽然未主动bind,但在sendto中,已经由内核自动bind,因此也能正常接收服务端消息。自此,双端通信的逻辑就是完善的。
相关推荐
KingRumn6 小时前
Linux信号之标准信号与实时信号
linux·算法
Ha_To8 小时前
2025.12.22 OSPF多区域原理与配置方法
网络
QT 小鲜肉8 小时前
【Linux命令大全】001.文件管理之git命令(实操篇)
linux·服务器·笔记·git·elasticsearch
sishen41999 小时前
嵌入式Linux没有学习方向怎么办,嵌入式Linux怎么学
linux
逆风水手9 小时前
Ansible自动化运维入门指南
linux·运维·自动化·ansible
Smile_25422041810 小时前
vlc的使用
网络·webrtc·实时音视频
旖旎夜光10 小时前
Linux(3)(下)
linux·学习
小鹿学程序10 小时前
任务一-1.子任务一:基础环境准备
linux·bigdata
清水白石00810 小时前
《requests vs httpx:Python 网络请求库的全面对比与实战指南》
网络·python·httpx
Nautiluss11 小时前
一起玩XVF3800麦克风阵列(十)
linux·人工智能·python·音频·语音识别·实时音视频·dsp开发