当前位置: 首页 > news >正文

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.dtcms.com/a/269546.html

相关文章:

  • unity 模型UV重叠问题相关(重新整理)
  • BUUCTF在线评测-练习场-WebCTF习题[GXYCTF2019]BabySQli1-flag获取、解析
  • 无法访问宝塔面板 - 特网科技
  • Coze智能体平台全景解析:从零构建企业级AI应用的实战指南
  • Spring Boot 企业项目技术选型
  • UI前端大数据可视化实战策略:如何设计符合用户认知的数据展示方式?
  • 京东携手HarmonyOS SDK首发家电AR高精摆放功能
  • 开发在线商店:基于Vue2+ElementUI的电商平台前端实践
  • 二刷(李宏毅深度学习,醍醐灌顶,长刷长爽)
  • AI技术通过提示词工程(Prompt Engineering)正在深度重塑职场生态和行业格局,这种变革不仅体现在效率提升,更在重构人机协作模式。
  • 车载网络安全是当代车辆功能很重要的组成部分
  • 语言模型 RLHF 实践指南(一):策略网络、价值网络与 PPO 损失函数
  • 【OceanBase 诊断调优】—— SQL 查询触发笛卡尔积怎么处理
  • Rust BSS段原理与实践解析
  • 自动驾驶感知系统
  • OpenWebUI(4)源码学习-后端routers路由模块
  • Halcon 入门教程:卡尺工具(Measure)详解与实战应用
  • 采煤机:技术革新驱动下的全球市场格局与未来趋势
  • 无缝矩阵的音频合成与音频分离功能详解
  • 大数据在UI前端的应用深化:用户偏好的动态调整与个性化推荐
  • Next.js ISR 缓存机制与最佳实践教程
  • 论文略读; AdapterFusion:Non-Destructive Task Composition for Transfer Learning
  • Android中MVI架构详解
  • 875、爱吃香蕉的珂珂
  • 吃透二分法的模板解法(适合所有类似于二分的算法题)
  • 百度斩获大模型中标第一,股价上涨5%
  • 深度剖析:Ceph分布式存储系统架构
  • 实时开发IDE部署指南
  • Tomcat与IIS:核心差异及接口调用实战解析
  • paddlehub环境搭建和测试