linux网络编程——UDP编程
写在前边
本文是B站up主韦东山的4_8-3.UDP编程示例_哔哩哔哩_bilibili视频的笔记,其中有些部分博主也没有理解,希望各位辩证的看。
UDP协议简介
UDP 是一个简单的面向数据报的运输层协议,在网络中用于处理数据包,是一种无连接的协议。UDP 不提供可靠性的传输,它只是把应用程序传给 IP 层的数据报发送出去,但是并不能保证它们能到达目的地。由于 UDP 在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
对于UDP网络编程步骤,这里借用韦山东老师的图:

图 3UDP 用户数据包模式
UDP相对于TCP编程来说简单了很多,因为UDP没有TCP那些可靠连接的东西,所以编程相对来说也简单了一些。
这里对于函数,只有发送和接受函数和之前有点区别:
sendto()
函数结构
#include <sys/types.h>#include <sys/socket.h>ssize_t sendto ( socket s , const void * msg, int len, unsigned int flags, conststruct sockaddr * to , int tolen ) ;
描述
sendto() 用来将数据由指定的socket传给对方主机。
参数
- s
用于通信的通信描述符,对于服务器,就是指accept函数返回的通信描述符
- msg
指向一片应用缓存,用于存放要发送的数据,存放数据一般使用结构体变量。
- len
存放发送数据的缓存的大小。
- flags
一般设置为0,此时是阻塞发送的,阻塞发送是指发送数据不成功会一直阻塞,直到被某信号中断或发送成功为止,不过发送数据一般不阻塞。
- to
存放指定欲传送的网络地址,结构sockaddr请参考bind()。
- tolen
sockaddr的结构长度。
- 返回值
成功:返回发送的字节数,失败:返回-1
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);
描述
它是一个系统调用,用于从套接字接收数据。该函数通常与无连接的数据报服务(如 UDP)一起使用,但也可以与其他类型的套接字使用。与简单的 recv() 函数不同,recvfrom() 可以返回数据来源的地址信息。
参数
- sockfd
一个已打开的套接字的描述符
- buf
指明一个缓冲区,该缓冲区用来存放recvfrom函数接收到的数据
- len
指明buf的长度。
- flags
传0 表示使用默认协议。
- src_addr
一个指针,指向一个 sockaddr 结构,用于保存发送数据的源地址,结构sockaddr请参考bind()。
- addrlen
src_addr的结构长度。当 recvfrom() 返回时,该值会被修改为实际地址的长度(以字节为单位)。
- 返回值
成功:成功执行时,返回接收到的字节数。,失败:返回-1。
剩下的函数请参考TCP中的函数:linux网络编程——TCP编程-CSDN博客
现在分别实现server 程序和client 程序。
server程序
在这个函数中参照server图进行编程,将图中所有函数挨个实现即可。

