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…...

[Python]生成器和yield关键字
生成器和yield关键字 1.生成器介绍: 概述: 它指的是 generator, 类似于以前学过的: 列表推导式, 集合推导式, 字典推导式… 作用: 降低资源消耗, 快速(批量)生成数据. 实现方式: 1.推导式写法. my_generator (i for i in range(5)) 2.yield写法. def get_gene…...

Nginx 负载均衡+高可用 集群部署(Keepalived+LVS DR模式)
一、LVS负载均衡简介 1.1 LVS基本介绍 LVS(Linux Virtual Server)即Linux虚拟服务器,是由章文嵩博士主导开发的开源负载均衡项目,目前LVS已经被集成在Linux内核中。该项目在Linux内核中实现了基于IP地址的请求数据负载均衡调度方…...

算法 | 基础 | 出现奇数次的数字
这里写自定义目录标题 异或运算题目1题目2 本篇是关于异或(^)运算的运用。后期看算法过程中如果再碰到异或的都会收录到本篇中 异或运算 在逻辑学中,逻辑算符异或(exclusive or)是对两个运算元的一种逻辑析取类型&am…...

log4j 控制台和文件输出乱码问题解决
一个小问题,却让我感觉到,现在真正动脑的人很少。。我来说说吧。 今天遇到一个小问题, log4j输出到文件乱码,控制台正常。显然是编码问题导致。Google一搜,几乎一水的说: 项目中log4j在英文版linux下输出中…...

在国产芯片上实现YOLOv5/v8图像AI识别-【4.2】RK3588获取USB摄像头图像推流RTSP更多内容见视频
本专栏主要是提供一种国产化图像识别的解决方案,专栏中实现了YOLOv5/v8在国产化芯片上的使用部署,并可以实现网页端实时查看。根据自己的具体需求可以直接产品化部署使用。 B站配套视频:https://www.bilibili.com/video/BV1or421T74f 前言…...

TCP/IP协议栈详解及其在现代网络中的应用
在当今数字化时代,网络已成为我们生活中不可或缺的一部分。无论是社交、工作还是娱乐,网络都在背后发挥着至关重要的作用。而这一切的实现,都离不开TCP/IP协议栈。本文将详细介绍TCP/IP协议栈的结构、各层功能以及它在现代网络中的应用。 什…...

亚信安全荣获“2024年网络安全优秀创新成果大赛”优胜奖
近日,由中央网信办网络安全协调局指导、中国网络安全产业联盟(CCIA)主办的“2024年网络安全优秀创新成果大赛”评选结果公布。亚信安全信舱ForCloud荣获“创新产品”优胜奖,亚信安全“宁波市政务信息化网络数据安全一体化指挥系统…...

如何从硬盘恢复已删除/丢失的文件?硬盘恢复已删除的文件技巧
如何从硬盘恢复已删除/丢失的文件?本教程将教您如何使用专业硬盘恢复软件从内置或外置硬盘恢复数据,或不使用软件从硬盘恢复已删除的文件。 “有人知道如何从外部硬盘恢复文件吗?当我将外部硬盘插入计算机时,我错误地删除了一些文…...

[Linux]:权限
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. Linux权限的基本概念 1.1 root与普通用户 在Linux系统中,存在…...

启动Spring Boot报错
一、遇到的问题 启动Spring Boot报错 Unable to close ApplicationContext org.springframework.boot.SpringApplication: Application run failed java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.cache.CacheAutoCo…...