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

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视频的笔记&#xff0c;其中有些部分博主也没有理解&#xff0c;希望各位辩证的看。 UDP协议简介 UDP 是一个简单的面向数据报的运输层协议&#xff0c;在网络中用于处理数据包&#xff0c;是一种无连接的…...

第四部分:1---文件内核对象,文件描述符,输出重定向

目录 struct file内核对象&#xff1a; 如何读写文件&#xff1f; 文件描述符在文件描述符表中的分配规则&#xff1a; 输出重定向初步解析&#xff1a; dup2实现复制文件描述符&#xff1a; struct file内核对象&#xff1a; struct file 是在内核空间中创建的用于描述文…...

如何在开发与生产环境中应用 Flask 进行数据库管理:以 SQLAlchemy 和 Flask-Migrate 为例

在使用 Flask 进行开发时&#xff0c;数据库管理是一个至关重要的环节。借助 SQLAlchemy 作为 ORM&#xff08;对象关系映射&#xff09;工具和 Flask-Migrate 进行数据库迁移&#xff0c;开发者可以高效地进行数据库管理&#xff0c;并在不同的环境&#xff08;如开发环境和生…...

【Java零基础】Java核心知识点之:Map

HashMap(数组链表红黑树) HashMap 根据键的 hashCode 值存储数据&#xff0c;大多数情况下可以直接定位到它的值&#xff0c;因而具有很快的访问速度&#xff0c;但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null&#xff0c;允许多条记录的值为 null。HashMa…...

9.12日常记录

1.extern关键字 1&#xff09;诞生动机:在一个C语言项目中&#xff0c;需要再多个文件中使用同一全局变量或是函数&#xff0c;那么就需要在这些文件中再声明一遍 2&#xff09;用于声明在其他地方定义的一个变量或是函数&#xff0c;在当前位置只是声明&#xff0c;告诉编译器…...

光纤的两种模式

光纤主要分为两种模式&#xff1a;‌‌单模光纤&#xff08;Single-Mode Fiber, SMF&#xff09;‌和‌‌多模光纤&#xff08;Multi-Mode Fiber, MMF&#xff09;‌。这两种光纤在传输特性、应用场景以及传输距离上存在显著差异。‌12 单模光纤 ‌定义‌&#xff1a;单模光纤…...

SpringMVC的初理解

1. SpringMVC是对表述层&#xff08;Controller&#xff09;解决方案 主要是 1.简化前端参数接收( 形参列表 ) 2.简化后端数据响应(返回值) 1.数据的接受 1.路径的匹配 使用RequestMapping(可以在类上或在方法上)&#xff0c;支持模糊查询&#xff0c;在内部有method附带…...

Python 基本库用法:数学建模

文章目录 前言数据预处理——sklearn.preprocessing数据标准化数据归一化另一种数据预处理数据二值化异常值处理 numpy 相关用法跳过 nan 值的方法——nansum和nanmean展开多维数组&#xff08;变成类似list列表的形状&#xff09;重复一个数组——np.tile 分组聚集——pandas.…...

Android Greendao的数据库复制到设备指定位置

方法如下&#xff1a; private void export() {// 确保您已经请求并获得了WRITE_EXTERNAL_STORAGE权限// 获取要储存的设备路径String picturesDirPath Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();// 在公共目录下创建…...

Ajax 揭秘:异步 Web 交互的艺术

Ajax 揭秘&#xff1a;异步 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应用开发中&#xff0c;标题栏是用户界面的重要组成部分。一个好的标题栏不仅能够提升应用的专业感&#xff0c;还能增强用户体验。然而&#xff0c;传统的标题栏实现方式往往存在代码冗余、样式不统一、性能开销大等问题。今天&#xff0c;我们将介绍一个名为TitleBa…...

Lua协同程序Coroutine