图 4server
具体实现看代码:
#include <sys/types.h> /* See NOTES */#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netinet/in.h>#include <sys/wait.h>#include <unistd.h>#include <arpa/inet.h>#include <pthread.h>/** 服务器端程序* socket* bind* sendto/recvfrom* close*/#define PORT 8888struct Param {int sockfd;char* buff;struct sockaddr* src_addr;};// 接收数据在子线程中处理void* Receive_data(void* Param1){struct Param Param2 = *(struct Param*)Param1;while (1){// 接收数据int addr_len = sizeof(Param2.src_addr);int iRecvLen = recvfrom(Param2.sockfd, Param2.buff, sizeof(Param2.buff), 0, Param2.src_addr, &addr_len);if (iRecvLen > 0){Param2.buff[iRecvLen] = '\0';// inet_ntoa(tSocketClientAddr.sin_addr)是将IP地址转换为字符串的函数printf("Get Msg From Client: %s: %s\n", inet_ntoa(((struct sockaddr_in*)Param2.src_addr)->sin_addr), Param2.buff);}}}int main(int argc, char** argv){int isocketfd;int Client_socketfd;int ret;struct sockaddr_in my_addr;struct sockaddr_in Client_addr;char send_buf[1024];char buff[1000];struct Param Param1;pthread_t ntid;// SOCK_DGRAM是UDP协议,AF_INET表示IPv4协议isocketfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == isocketfd){printf("create socket failed!\n");return -1;}// 配置bind函数的地址信息my_addr.sin_family = AF_INET; //指定协议族为IPV4版本的TCP/IP协议族my_addr.sin_port = htons(PORT); //指定端口号(和客户端通信的端口号,两者必须一致)my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //指定IP地址,这里设置为INADDR_ANY,表示可以接收任何来源的连接请求ret = bind(isocketfd, (const struct sockaddr*)&my_addr,sizeof(struct sockaddr));if (-1 == ret){printf("bind socket failed!\n");return -1;}Param1.sockfd = isocketfd;Param1.buff = buff;Param1.src_addr = (struct sockaddr*)&Client_addr;ret = pthread_create(&ntid, NULL, Receive_data, &Param1);if (ret){printf("create pthread failed!\n");return -1;}while (1){// 发送数据if (fgets(send_buf, sizeof(send_buf), stdin)){sendto(isocketfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&Client_addr, sizeof(Client_addr));}}close(isocketfd);return 0;}
这里使用了多线程将发送和接收数据分开,实现发送和接收数据互不干涉,其中pthread_create()函数是创建一个线程,具体函数分析见pthread_create()章节,这里将接收数据放入了创建的子线程中,主函数中实现发送函数。

图 5服务器端测试结果
这里获得的数据,其中192.168.147.132的IP是客户端的数据。
client 程序
在客户端的程序中,基本思路还是和之前服务器的程序相同,都是使用多线程将接收数据放入了创建的子线程中,还是依照韦老师的图:

图 6client
依次实现如上函数即可,具体实现如下代码:
#include <sys/types.h> /* See NOTES */#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netinet/in.h>#include <sys/wait.h>#include <unistd.h>#include <arpa/inet.h>#include <pthread.h>/** UDP客户端程序* socket* send* close*/#define PORT 8888// 线程参数结构体struct Param {int sockfd;char* buff;struct sockaddr* src_addr;};// 接收数据在子线程中处理void* Receive_data(void* Param1){struct Param Param2 = *(struct Param*)Param1;while (1){// 接收数据int addr_len = sizeof(Param2.src_addr);int iRecvLen = recvfrom(Param2.sockfd, Param2.buff, sizeof(Param2.buff), 0, Param2.src_addr, &addr_len);if (iRecvLen > 0){Param2.buff[iRecvLen] = '\0';// inet_ntoa(tSocketClientAddr.sin_addr)是将IP地址转换为字符串的函数printf("Get Msg From Client: %s: %s\n", inet_ntoa(((struct sockaddr_in*)Param2.src_addr)->sin_addr), Param2.buff);}else if (iRecvLen == -1){perror("recvfrom failed");break;}}}int main(int argc, char** argv){int isocketfd;struct sockaddr_in client_addr;char send_buf[1024];struct Param Param1;pthread_t ntid;char reve_buff[1024];memset(send_buf, 0, sizeof(send_buf));if (argc < 2){printf("Usage: %s ip_address\n", argv[0]);return -1;}client_addr.sin_family = AF_INET; //指定协议族为IPV4版本的TCP/IP协议族client_addr.sin_port = htons(PORT); //指定端口号//指定IP地址,htons()函数是将一个本地字节序的short转为网络字节序的shortclient_addr.sin_addr.s_addr = inet_addr(argv[1]);isocketfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == isocketfd){printf("create socket failed!\n");return -1;}Param1.sockfd = isocketfd;Param1.buff = reve_buff;Param1.src_addr = (struct sockaddr*)&client_addr;int ret = pthread_create(&ntid, NULL, Receive_data, &Param1);if (ret){printf("create pthread failed!\n");return -1;}while (1){if (fgets(send_buf, sizeof(send_buf), stdin)){sendto(isocketfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));}}return 0;}

