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,因此也能正常接收服务端消息。自此,双端通信的逻辑就是完善的。
相关推荐
weixiao04304 小时前
Linux网络 网络层
linux·网络·智能路由器
静若繁花_jingjing4 小时前
面试_项目问题_RPC调用异常
网络·网络协议·rpc
从零开始的ops生活4 小时前
【Day 80】Linux-NAS 和 SAN 存储
linux·运维·php
せいしゅん青春之我5 小时前
[JavaEE初阶] 防止网络传输中的中间人入侵---证书
服务器·网络·网络协议·java-ee
Wang's Blog5 小时前
Linux小课堂: 输入重定向与管道操作详解
linux·运维·服务器
RTC老炮6 小时前
webrtc弱网-ReceiveSideCongestionController类源码分析及算法原理
网络·算法·webrtc
迎風吹頭髮6 小时前
Linux内核架构浅谈49-Linux per-CPU页面缓存:热页与冷页的管理与调度优化
linux·缓存·架构
jason.zeng@15022076 小时前
centos中安装redis
linux·redis·centos
w23617346017 小时前
Linux 服务器安全巡检与加固:从命令到实操(CentOS/Ubuntu 通用)
linux·服务器·安全·安全加固·安全巡检