UDP的socket编程

socket接口

int socket(int domain, int type, int protocol);

参数说明​

参数说明
domain协议族(地址族),如 AF_INET(IPv4)、AF_INET6(IPv6)
type套接字类型,UDP 使用 SOCK_DGRAM(数据报)
protocol通常设为 0(自动选择),或 IPPROTO_UDP

socket() 的前两个参数 domain(地址族)和 type(套接字类型)已经分别指定了​​网络层协议​​(如 IPv4/IPv6)和​​传输层协议​​(如 TCP/UDP),第三个参数是历史原因被留了下来,现在一般设为0

底层原理

socket系统调用会创建struct file,struct socket,struct sock等结构体,最终返回该套接字的文件描述符

struct sock 

传输层和网络层的底层实现

struct sock {struct sk_buff_head  sk_receive_queue; // 传输层接收缓冲区struct sk_buff_head  sk_write_queue;   // 传输层发送缓冲区struct proto       *sk_prot;           // 纯粹的传输层协议的操作集union {struct inet_sock  inet;            // IPv4的底层结构体struct ipv6_sock  ipv6;            // IPv6的底层结构体};// ...(定时器、拥塞控制、状态等)
};


struct socket

对struct sock进行封装,主要是封装出了用户级的系统调用操作集

struct socket {struct sock     *sk;       const struct proto_ops *ops; //协议相关的系统调用​​(如 bind、connect、sendmsg)struct file     *file;     
};

操作集辨析

 1.file_operations(struct file)​

​​文件的通用操作接口​​(如 readwritepoll

2.proto_ops(struct socket)

实现协议相关的系统调用​​(如 bindconnectsendmsg

3. struct proto(struct sock)

传输层协议的底层操作集

recvfrom 函数声明​

ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen
);

参数详解​

​参数​​类型​​说明​
sockfdint接受数据的套接字文件描述符(由 socket() 创建)。
bufvoid *接收数据的缓冲区地址,用于存储接收到的数据。
lensize_t缓冲区的最大长度(字节数),防止缓冲区溢出。
flagsint控制接收行为的标志位(如 MSG_DONTWAITMSG_PEEK),通常设为 0
src_addrstruct sockaddr *接收发送方套接字地址结构体​​的缓冲区
addrlensocklen_t *传入缓冲区的大小,返回套接字地址结构体大小。

返回值​

​返回值​​说明​
> 0成功接收到的字节数。
0​仅对 TCP 有效​​,表示连接已关闭(UDP 不会返回 0)。
-1 (失败)出错,可通过 errno 获取错误码(如 EAGAIN 表示非阻塞模式下无数据)。

sendto函数

ssize_t sendto(int sockfd,                  // 套接字文件描述符const void *buf,            // 待发送数据的缓冲区size_t len,                 // 数据长度(字节数)int flags,                  // 发送方式控制标志(通常设为 0)const struct sockaddr *dest_addr,  // 目标地址结构体socklen_t addrlen           // 目标地址结构体长度
);

​参数解释​

​参数​​类型​​说明​
sockfdint套接字文件描述符(由 socket() 创建)。
bufconst void *待发送数据的缓冲区地址。
lensize_t数据的长度(字节数)。
flagsint控制发送行为的标志位(如 MSG_DONTWAITMSG_MORE),通常设为 0
dest_addrconst struct sockaddr *​目标地址结构体​​(如 struct sockaddr_in)。
addrlensocklen_tdest_addr 结构体的实际长度(如 sizeof(struct sockaddr_in))。

 返回值​

​返回值​​说明​
> 0成功发送的字节数。
-1 (失败)出错,可通过 errno 获取错误码(如 EAGAIN 表示非阻塞模式下无法立即发送)。

udp服务器逻辑

1.利用socket函数创建套接字,传参地址族和套接字类型,第三个参数是历史遗留不用管,比如socket(AF_INET, SOCK_DGRAM, 0),说明套接字网络层是ipv4,传输层是tcp,其底层就是创建struct file还有对应的struct socket和struct sock,然后返回套接字描述符

2.接下来要将套接字绑定端口,创建ipv4对应的套接字地址结构体struct sockaddr_in,然后填写地址族AF_INET,再填写端口号和ip地址,一般端口号是靠命令行参数来给出,IP地址则是INADDR_ANY,该套接字绑定的ip是任意的,也就是通过任何一个网卡接收都可以。

3.然后服务器死循环调用recvfrom,recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);,没有数据则在套接字接收缓冲区等待队列上阻塞等待

udp客户端逻辑

1.命令行参数指明服务器端主机的任意一个网卡的ip地址,然后再指明端口,创建套接字socket(AF_INET, SOCK_DGRAM, 0);

2.用命令行参数准备好服务器通信套接字的地址结构体struct sockaddr_in,然后sendto发消息

