UDP通信实现
目录
前言
一、基础知识
1、跨主机传输
1、字节序
2、主机字节序和网络字节序
3、IP转换
2、套接字
3、什么是UDP通信
二、如何实现UDP通信
1、socket():创建套接字
2、bind():绑定套接字
3、sendto():发送指定套接字文件数据
4、recvfrom():接收指定地址信息的数据
三、具体实现代码
前言
在前面我们知道,在使用UDP通信是在传输层选择使用UDP协议,并且在传输层只有两个协议,分别是UDP和TCP协议,在本节中,我们就来学习如何实现UDP通信
一、基础知识
1、跨主机传输
1、字节序
字节序:不同类型的CPU主机,内存存储多字节数据时的存在不同序列存储方式
a、小端字节序(小端存储):低序字节存储在内存低地址上,高序字节存储在内存高地址上
b、大端字节序(大端存储):低序字节存储在内存高地址上,高序字节存储在内存低地址上
short、int、long 有字节序的概念
char、float、字符串没有字节序的说法
如何查看电脑是大端存储还是小端存储
//查看电脑大端存储还是小端存储 #include<stdio.h> int main(int argc, const char *argv[]) {int a=0x87654321;char *p=&a;printf("a=%#x\n",*p);return 0; }
我的电脑输出的是a=0x21,说明是小段存储,其实大多数电脑都是小端存储
2、主机字节序和网络字节序
- 主机字节序:主机本身在计算机中存储多字节数据的方式(大端、小端:CPU)现目前电脑一般都是小端
- 网络字节序:数据在网络中规定的传输方式,网络字节序使用大端字节序方式传输
所以在跨主机传输过程中,需要使用统一的字节序,即网络字节序,避免兼容性问题
主机字节序转换为网络字节序,便于传输:
#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong); 功能:把 hostlong 主机字节序整型转换为网络字节序,返回值就是网络字节序整数uint16_t htons(uint16_t hostshort); 功能:把 hostshort 主机字节序短整型转换为网络字节序,返回值就是网络字节序短整数
网络字节序转换为主机字节序,便于解析识别:
#include <arpa/inet.h>uint32_t ntohl(uint32_t netlong); 功能:把 netshort 网络字节序 整型 转换为主机存储的主机字节序,返回值就是 主机字节序整数uint16_t ntohs(uint16_t netshort); 功能:把 netshort 网络字节序短整型 转换为主机存储的主机字节序,返回值就是 主机字节序
3、IP转换
在主句传输数据时会对大于两个字节的数据进行网络字节序的转换,那么IP地址通常是大于两个字节的,也同样要进行IP转换
IP地址整数转换为二进制网络字节序的IP地址 :
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>in_addr_t inet_addr(const char *cp); 功能:将 ip地址字符串 转换为 IP地址整数(网络字节序IP地址)参数:const char *cp:要转换的 IP地址的点分十进制字符串首地址返回值: 成功,返回 转换后的 网络字节序的IP地址 typedef uint32_t in_addr_t;
IP地址的二进制网络字节序转换为IP地址的整数:
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>char *inet_ntoa(struct in_addr in); 功能:把 IP地址转换为 点分十进制字符串格式参数:struct in_addr in:指定要转换的IP地址 的结构体类型,结构体中的成员为 IP地址类型:typedef uint32_t in_addr_t;struct in_addr {in_addr_t s_addr;//IP地址 网络字节序 整数};
2、套接字
最早套接字和共享内存、消息队列、管道一样,只能实现一个主机内部的进程间通信,随着TCP/IP网络模型的引入,使得套接字能够支持不同主机之间的进程间通信,socket函数,创建一个套接字文件,可以在内核空间中创建两块缓冲区,用于发送数据,接收数据。也包含对应的TCP/IP协议规则
使用socket()函数创建套接字文件
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h>int socket(int domain, int type, int protocol); 功能:创建socket套接字,用于网络通信参数: 参数1:int domain:地址族,协议族AF_UNIX, AF_LOCAL Local communication unix(7)AF_INET IPv4 Internet protocols ip(7)AF_INET6 IPv6 Internet protocols ipv6(7) 参数2:int type:类型SOCK_STREAM:字节流套接字,流式套接字,默认使用TCP协议SOCK_DGRAM:数据报套接字,报式套接字,默认使用UDP协议SOCK_RAW:原始套接字,其协议需要在第三个参数中指定 参数3:int protocol:协议0:使用默认协议IPPROTO_TCPIPPROTO_UDP返回值: 成功,返回 套接字文件描述符(套接字) 失败,返回-1,设置errno
3、什么是UDP通信
根据传输层的协议不同,通信的实现、通信的方式也各不相同,是不同的方式完成通信
传输层:TCP、UDP
通信方式有两种:UDP通信 与 TCP通信
UDP通信的步骤:
二、如何实现UDP通信
1、socket():创建套接字
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h>int socket(int domain, int type, int protocol); 功能:创建socket套接字,用于网络通信,在内核空间中创建套接字文件(有两个缓冲区:发送缓冲区、接收缓冲区),返回该套接字文件缓冲区的文件描述符参数: 参数1:int domain:地址族,协议族AF_UNIX, AF_LOCAL Local communication unix(7)AF_INET IPv4 Internet protocols ip(7)AF_INET6 IPv6 Internet protocols ipv6(7) 参数2:int type:类型SOCK_STREAM:字节流套接字,流式套接字,默认使用TCP协议SOCK_DGRAM:数据报套接字,报式套接字,默认使用UDP协议SOCK_RAW:原始套接字,其协议需要在第三个参数中指定 参数3:int protocol:协议0:使用默认协议IPPROTO_TCPIPPROTO_UDP返回值: 成功,返回 套接字文件描述符(套接字) 失败,返回-1,设置errno
2、bind():绑定套接字
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);功能:绑定地址信息到指定的套接字文件描述符上,为套接字通信指定使用的IP、port参数: 参数1:int sockfd:指定要将地址信息绑定到哪个套接字上,套接字文件描述符 参数2:const struct sockaddr *addr:地址信息结构体的指针,通用的一个地址结构体,由于存在不同的地址族选择,所以地址的表示方式不一样,为了统一表示,所以参数为通用的地址信息结构体类型用来表示有一个地址信息结构体:通用结构体struct sockaddr {sa_family_t sa_family;char sa_data[14];}真实的地址信息结构体需要根据地址族来指定不同的地址族有不同的地址信息结构体AF_INET地址族的地址信息结构体:struct sockaddr_in {sa_family_t sin_family;//指定地址族,AF_INETin_port_t sin_port;//端口号的网络字节序,2个字节struct in_addr sin_addr;//使用的ip地址的网络字节序(结构体类型)};struct in_addr {//ip地址的网络字节序结构体uint32_t s_addr;//ip地址网络字节序}; 参数3: socklen_t addrlen:真实的地址信息结构体大小返回值: 成功,返回0 失败,返回-1,设置errno
3、sendto():发送指定套接字文件数据
#include <sys/types.h> #include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 功能:发送数据给指定的接收方,即当前进程套接字发送数据给指定的ip、port进程参数: 参数1:int sockfd:套接字,通信:使用指定的套接字描述符来发送数据(数据传入哪个套接字的缓冲区用于发送) 参数2:const void *buf:指定要发送的数据的首地址(把指定地址的数据进行发送) 参数3:size_t len:发送多少个字节 参数4:int flags:选项0:阻塞方式发送,当缓冲区满,阻塞等待,不继续执行MSG_DONTWAIT:非阻塞方式发送,当缓冲区满,不等待,返回错误失败 参数5:const struct sockaddr *dest_addr:地址信息结构体,指定将数据发送给谁(ip、port),填写对方的地址信息地址信息根据地址族不同,结构体信息内容不同如果:AF_INETAF_INET地址族的地址信息结构体:struct sockaddr_in {sa_family_t sin_family;//指定地址族,AF_INETin_port_t sin_port;//端口号的网络字节序,2个字节struct in_addr sin_addr;//使用的ip地址的网络字节序(结构体类型)};struct in_addr {//ip地址的网络字节序结构体uint32_t s_addr;//ip地址网络字节序}; 参数6: socklen_t addrlen:真实的地址信息结构体的大小返回值: 成功,返回发送的字节数 失败,返回-1,设置errno
4、recvfrom():接收指定地址信息的数据
#include <sys/types.h> #include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen); 功能:接收数据包,同时可以接收到数据包从哪里来(额可以获取发送方的地址信息)参数: 参数1:int sockfd:通信使用的套接字文件描述符,指定获取哪个套接字的数据(对方发送发送到ip、port的套接字缓冲区) 参数2:void *buf:存储读取到的数据,接收的数据存储的地址 参数3:size_t len:要读取多少个字节 参数4:int flags:选项 0:阻塞方式接收,当缓冲区为空,没有接收到数据时,阻塞等待,不继续执行MSG_DONTWAIT:非阻塞方式接收,当缓冲区为空(没有数据),不等待,返回错误失败 参数5:struct sockaddr *src_addr:地址信息结构体,不同的地址族地址信息结构体不同,不同的地址族使用对应的结构体来存储,发送方的地址信息如果不想知道发送方的地址信息,则填NULL 参数6:socklen_t *addrlen:地址信息结构体的大小,指针对应空间存储如果不想获取,则填NULL返回值: 成功,返回收到的字节数 失败,返回-1,设置错误码
三、具体实现代码
在实现通信之前,我们使用下面网络调试助手来进行通信传输
通过网盘分享的文件:scomm.exe
链接: https://pan.baidu.com/s/1OkiZLT_CeoryEZepaOSGqQ 提取码: 8a85
首先,更改下面的代码
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <string.h> #include <pthread.h>#define PORT 20000 #define DEST_PORT 10000 #define DEST_IP "192.168.124.29" #define BUF_SIZE 128int sockfd; struct sockaddr_in destaddr;void *send_thread(void *arg) {char buf[BUF_SIZE];while (1) {bzero(buf, BUF_SIZE);fgets(buf, BUF_SIZE, stdin);sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&destaddr, sizeof(struct sockaddr_in));}return NULL; }void *recv_thread(void *arg) {char buf[BUF_SIZE];while (1) {struct sockaddr_in rcv_addr;socklen_t rcv_addr_len = sizeof(rcv_addr);int size = recvfrom(sockfd, buf, BUF_SIZE - 1, 0, (struct sockaddr*)&rcv_addr, &rcv_addr_len);if (size > 0) {buf[size] = '\0';printf("Received: %s\n", buf);}}return NULL; }int main(int argc, const char *argv[]) {// 创建套接字,使用UDP通信sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("socket creation failed");return -1;}// 绑定套接字struct sockaddr_in udpaddr;udpaddr.sin_family = AF_INET;udpaddr.sin_port = htons(PORT);udpaddr.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd, (struct sockaddr*)&udpaddr, sizeof(struct sockaddr_in)) < 0) {perror("bind failed");close(sockfd);return -1;}// 设置对方的信息destaddr.sin_family = AF_INET;destaddr.sin_port = htons(DEST_PORT);destaddr.sin_addr.s_addr = inet_addr(DEST_IP);// 创建发送和接收线程pthread_t send_tid, recv_tid;pthread_create(&send_tid, NULL, send_thread, NULL);pthread_create(&recv_tid, NULL, recv_thread, NULL);// 等待线程完成pthread_join(send_tid, NULL);pthread_join(recv_tid, NULL);// 关闭套接字close(sockfd);return 0; }
但是代码中的IP地址要更改
更改步骤:
1、将下面的DEST_IP改为打开网络调试助手的IP地址,
如何查找打开的网络调试助手的代码和端口
在这里查看网络端口和接收端的IP地址,每个人的不一样,因此要读者自己去设置
相关文章:

UDP通信实现
目录 前言 一、基础知识 1、跨主机传输 1、字节序 2、主机字节序和网络字节序 3、IP转换 2、套接字 3、什么是UDP通信 二、如何实现UDP通信 1、socket():创建套接字 2、bind():绑定套接字 3、sendto():发送指定套接字文件数据 4、recvfrom():接收指定地址信息的数据 三…...

windows下使用vscode编写运行以及调试C/C++
vscode支持类似于vs的断点调试c/c,也可以直接编译&运行c/c 先是编译运行 c/c的方法 微软官方起初设定的科学做法(这也是现在的科学做法)是通过在vscode集成控制台写命令行的方式来实现编译运行程序的,但也可以通过code runner插件…...
python容器4--集合
(1) 什么是集合 集合:Python中使用关键字set表示 集合中存储多个、没有顺序的、不能重复的、可以是不同类型的多个数据! (2) 集合的声明 python中通过set()或者花括号声明空集合、非空集合 # 声明空集…...

MySQL record 01 part
更改密码: alter user rootlocalhost identified with mysql_native_password by ‘123456’; 注意: 在命令行方式下,每条MySQL的命令都是以分号结尾的,如果不加分号,MySQL会继续等待用户输入命令,直到MyS…...
2024年高教社杯全国大学生数学建模竞赛A题思路(2024数学建模国赛A题思路)
A题 “板凳龙” 闹元宵 “板凳龙”,又称“盘龙”,是浙闽地区的传统地方民俗文化活动。人们将少则几十条,多则上百条的板凳首尾相连,形成蜿蜒曲折的板凳龙。盘龙时,龙头在前领头,龙身和龙尾相随盘旋,整体呈圆盘状。一般来说,在舞龙队能够自如地盘入和盘出的前提下,盘龙…...
Go语言基础语法 20240904更新
代码开源地址 https://github.com/zhangdapeng520/zdpgo_basic 快速入门 示例代码: package mainimport "fmt"func main() {fmt.Println("Hello World") }第一行代码 package 用来声明包名。main包时整个程序的入口包,在一个Go语…...

软件测试 | 性能测试
性能测试的概念 为了 发现系统性能问题 或 获取系统性能相关指标 而进行的测试。 常见性能测试指标 并发数 即并发用户数。 从业务层面看,并发用户数指的是 实际使用系统的用户总数。从后端服务器层面看,指的是 web服务器在一段时间内处理浏览器请求而建…...
Arduino IDE
Arduino IDE(集成开发环境)的安装过程是一个相对直观且易于操作的流程,主要步骤包括下载、安装和配置。以下将详细阐述Arduino IDE的安装过程,同时提供一些背景信息和注意事项,确保安装过程顺利进行。 一、Arduino ID…...

统计学习方法与实战——统计学习方法之感知机
感知机 感知机三要素分析模型策略损失函数选择 算法原始形式对偶形式 相关问题 例子iris数据集分类实战数据集查看 显示结果sklearn 实战感知机 习题解答习题2.1解题步骤反证法 习题2.2习题2.3凸壳线性可分线性可分证明凸壳不相交证明充分性:凸壳不相交\Rightarrow⇒…...

语言学习有捷径?没错!这4个方法让你轻松搞定英语翻译
现在全世界都在用英语,这门语言真的超级重要。不管你是学习、上班还是出去玩,会点英语翻译肯定能帮上大忙。但是,对很多人来说,翻译英语还是挺难的。别急,今天我就来给你介绍几个超好用的英语翻译工具,让你…...

聊一聊大型网站稳定性建设思路
目录 架构阶段的稳定性建设项目 编码阶段的稳定性建设 测试阶段的稳定性建设 发布阶段的稳定性建设 运行阶段的稳定性建设项目 故障发生时的稳定性建设 网站稳定性的建设是一项综合的系统工程,就像人的健康一样,如果平时不注意健康饮食、不注意锻炼…...

Nginx常用配置
Windows版本Nginx开机自启动 可直接下载已经配置好的文件,点击即可下载:Windows版本Nginx1.26.0 下载WinSW v2.12.0 首先从https://github.com/winsw/winsw/releases下载WinSW v2.12.0 下载Nginx 下载地址https://nginx.org/en/download.html 修…...

前端开发中遇到的小问题以及解决方案记录2
1、H5中适配屏幕的工具-postcss-px-to-viewport postcss-px-to-viewport。因为设计稿一般给的都是375px宽度的,所以假如一个字体是16px,那么在开发中不能直接写死为16px,因为各个厂商的手机屏幕大小是不同的,所以要根据屏幕大小去…...

Qt-常用控件(3)-输入类
1. QLineEdit QLineEdit 用来表示单行输入框.可以输入一段文本,但是不能换行 核心属性 属性说明text输入框中的文本inputMask输入内容格式约束maxLength最大长度frame是否添加边框echoMode显示方式. QLineEdit::Normal :这是默认值,文本框会显示输入的文本。QLineE…...
使用Docker启动Redis容器并映射端口
在现代软件开发中,Redis 是一种非常流行的开源内存数据结构存储,通常用作数据库、缓存或消息传递系统。Docker 是一个开源的应用容器引擎,它允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux …...

用fastapi搭建cpca地址提取服务接口
以前的客户地址比较乱,现在想提取出省份城市, 开始了解分词技术,后发现python有这样的库 cpca提取地址挺不错,可以从垃圾地址中提取省市区以及区号。 文章会用fastapi搭建服务端 通过post调用cpca,提取来了后&#…...
libvncclient编写多线程qt的VNC客户端
概述 使用qt和libvncclient编写vnc的客户端程序,多线程读写,拒绝卡顿。qt环境:5.15.3libvncclient:0.9.14下载地址:https://github.com/LibVNC/libvncserver/releases 编译libvncclient 打开CMakeList文件ÿ…...
视频处理基础之gradio框架实现
这些函数是用于处理视频文件的Python代码片段,它们依赖于ffmpeg和ffprobe工具,这些工具是FFmpeg项目的一部分,用于处理视频和音频数据。下面是每个函数的用途和用法的总结: 1. ffmpeg_installed() 函数: - 用途&am…...

黑马点评2——商户查询缓存(P37店铺类型查询业务添加缓存练习题答案)redis缓存、更新、穿透、雪崩、击穿、工具封装
文章目录 什么是缓存?添加Redis缓存店铺类型查询业务添加缓存练习题 缓存更新策略给查询商铺的缓存添加超时剔除和主动更新的策略 缓存穿透缓存空对象布隆过滤 缓存雪崩解决方案 缓存击穿解决方案基于互斥锁方式解决缓存击穿问题基于逻辑过期的方式解决缓存击穿问题…...

概率DP (由一道绿题引起的若干问题。目前为一些老题,蒟蒻的尝试学习1.0)
概率DP: 利用动态规划去解决 概率 期望 的题目。 概率DP 求概率(采用顺推) 从 初始状态推向结果,同一般的DP类似,只是经历了概率论知识的包装。 老题: 添加链接描述 题意: 袋子里有w只白鼠&am…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...