图 7客户端测试结果
连接成功后即可发送和接收数据。
pthread_create()
函数结构
#include <pthread.h>int pthread_create(pthread_t* restrict tidp,const pthread_attr_t* restrict_attr,void* (*start_rtn)(void*),void *restrict arg);
描述
用来创建线程,并向线程函数传递参数。
参数
- tidp
事先创建好的pthread_t类型的参数。成功时tidp指向的内存单元被设置为新创建线程的线程ID。
- attr
用于定制各种不同的线程属性。通常直接设为NULL。
- start_rtn
新创建线程从此函数开始运行。无参数时arg设为NULL即可。
- arg
start_rtn函数的参数。无参数时设为NULL即可。有参数时输入参数的地址。当多于一个参数时应当使用结构体传入。
- 返回值
成功:返回0,失败:返回错误码。
相关文章:
linux网络编程——UDP编程
写在前边 本文是B站up主韦东山的4_8-3.UDP编程示例_哔哩哔哩_bilibili视频的笔记,其中有些部分博主也没有理解,希望各位辩证的看。 UDP协议简介 UDP 是一个简单的面向数据报的运输层协议,在网络中用于处理数据包,是一种无连接的…...
第四部分:1---文件内核对象,文件描述符,输出重定向
目录 struct file内核对象: 如何读写文件? 文件描述符在文件描述符表中的分配规则: 输出重定向初步解析: dup2实现复制文件描述符: struct file内核对象: struct file 是在内核空间中创建的用于描述文…...
如何在开发与生产环境中应用 Flask 进行数据库管理:以 SQLAlchemy 和 Flask-Migrate 为例
在使用 Flask 进行开发时,数据库管理是一个至关重要的环节。借助 SQLAlchemy 作为 ORM(对象关系映射)工具和 Flask-Migrate 进行数据库迁移,开发者可以高效地进行数据库管理,并在不同的环境(如开发环境和生…...
【Java零基础】Java核心知识点之:Map
HashMap(数组链表红黑树) HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null,允许多条记录的值为 null。HashMa…...
9.12日常记录
1.extern关键字 1)诞生动机:在一个C语言项目中,需要再多个文件中使用同一全局变量或是函数,那么就需要在这些文件中再声明一遍 2)用于声明在其他地方定义的一个变量或是函数,在当前位置只是声明,告诉编译器…...
光纤的两种模式
光纤主要分为两种模式:单模光纤(Single-Mode Fiber, SMF)和多模光纤(Multi-Mode Fiber, MMF)。这两种光纤在传输特性、应用场景以及传输距离上存在显著差异。12 单模光纤 定义:单模光纤…...
SpringMVC的初理解
1. SpringMVC是对表述层(Controller)解决方案 主要是 1.简化前端参数接收( 形参列表 ) 2.简化后端数据响应(返回值) 1.数据的接受 1.路径的匹配 使用RequestMapping(可以在类上或在方法上),支持模糊查询,在内部有method附带…...
Python 基本库用法:数学建模
文章目录 前言数据预处理——sklearn.preprocessing数据标准化数据归一化另一种数据预处理数据二值化异常值处理 numpy 相关用法跳过 nan 值的方法——nansum和nanmean展开多维数组(变成类似list列表的形状)重复一个数组——np.tile 分组聚集——pandas.…...
Android Greendao的数据库复制到设备指定位置
方法如下: private void export() {// 确保您已经请求并获得了WRITE_EXTERNAL_STORAGE权限// 获取要储存的设备路径String picturesDirPath Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();// 在公共目录下创建…...
Ajax 揭秘:异步 Web 交互的艺术
Ajax 揭秘:异步 Web 交互的艺术 一 . Ajax 的概述1.1 什么是 Ajax ?1.2 同步和异步的区别1.3 Ajax 的应用场景1.3.1 注册表单的用户名异步校验1.3.2 内容自动补全 二 . Ajax 的交互模型和传统交互模型的区别三 . Ajax 异步请求 axios3.1 axios 介绍3.1.1 使用步骤3…...
TitleBar:打造高效Android标题栏的新选择
在Android应用开发中,标题栏是用户界面的重要组成部分。一个好的标题栏不仅能够提升应用的专业感,还能增强用户体验。然而,传统的标题栏实现方式往往存在代码冗余、样式不统一、性能开销大等问题。今天,我们将介绍一个名为TitleBa…...
Lua协同程序Coroutine
Lua 协同程序(Coroutine) 定义 Lua 协同程序(Coroutine)与线程类似:拥有独立的堆栈、局部变量、指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。 协同程序可以理解为一种特殊的线程,可以暂停和恢复其执行,从而允…...
【vue+帆软】帆软升级,从版本9升级到版本11,记录升级过程
帆软要升级,记录下过程 1、帆软官网地址必不可少,戳这里,跳转帆软官网 点击前端开发指南 点击JS API 跳转过来就是版本11 一直往下翻,在最底部有个2.2 在Web中使用,圈起来的就是要引入到index.html中的脚本 在项…...
linux从0到1 基础完整知识
1. Linux系统概述 Linux是一种开源操作系统,与Windows或macOS等操作系统不同,Linux允许用户自由地查看、修改和分发其源代码。以下是Linux系统的一些显著的优势。 稳定性和可靠性: 内核以其稳定性而闻名,能够持续运行数月甚至数…...
“人大金仓”正式更名为“电科金仓”; TDSQL-C支持回收站/并行DDL等功能; BigQuery支持直接查询AlloyDB
重要更新 1. “人大金仓”正式更名为“电科金仓”,完整名称“中电科金仓(北京)科技股份有限公司”,突出金仓是中国电子科技集团有限公司在基础软件领域产品( [1] ) 。据悉人大金仓在上半年营收入为9056万元,净利润约21…...
大模型微调 - 用PEFT来配置和应用 LoRA 微调
大模型微调 - 用PEFT来配置和应用 LoRA 微调 flyfish PEFT(Parameter-Efficient Fine-Tuning)是一种参数高效微调库,旨在减少微调大型预训练模型时需要更新的参数量,而不影响最终模型的性能。它支持几种不同的微调方法ÿ…...
Ubuntu构建只读文件系统
本文介绍Ubuntu构建只读文件系统。 嵌入式系统使用过程中,有时会涉及到非法关机(比如直接关机,或意外断电),这可能造成文件系统损坏,为了提高系统的可靠性,通常将根文件系统设置为只读…...
【黑金系】金融UI/UX体验设计师面试作品集 Figma源文件分享
在数字金融时代,UI/UX体验设计师扮演着至关重要的角色。他们不仅塑造着产品的界面,更引领着用户的使用体验。我们的面试作品集,正是这样一部展现金融UI/UX设计魅力的宝典。 这套作品集汇聚了众多经典案例,每一处设计都经过精心雕…...
Golang | Leetcode Golang题解之第392题判断子序列
题目: 题解: func isSubsequence(s string, t string) bool {n, m : len(s), len(t)f : make([][26]int, m 1)for i : 0; i < 26; i {f[m][i] m}for i : m - 1; i > 0; i-- {for j : 0; j < 26; j {if t[i] byte(j a) {f[i][j] i} else {…...
Liunx常用指令
1. 文件和目录管理 ls 用法:ls [选项] [文件/目录]示例:ls -l(以长列表格式显示),ls -a(显示所有文件,包括隐藏文件)。 cd 用法:cd [目录]示例:cd ..…...
禅修运维法:服务器宕机时集体冥想
当技术危机遇上心灵平静在软件测试领域,服务器宕机是高频挑战,不仅中断测试流程,还引发团队压力。传统运维强调硬件修复和代码调试,但忽略了人的因素——压力下的决策失误往往加剧问题。禅修运维法创新性地将佛教禅修融入IT管理&a…...
用极空间 NAS 搭专属博客:Typecho 部署全攻略,把创作握在自己手里
前言 作为常年折腾各类私有部署工具的科技爱好者,我一直觉得「真正的创作自由」,藏在自己能掌控的服务器里。试过不少博客程序,要么配置繁琐,要么资源占用高,直到把 Typecho 和极空间 NAS 结合,才找到最舒…...
华为光猫配置解密工具技术架构解析与实现机制
华为光猫配置解密工具技术架构解析与实现机制 【免费下载链接】HuaWei-Optical-Network-Terminal-Decoder 项目地址: https://gitcode.com/gh_mirrors/hu/HuaWei-Optical-Network-Terminal-Decoder 在网络设备运维领域,华为光猫配置文件的安全加密机制为设备…...
RWKV7-1.5B-g1a保姆级部署教程:离线加载+免外网依赖,中小企业AI落地首选
RWKV7-1.5B-g1a保姆级部署教程:离线加载免外网依赖,中小企业AI落地首选 1. 模型简介 rwkv7-1.5B-g1a 是基于新一代 RWKV-7 架构的多语言文本生成模型,专为中小企业AI落地场景优化设计。这个1.5B参数的轻量级模型在保持高质量生成能力的同时…...
OpenSSH用户枚举漏洞(CVE-2018-15473)修复实战:从检测到升级的完整指南
OpenSSH用户枚举漏洞(CVE-2018-15473)修复实战:从检测到升级的完整指南 在当今的网络安全环境中,SSH服务作为远程管理服务器的标准协议,其安全性直接关系到整个系统的防护水平。2018年曝光的OpenSSH用户枚举漏洞(CVE-2018-15473)虽然CVSS评分…...
语音合成延迟优化:IndexTTS-2-LLM网络IO调优实战
语音合成延迟优化:IndexTTS-2-LLM网络IO调优实战 1. 为什么语音合成总在“等”?从用户卡顿说起 你有没有试过在语音合成页面点下“开始合成”,然后盯着进度条数秒——明明只是一句话,却要等3秒、5秒,甚至更久&#x…...
OpenClaw自动化邮件处理:GLM-4.7-Flash模型分类与回复
OpenClaw自动化邮件处理:GLM-4.7-Flash模型分类与回复 1. 为什么需要自动化邮件处理 每天早晨打开邮箱时,我的收件箱总是堆满了各种邮件——工作汇报、会议邀请、订阅资讯、促销广告……手动分类和回复这些邮件至少会消耗我30分钟时间。直到上个月&…...
别再死记硬背公式了!用3Blue1Brown的几何动画,5分钟搞懂行列式到底是啥
用动画解锁行列式的几何直觉:从死记硬背到可视化理解 当你第一次在课本上看到行列式的计算公式时,是否感到困惑——这个看似随意的ad-bc到底意味着什么?为什么它能够决定矩阵是否可逆?传统教学往往让我们陷入计算的泥潭࿰…...
Gemma-3 Pixel Studio镜像免配置:开箱即用的12B多模态推理工作站
Gemma-3 Pixel Studio镜像免配置:开箱即用的12B多模态推理工作站 1. 产品概览 Gemma-3 Pixel Studio是基于Google最新开源Gemma-3-12b-it模型构建的高性能多模态对话终端。这个预配置的Docker镜像消除了复杂的部署流程,让用户能够立即体验12B参数大模型…...
包装器简介
可调用对象:可以使用()运算符进行调用的对象,本质是能像函数一样使用的东西常见课调用对象:函数指针,仿函数,lambda表达式我们能否使用统一的方式对其封装,进行调用,这时…...