udp发送消息过程分析

udp是没有发送缓冲区的,只有接收缓冲区,客户端调用sendto,会自动给套接字绑定端口,然后直接开始封装udp报文,然后交给IP层(其实就是调用ip协议的接口),传的参数就是udp报文和目标ip地址,ip层查路由表确定下一跳ip和发送网卡接口,封装IP报头,交给数据链路层处理(本质是调用以太网协议接口),传参IP报文和下一跳ip和发送网卡接口,网卡驱动会先查arp缓存,得到下一跳ip的mac地址,然后给报文加上mac头和crc校验,写进发送网卡对应的发送缓冲区,写网卡的TDT寄存器通知,然后网卡会DMA将数据读出,HVY转换信号,接口发送出去,咱们假设客户端是内网的一个主机,服务器部署在外网主机上,那这个下一跳很明显是路由器,路由器的网卡接口收到信号后,HVY信号转换,DMA写进网卡的接收缓冲区,触发硬件中断,cpu陷入内核,执行中断向量表中的中断方法,网卡驱动将数据读出,检查mac地址,然后看帧类型是IP帧,于是进行crc校验,没有问题就去掉mac头和crc校验,交给ip层,然后IP头的TTL减一,更改源ip为路由器的WAN口ip,并根据ip头中的首部长度,总长度,上层协议类型这些字段将udp头中的源port也改了(路由器除了维护路由表,还会维护地址转换表来辅助NAT,地址转换表里的对应关系是{源ip,源port,目的ip,目的port}和{改过的源ip,改过的源port,目的ip,目的端口}),改完后去查路由表确定下一跳ip和发送网卡,然后和之前一样发出去,这次发到公网了,服务器收到后不断解包到传输层(此时的底层应该是调用了udp协议的接口,将udp报文传过去),然后udp层会根据udp头里的端口拼出三元组{协议,目的ip,目的端口},然后根据OS维护的hash表找到对应udp套接字,将udp报文整个写进该套接字的接收缓冲区,然后唤醒接收缓冲区等待队列上的进程,recvfrom系统调用从接收缓冲区中读出一个完整的udp报文,然后去掉报头,将有效载荷写进recvfrom函数参数传来的的应用层缓冲区里,并填充参数传来的套接字地址和其大小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90417.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SD-WAN的管件制造数字化产线系统集成方案

1. 背景与目标随着制造业向智能化、数字化方向转型,传统产线面临着数据割裂、协同效率低下等问题。管件制造作为典型场景,涉及多环节的设计、制造与质检流程,亟需一套高效的系统集成方案,保障全流程数据贯通与实时协同。本方案基于…

学习open62541 --- [79] 在docker中运行open62541工程

docker是非常流行的容器技术,解决了部署环境不一致的问题,open62541的工程也可以在docker容器中运行,本文讲述如何把open62541工程放到docker容器中运行。 本文使用WSL ubuntu 22.04作为宿主环境,其它linux也是一样。一 拉取debia…

Spring Boot微服务中集成gRPC实践经验分享

Spring Boot微服务中集成gRPC实践经验分享 一、业务场景描述 在某电商系统中,推荐服务、库存服务、订单服务等微服务需要高效、双向流式通信,RESTHTTP已无法满足低延迟、高并发和严格类型安全的需求。为此,我们选择在Spring Boot微服务中集成…

springboot项目编写测试类,乱码问题解决

​MockMvc 的默认行为​ MockMvc ​默认使用 ISO-8859-1 解码响应,而服务端实际返回 UTF-8 编码数据 。 Postman 无乱码是因浏览器自动识别编码,但 MockMvc 需显式配置。 ​过滤器失效场景​ Spring 的 CharacterEncodingFilter ​默认只对 POST 请求生效…

打破传统,开启 AR 智慧课堂​

在教育领域,AR 智慧课堂宛如一场及时雨,为传统教育模式带来了革命性的变革,让学习变得更加生动有趣、高效互动。通过 AR 技术,抽象的知识瞬间变得鲜活起来,学生们可以在虚拟与现实交织的世界中,探索历史的长…

热烈祝贺 Flink 2.0 存算分离入选 VLDB 2025

VLDB 2025 论文热烈祝贺 Apache Flink 2.0 的重磅研究成果《Disaggregated State Management in Apache Flink 2.0 》被数据库领域顶级会议 VLDB 2025 正式接收!这项工作由 Apache Flink 社区 联合 阿里巴巴实时计算 Flink 团队 以及多位学术界研究人员共同完成&…

蓄电池能量管理matlab的simulink仿真

