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,因此也能正常接收服务端消息。自此,双端通信的逻辑就是完善的。
相关推荐
Fnetlink12 小时前
Fnet 云网安 260904
网络·人工智能·安全·web安全·网络安全
tangwangbi2 小时前
Linux 系统配置文件:/etc/profile、~/.bashrc 和 ~/.bash_profile 三者之间的区别与作用
linux·运维·bash
天远数科2 小时前
风险治理实战:基于天远车信盟出险构建自动化理赔核保流水线
java·网络·人工智能·自动化
蜀道山老天师2 小时前
Shell Bash变量与运算符(含条件测试与流程控制)
linux·运维·bash
Mr.朱鹏2 小时前
Linux 服务器 LVM 根分区在线动态扩容
linux·服务器·数据库
mengge.cloud3 小时前
存储技术基础小白教程
linux·运维·服务器·wpf·存储
志栋智能3 小时前
安全超自动化如何支持大规模安全运营?
网络·安全·自动化
星恒讯工业路由器3 小时前
农村宽带覆盖难?无线专网方案正在改写“最后一公里”规则
网络·物联网·网桥·无线网桥·农村宽带覆盖·无线专网·户外网络
tang777894 小时前
反爬虫场景下代理IP池的动态扩容与失效IP自动清理方案实现
linux·服务器·网络·爬虫代理·住宅代理ip
yuewell_ai4 小时前
机器人调度通讯怎么设计才不会被网络抖动瘫痪
网络·机器人·php