Lua 协同程序(Coroutine) 定义 Lua 协同程序(Coroutine)与线程类似&#xff1a;拥有独立的堆栈、局部变量、指令指针&#xff0c;同时又与其它协同程序共享全局变量和其它大部分东西。 协同程序可以理解为一种特殊的线程&#xff0c;可以暂停和恢复其执行&#xff0c;从而允…...

【vue+帆软】帆软升级,从版本9升级到版本11,记录升级过程

帆软要升级&#xff0c;记录下过程 1、帆软官网地址必不可少&#xff0c;戳这里&#xff0c;跳转帆软官网 点击前端开发指南 点击JS API 跳转过来就是版本11 一直往下翻&#xff0c;在最底部有个2.2 在Web中使用&#xff0c;圈起来的就是要引入到index.html中的脚本 在项…...

linux从0到1 基础完整知识

1. Linux系统概述 Linux是一种开源操作系统&#xff0c;与Windows或macOS等操作系统不同&#xff0c;Linux允许用户自由地查看、修改和分发其源代码。以下是Linux系统的一些显著的优势。 稳定性和可靠性&#xff1a; 内核以其稳定性而闻名&#xff0c;能够持续运行数月甚至数…...

“人大金仓”正式更名为“电科金仓”; TDSQL-C支持回收站/并行DDL等功能; BigQuery支持直接查询AlloyDB

重要更新 1. “人大金仓”正式更名为“电科金仓”&#xff0c;完整名称“中电科金仓&#xff08;北京&#xff09;科技股份有限公司”&#xff0c;突出金仓是中国电子科技集团有限公司在基础软件领域产品( [1] ) 。据悉人大金仓在上半年营收入为9056万元&#xff0c;净利润约21…...

大模型微调 - 用PEFT来配置和应用 LoRA 微调

大模型微调 - 用PEFT来配置和应用 LoRA 微调 flyfish PEFT&#xff08;Parameter-Efficient Fine-Tuning&#xff09;是一种参数高效微调库&#xff0c;旨在减少微调大型预训练模型时需要更新的参数量&#xff0c;而不影响最终模型的性能。它支持几种不同的微调方法&#xff…...

Ubuntu构建只读文件系统

本文介绍Ubuntu构建只读文件系统。 嵌入式系统使用过程中&#xff0c;有时会涉及到非法关机&#xff08;比如直接关机&#xff0c;或意外断电&#xff09;&#xff0c;这可能造成文件系统损坏&#xff0c;为了提高系统的可靠性&#xff0c;通常将根文件系统设置为只读&#xf…...

【黑金系】金融UI/UX体验设计师面试作品集 Figma源文件分享

在数字金融时代&#xff0c;UI/UX体验设计师扮演着至关重要的角色。他们不仅塑造着产品的界面&#xff0c;更引领着用户的使用体验。我们的面试作品集&#xff0c;正是这样一部展现金融UI/UX设计魅力的宝典。 这套作品集汇聚了众多经典案例&#xff0c;每一处设计都经过精心雕…...

Golang | Leetcode Golang题解之第392题判断子序列

题目&#xff1a; 题解&#xff1a; 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 用法&#xff1a;ls [选项] [文件/目录]示例&#xff1a;ls -l&#xff08;以长列表格式显示&#xff09;&#xff0c;ls -a&#xff08;显示所有文件&#xff0c;包括隐藏文件&#xff09;。 cd 用法&#xff1a;cd [目录]示例&#xff1a;cd ..&#xf…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下&#xff0c;企业和个人创作者为了扩大影响力、提升传播效果&#xff0c;纷纷采用短视频矩阵运营策略&#xff0c;同时管理多个平台、多个账号的内容发布。然而&#xff0c;频繁的文案创作需求让运营者疲于应对&#xff0c;如何高效产出高质量文案成…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...

python打卡第47天

昨天代码中注意力热图的部分顺移至今天 知识点回顾&#xff1a; 热力图 作业&#xff1a;对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图&#xff0c;展示模…...

算法250609 高精度

加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...