蓄电池能量管理matlab的simulink仿真模型 AlternatorTableData.mat , 7395 Battery_Management_Lib.mdl , 577258 Readme.txt , 1293 license.txt , 1551 ssc_battery_management.mdl , 221248 ssc_lead_acid_battery_50Ah_ini.m , 1760 ssc_lead_acid_battery_80Ah_ini.m , 1…

MyBatisPlus-03-扩展功能

文章目录【README】【1】基于MyBatisPlus的代码生成器【2】MyBatisPlus-DB静态工具【2.1】使用MyBatisPlus的DB静态工具查询单个及多个用户地址【查询单个用户的访问效果】【查询多个用户的访问效果】【3】逻辑删除【3.1】代码实现【4】枚举处理器【4.1】代码实现【5】JSON处理…

初识Neo4j之Cypher(三)

目录 一、介绍 二、语法 1、节点 2、关系 3、属性 4、模式 一、介绍 Cypher 是 Neo4j 的声明式查询语言,兼容 GQL 标准。通过 openCypher 项目,Cypher 以开源方式提供。它类似于 SQL,但专为图数据优化。 Cypher 直观且接近自然语言&…

19-C#静态方法与静态类

C#静态方法与静态类 1.static-静态方法animal.eat();//直接调用 public class animal {public static void eat()//定义静态方法{messagebox.show("animal eat");} }2.static-静态类animal.eat();//直接调用public stat…

基于YOLO的足球检测Web应用:从训练到部署的完整实战

用Python和深度学习技术打造一个完整的足球检测系统,支持图片检测、视频分析和实时监控。本文带你从零开始构建一个专业的Web应用。🎯 项目背景 在体育赛事分析和足球训练中,准确识别和定位足球是一个重要需求。本项目利用YOLO深度学习算法&a…

npm 切换 node 版本 和npm的源

在开发过程中,不同项目可能需要不同版本的 Node.js,同时 于由XX原因,我们需要切换npm的源。这时如果需要切换node版本或者npm的源,我们可以使用以下方法。 使用 nvm 切换 Node 版本 1、安装 npm install nvm -g2、使用 # 列出所有…

Java学习第二十部分——EasyMock

目录 一.概述 二.作用 三.工作原理 四.使用示例 五.主要特点 六.适用场景 七.其他模拟框架比较 八.idea简单项目实战 1.打开idea创建Java项目,注意构建系统选“Maven” 2.为pom.xml文件添加如下依赖,并重新加载Maven依赖,直至不报错…

机器学习模型在C++平台的部署

一、概述机器学习模型的训练通常在Python环境下完成,而现实生产环境的复杂性和多样性使得模型的部署成为一个值得关注的重点。不同应用场景下有不同适应的实现方式,这里主要介绍通过一种通用中间格式——ONNX(Open Neural Network Exchange&a…

保姆级安装 Ruby 环境下载及安装教程, RubyInstaller下载及安装教程

一、下载安装 RubyInstaller 1.打开 RubyInstaller 官网:https://rubyinstaller.org/ 点击跳转, 官网界面如下图: 点击下载最新的 RubyDevkit 版本(如 RubyDevkit 3.4.X (x64) )。如下图所示: 注意点:如果…

SQL 一键生成 Go Struct!支持字段注释、类型映射、结构体命名规范

SQL 一键生成 Go Struct!支持字段注释、类型映射、结构体命名规范 在 Golang 开发中,尤其是操作数据库时,我们经常会遇到这种场景: ✅ 拿到数据库建表 SQL,却要手动写 Go struct✅ 字段几十个、类型复杂,…

Web 前端框架选型:React、Vue 和 Angular 的对比与实践

Web 前端框架选型:React、Vue 和 Angular 的对比与实践 选择前端框架就像选择一个长期合作伙伴。错误的选择可能会让你的项目在未来几年内背负沉重的技术债务,而正确的选择则能让开发效率飞速提升。 经过多年的项目实践,我发现很多新人在框架…

C# 值拷贝、引用拷贝、浅拷贝、深拷贝

值拷贝定义:直接复制变量的值,适用于基本数据类型(如int, float, char等)。在 C# 中,值类型(基本数据类型和结构体)默认使用值拷贝。特点:创建原始值的完全独立副本,修改…

深度学习图像分类数据集—百种鸟类识别分类

该数据集为图像分类数据集,适用于ResNet、VGG等卷积神经网络,SENet、CBAM等注意力机制相关算法,Vision Transformer等Transformer相关算法。 数据集信息介绍:525种鸟类识别分类 训练数据集总共有84635张图片,每个文件夹…

零基础 “入坑” Java--- 八、类和对象(一)

文章目录一、初识面向对象二、类的定义和使用1.认识类2.类的定义格式三、类的实例化四、this引用五、对象的构造及初始化1.有关初始化2.构造方法3.就地初始化一、初识面向对象 Java是一门纯面向对象的语言(OOP),在面向对象的世界里&#xff…