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

Linux网络编程 多进程UDP聊天室:共享内存与多进程间通信实战解析

知识点1【项目功能介绍】

今天我们写一个 UDP多进程不同进程间通信的综合练习

我这里说一下 这个项目的功能:

1、群发(有设备个数的限制):发送数据,其他所有客户端都要受到数据

2、其他客户端 可以向本机发送消息

3、私发:私发的格式为 /IP:端口号,数据

知识点2【项目实现思路】

1、首先最基本的UDP的步骤

创建套接字→绑定套接字→操作→关闭套接字

2、创建两个子进程,一个子进程负责收数据,另一个子进程负责发数据

3、由于子进程之间 都需要 所连接的设备的 IP 和 端口号,但是子进程之间的空间又是独立的,因此我们需要用共享内存的方式,而共享内存共享的则是一个地址结构体数组

1、共享结构体数组

    char shm_name[32] = "./shm_file";int fd_shm = open(shm_name,O_CREAT | O_RDWR,0666);if(fd_shm < 0){perror("open");_exit(-1);}int shm_size = sizeof(struct sockaddr_in) * NUM_DEVICE;//2、设置共享内存大小ftruncate(fd_shm,shm_size);//3、内存映射struct sockaddr_in * sockaddr_shm = (struct sockaddr_in *)mmap(NULL,shm_size,PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);if(sockaddr_shm  == MAP_FAILED){perror("mmap");_exit(-1);}bzero(sockaddr_shm,shm_size);

1、首先打开文件(可读可写,创建)

2、由于文件打开,大小为0,我们需要进行扩容

ftruncate();

3、内存映射mmap

NULL(系统自动寻找内存空间),空间大小,文件权限,共享,要映射的文件,偏移量

4、清空内存

bzero();

2、UDP常规流程

创建套接字 和 绑定

		//套接字创建int fd_sock = socket(AF_INET,SOCK_DGRAM,0);if(fd_sock < 0){perror("socket");_exit(-1);}//绑定struct sockaddr_in addr_src;addr_src.sin_family = AF_INET;addr_src.sin_port = htons(8000);addr_src.sin_addr.s_addr = htonl(INADDR_ANY); int ret_bind = bind(fd_sock,(struct sockaddr *)&addr_src,sizeof(addr_src));if(ret_bind < 0){perror("bind");_exit(-1);}

不多作介绍

3、创建子进程的模式

以创建两个为例

    //创建子进程size_t i = 0;for (; i < 2; i++){int pid = fork();if(pid < 0){perror("fork");_exit(-1);}if(pid == 0){break;}}if(i == 0)//子进程1{}else if(i == 1)//子进程2{}

不多作介绍

4、收数据

    if(i == 0)//进程1,负责收数据{while(1){char buf[500] = "";int len = sizeof(struct sockaddr_in);struct sockaddr_in buf_recv;int ret_recv = recvfrom(fd_sock,buf,sizeof(buf),0,(struct sockaddr *)&buf_recv,&len);if(ret_recv < 0){perror("recvfrom");_exit(-1);}//查看该IP和端口是否存在int exists = 0;for (size_t j = 0; j < NUM_DEVICE; j++){if(buf_recv.sin_addr.s_addr == sockaddr_shm[j].sin_addr.s_addr && buf_recv.sin_port == sockaddr_shm[j].sin_port){exists = 1;break;}}if(exists != 1)//不存在,存入第一个空的地址结构体{size_t k = 0;for (; k < NUM_DEVICE; k++){if(ntohs(sockaddr_shm[k].sin_port) == 0){memcpy(&sockaddr_shm[k],&buf_recv,sizeof(buf_recv));//代码书写过程中,这里出现错误 break;}}if(k == NUM_DEVICE){printf("\\r群聊已满,无法加入\\n");continue;}}//遍历收到的信息char buf_IP[16] = "";inet_ntop(AF_INET,&buf_recv.sin_addr.s_addr,buf_IP,sizeof(buf_IP));int port = ntohs(buf_recv.sin_port);printf("\\r收到IP:%s,端口号:%d的信息为:%s\\n",buf_IP,port,buf);printf("\\r请输入数据(提示/起始可指定IP发送):");fflush(stdout);}_exit(-1);}

思路讲解

1、首先接收数据

2、判断数据来源客户端,是否存在,如果不存在,则存在 结构体数组的 最小有效的下标 中,当数组存满后,需要提醒一下,但是不会退出,已经连接的设备仍然可以发送/接收数据,因此需要用continue而不是break

这里我要说我写的过程中的一个错误,希望大家以我为诫,别犯类似错误

我在下面代码中,数组下标忘记写了&sockaddr_shm[k]→sockaddr_shm,导致我永远只能给一台设备发送数据

for (; k < NUM_DEVICE; k++)
{if(ntohs(sockaddr_shm[k].sin_port) == 0){memcpy(&sockaddr_shm[k],&buf_recv,sizeof(buf_recv));//代码书写过程中,这里出现错误 break;}
}

3、遍历收到的数据

5、发数据

else if(i == 1){   while(1){printf("\\r请输入数据(提示/起始可指定IP发送):");fflush(stdout);char buf[256] = "";fgets(buf,sizeof(buf),stdin);buf[strlen(buf) - 1] = 0;if(buf[0] == '/'){char buf_ip[16] = "";int int_port = 0;char data[256] = "";sscanf(buf,"/%[^:]:%4d,%s",buf_ip,&int_port,data);int int_ip = 0;//转为网络字节序inet_pton(AF_INET,buf_ip,&int_ip);int_port = htons(int_port);//定义一个标志位,判断输入的端口是不是存在int flag = 0;size_t k = 0;for (; k < NUM_DEVICE; k++){if(sockaddr_shm[k].sin_addr.s_addr == int_ip && sockaddr_shm[k].sin_port == int_port){flag = 1;break;}}if(flag == 1){//私发sendto(fd_sock,data,sizeof(data),0,(struct sockaddr *)&sockaddr_shm[k],sizeof(struct sockaddr_in));}else{//不存在该端口,打印提示内容,输出现有的所有IP和端口printf("指令错误,请按照下面的model输入\\n");printf("mode:/192.168.6.3:9000,data\\n");if(sockaddr_shm[0].sin_addr.s_addr != 0);{printf("以下是已经连接的端口\\n");for (size_t i = 0; i < NUM_DEVICE; i++){if(sockaddr_shm[i].sin_port != 0){inet_ntop(AF_INET,&sockaddr_shm[i].sin_addr.s_addr,buf_ip,sizeof(buf_ip));int_ip = ntohs(sockaddr_shm->sin_port);printf("%s:%d\\n",buf_ip,int_ip);}}}}}else//群发{for (size_t j = 0; j < NUM_DEVICE ;j++){if(sockaddr_shm[j].sin_port != 0){sendto(fd_sock,buf,sizeof(buf),0,(struct sockaddr *)&sockaddr_shm[j],sizeof(struct sockaddr_in));}}}}}

思路讲解

1、观察格式,我们发现私发格式 第一个字母必须要求是/开头,我们用这个作为进行判断

2、首先需要判断输入的端口 和 IP地址是否合法

3、如果合法,进行发送,不合法则需要 遍历提示内容,如果已经有设备的连接,需要遍历出可以通信的IP

注意

这一步比较复杂的是数据类型(网络字节序与主机字节序的转换,与点分法十进制串与 网络整形IP 的转换)

6、父进程负责回收空间

    else{while(1){int ret_wait = waitpid(-1,NULL,WNOHANG);if(ret_wait < 0){break;}}close(fd_shm);close(fd_sock);munmap(shm_name,shm_size);remove(shm_name);}

需要回收的空间介绍

1、共享内存时 打开的共享内存文件描述符

2、套接字

3、映射关系

4、映射文件删除

知识点2【整体代码演示】

//项目介绍 实现多人聊天室
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */
#include <strings.h>
#include <string.h>
#include <stdlib.h>#define NUM_DEVICE 10int main(int argc, char const *argv[])
{//父进程负责管理子进程的内存,子进程1负责收,子进程2 负责发//收的流程,创建sock,绑定端口,收,关闭端口//发的流程,创建sock,绑定端口,发,变比端口//由于需要子进程之间需要共享 结构体数组数据,这里需要利用到共享内存//1、创建共享内存,并计算大小char shm_name[32] = "./shm_file";int fd_shm = open(shm_name,O_CREAT | O_RDWR,0666);if(fd_shm < 0){perror("open");_exit(-1);}int shm_size = sizeof(struct sockaddr_in) * NUM_DEVICE;//2、设置共享内存大小ftruncate(fd_shm,shm_size);//3、内存映射struct sockaddr_in * sockaddr_shm = (struct sockaddr_in *)mmap(NULL,shm_size,PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);if(sockaddr_shm  == MAP_FAILED){perror("mmap");_exit(-1);}bzero(sockaddr_shm,shm_size);//套接字创建int fd_sock = socket(AF_INET,SOCK_DGRAM,0);if(fd_sock < 0){perror("socket");_exit(-1);}//绑定struct sockaddr_in addr_src;addr_src.sin_family = AF_INET;addr_src.sin_port = htons(8000);addr_src.sin_addr.s_addr = htonl(INADDR_ANY); int ret_bind = bind(fd_sock,(struct sockaddr *)&addr_src,sizeof(addr_src));if(ret_bind < 0){perror("bind");_exit(-1);}//创建子进程size_t i = 0;for (; i < 2; i++){int pid = fork();if(pid < 0){perror("fork");_exit(-1);}if(pid == 0){break;}}//子进程1 负责收if(i == 0){while(1){char buf[500] = "";int len = sizeof(struct sockaddr_in);struct sockaddr_in buf_recv;int ret_recv = recvfrom(fd_sock,buf,sizeof(buf),0,(struct sockaddr *)&buf_recv,&len);if(ret_recv < 0){perror("recvfrom");_exit(-1);}//查看该IP和端口是否存在int exists = 0;for (size_t j = 0; j < NUM_DEVICE; j++){if(buf_recv.sin_addr.s_addr == sockaddr_shm[j].sin_addr.s_addr && buf_recv.sin_port == sockaddr_shm[j].sin_port){exists = 1;break;}}if(exists != 1)//不存在,存入第一个空的地址结构体{size_t k = 0;for (; k < NUM_DEVICE; k++){if(ntohs(sockaddr_shm[k].sin_port) == 0){memcpy(&sockaddr_shm[k],&buf_recv,sizeof(buf_recv));//代码书写过程中,这里出现错误 break;}}if(k == NUM_DEVICE){printf("\\r群聊已满,无法加入\\n");continue;}}//遍历收到的信息char buf_IP[16] = "";inet_ntop(AF_INET,&buf_recv.sin_addr.s_addr,buf_IP,sizeof(buf_IP));int port = ntohs(buf_recv.sin_port);printf("\\r收到IP:%s,端口号:%d的信息为:%s\\n",buf_IP,port,buf);printf("\\r请输入数据(提示/起始可指定IP发送):");fflush(stdout);}_exit(-1);}//子进程2 负责发,这里设置,如果发送收到bye,Bye退出//实现发送消息,实际上是给多人发送,使用 结构体数组,存储多人的信息else if(i == 1){   while(1){printf("\\r请输入数据(提示/起始可指定IP发送):");fflush(stdout);char buf[256] = "";fgets(buf,sizeof(buf),stdin);buf[strlen(buf) - 1] = 0;if(buf[0] == '/'){char buf_ip[16] = "";int int_port = 0;char data[256] = "";sscanf(buf,"/%[^:]:%4d,%s",buf_ip,&int_port,data);int int_ip = 0;//转为网络字节序inet_pton(AF_INET,buf_ip,&int_ip);int_port = htons(int_port);//定义一个标志位,判断输入的端口是不是存在int flag = 0;size_t k = 0;for (; k < NUM_DEVICE; k++){if(sockaddr_shm[k].sin_addr.s_addr == int_ip && sockaddr_shm[k].sin_port == int_port){flag = 1;break;}}if(flag == 1){//私发sendto(fd_sock,data,sizeof(data),0,(struct sockaddr *)&sockaddr_shm[k],sizeof(struct sockaddr_in));}else{//不存在该端口,打印提示内容,输出现有的所有IP和端口printf("指令错误,请按照下面的model输入\\n");printf("mode:/192.168.6.3:9000,data\\n");if(sockaddr_shm[0].sin_addr.s_addr != 0);{printf("以下是已经连接的端口\\n");for (size_t i = 0; i < NUM_DEVICE; i++){if(sockaddr_shm[i].sin_port != 0){inet_ntop(AF_INET,&sockaddr_shm[i].sin_addr.s_addr,buf_ip,sizeof(buf_ip));int_ip = ntohs(sockaddr_shm->sin_port);printf("%s:%d\\n",buf_ip,int_ip);}}}}}else{for (size_t j = 0; j < NUM_DEVICE ;j++){if(sockaddr_shm[j].sin_port != 0){sendto(fd_sock,buf,sizeof(buf),0,(struct sockaddr *)&sockaddr_shm[j],sizeof(struct sockaddr_in));}}}}}//父进程回收子进程else{while(1){int ret_wait = waitpid(-1,NULL,WNOHANG);if(ret_wait < 0){break;}}close(fd_shm);close(fd_sock);munmap(shm_name,shm_size);remove(shm_name);}return 0;
}

代码运行结果

结束

代码重在练习!

代码重在练习!

代码重在练习!

今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!

相关文章:

Linux网络编程 多进程UDP聊天室:共享内存与多进程间通信实战解析

知识点1【项目功能介绍】 今天我们写一个 UDP &#xff0c;多进程与不同进程间通信的综合练习 我这里说一下 这个项目的功能&#xff1a; 1、群发&#xff08;有设备个数的限制&#xff09;&#xff1a;发送数据&#xff0c;其他所有客户端都要受到数据 2、其他客户端 都 可…...

网络结构及安全科普

文章目录 终端联网网络硬件基础网络协议示例&#xff1a;用户访问网页 OSI七层模型网络攻击&#xff08;Hack&#xff09;网络攻击的主要类别&#xff08;一&#xff09;按攻击目标分类&#xff08;二&#xff09;按攻击技术分类 网络安全防御 典型攻击案例相关名词介绍网络连接…...

CAD文件如何导入BigemapPro

问题描述 在使用 BigemapPro 加载 CAD 文件的过程中&#xff0c;会出现两种不同的情况&#xff1a;部分文件能够被软件自动识别投影并顺利加载&#xff1b;而另一部分文件则无法自动识别投影&#xff0c;需要手动干预才能准确加载到影像上。下面为您详细介绍这两种情况的具体操…...

Spring-AOP分析

Spring分析-AOP 1.案例引入 在上一篇文章中&#xff0c;【Spring–IOC】【https://www.cnblogs.com/jackjavacpp/p/18829545】&#xff0c;我们了解到了IOC容器的创建过程&#xff0c;在文末也提到了AOP相关&#xff0c;但是没有作细致分析&#xff0c;这篇文章就结合示例&am…...

opencv 对图片的操作

对图片的操作 1.图片镜像旋转&#xff08;cv2.flip()&#xff09;2 图像的矫正 1.图片镜像旋转&#xff08;cv2.flip()&#xff09; 图像的旋转是围绕一个特定点进行的&#xff0c;而图像的镜像旋转则是围绕坐标轴进行的。图像的镜像旋转分为水平翻转、垂直翻转、水平垂直翻转…...

Python第一周作业

Python第一周作业 文章目录 Python第一周作业 如何在命令行中创建一个名为venv的虚拟环境&#xff1f;请写出具体命令编写一段代码&#xff0c;判断变量x是否为偶数&#xff0c;如果是则返回"Even"&#xff0c;否则返回"Odd"编写代码&#xff0c;使用分支结…...

jinjia2将后端传至前端的字典变量转换为JS变量

后端 country_dict {AE: .amazon.ae, AU: .amazon.com.au} 前端 const country_list JSON.parse({{ country_list | tojson | safe }});...

[渗透测试]渗透测试靶场docker搭建 — —全集

[渗透测试]渗透测试靶场docker搭建 — —全集 对于初学者来说&#xff0c;仅仅了解漏洞原理是不够的&#xff0c;还需要进行实操。对于公网上的服务我们肯定不能轻易验证某些漏洞&#xff0c;否则可能触犯法律。这是就需要用到靶场。 本文主要给大家介绍几种常见漏洞对应的靶场…...

二分查找、分块查找、冒泡排序、选择排序、插入排序、快速排序

二分查找/折半查找 前提条件&#xff1a;数组中的数据必须是有序的 核心逻辑&#xff1a;每次排除一半的查找范围 优点&#xff1a;提高查找效率 代码 public static int binarySearch(int[] arr, int num) {int start 0;int end arr.length - 1;while (start < end) {…...

【AI】SpringAI 第三弹:接入通用大模型平台

1.添加依赖 <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId> </dependency> 2.设置 yml 配置文件 在 application.yml 中添加 DeepSeek 的配置信息&#xff1a; spr…...

C++常用函数合集

万能头文件&#xff1a;#include<bits/stdc.h> 1. 输入输出流&#xff08;I/O&#xff09;函数 1.1cin 用于从标准输入流读取数据。 1.2cout 用于向标准输出流写入数据。 // 输入输出流&#xff08;I/O&#xff09;函数 #include <iostream> using namespace…...

22. git show

基本概述 git show 的作用是&#xff1a;显示各种 Git 对象&#xff08;如提交、标签、树对象、文件对象等&#xff09;的详细信息 基本用法 1.基本语法 git show [选项] [对象]2.查看提交的详细信息 git show <commit-hash> # 示例 git show a1b2c3d # 显示某…...

使用blob文件流

1.后端 GetMapping(value "/static/**")public void view(HttpServletRequest request, HttpServletResponse response) {// ISO-8859-1 > UTF-8 进行编码转换String imgPath extractPathFromPattern(request);if(oConvertUtils.isEmpty(imgPath) || imgPath&q…...

操作指南:在vue-fastapi-admin上增加新的功能模块

近期在github上看到一个很不错的web框架&#xff0c;https://github.com/mizhexiaoxiao/vue-fastapi-admin。该项目基于 FastAPI Vue3 Naive UI 的现代化前后端分离开发平台&#xff0c;融合了 RBAC 权限管理、动态路由和 JWT 鉴权&#xff0c;可以助力中小型应用快速搭建&am…...

文字、语音、图片、视频四个模态两两之间(共16种转换方向)的生成技术及理论基础的详细说明及表格总结

以下是文字、语音、图片、视频四个模态两两之间&#xff08;共16种转换方向&#xff09;的生成技术及理论基础的详细说明及表格总结&#xff1a; 1. 技术与理论基础详解 (1) 文字与其他模态的转换 文字→文字 技术&#xff1a;GPT、BERT、LLaMA等语言模型。理论&#xff1a;T…...

FramePack:让视频生成更高效、更实用

想要掌握如何将大模型的力量发挥到极致吗&#xff1f;叶梓老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具&#xff08;限时免费&#xff09;。 1小时实战课程&#xff0c;您将学习到如何轻松上手并有效利用 Llama Factory 来微调您的模型&#xff0c;以发挥其…...

【大语言模型DeepSeek+ChatGPT+python】最新AI-Python机器学习与深度学习技术在植被参数反演中的核心技术应用

在全球气候变化与生态环境监测的重要需求下&#xff0c;植被参数遥感反演作为定量评估植被生理状态、结构特征及生态功能的核心技术&#xff0c;正面临数据复杂度提升、模型精度要求高、多源异构数据融合等挑战。人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;…...

RSS 2025|苏黎世提出「LLM-MPC混合架构」增强自动驾驶,推理速度提升10.5倍!

论文题目&#xff1a;Enhancing Autonomous Driving Systems with On-Board Deployed Large Language Models 论文作者&#xff1a;Nicolas Baumann&#xff0c;Cheng Hu&#xff0c;Paviththiren Sivasothilingam&#xff0c;Haotong Qin&#xff0c;Lei Xie&#xff0c;Miche…...

Oracle expdp的 EXCLUDE 参数详解

Oracle expdp的 EXCLUDE 参数详解 EXCLUDE 是 Oracle Data Pump Export (expdp) 工具中的一个关键参数&#xff0c;用于指定在导出过程中要排除的对象或对象类型。 一、基本语法 expdp username/password DUMPFILEexport.dmp DIRECTORYdpump_dir EXCLUDEobject_type[:name_c…...

Git创建空分支并推送到远程仓库

new-empty-branch是新分支的名称 完全空提交&#xff08;Git 2.23&#xff09;【推荐】 git switch --orphan new-empty-branch git config user.email "youexample.com" git config user.name "Your Name" git commit --allow-empty -m "初始空提交…...

TDS电导率传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 三、程序设计 main文件 tds.h文件 tds.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 TDS电导率传感器介绍 &#xff1a; TDS&#xff08;Total Dissolved Solid&#xff09;&#xff0c;中文名总溶解固…...

初识Redis · C++客户端list和hash

目录 前言&#xff1a; list lpush lrange rpush rpush llen rpop lpop blpop hash hset hget hmget hkeys hvals hexists hdel 前言&#xff1a; 在上一篇文章我们介绍了string的基本使用&#xff0c;并且发现几乎唯一的难点就是使用迭代器方面&#xff0c;并且我们…...

SpringBoot和微服务学习记录Day3

Hystrix 熔断器 在分布式架构中&#xff0c;很多服务因为网络或自身原因不可避免发生故障&#xff0c;如果某个服务出现问题往往会导致一系列的服务都发生故障&#xff0c;导致整个微服务架构瘫痪&#xff0c;称为服务雪崩&#xff0c;Hystrix就是为了解决这个问题的 服务熔…...

12个领域近120个典型案例:2024年“数据要素X”大赛典型案例集(附下载)

2024年10月25日&#xff0c;2024年“数据要素”大赛全国总决赛颁奖仪式在北京举行。这次大赛是首届“数据要素x”大赛&#xff0c;全国共有近2万支队伍踊跃参赛&#xff0c;10万参赛者用数据编织梦想&#xff0c;最终角逐出12个赛道120个典型案例。 根据国家数据局等相关公开资…...

如何在腾讯云Ubuntu服务器上部署Node.js项目

最近弄了一个Node.js项目&#xff0c;包含前端用户前台&#xff0c;管理后台和服务端API服务三个项目&#xff0c;本地搭建好了&#xff0c;于是在腾讯云上新建了个Ubuntu 24.04服务器&#xff0c;想要将本地的Node.js项目部署上去&#xff0c;包括环境配置和数据库搭建。 本文…...

【NLP 67、知识图谱】

你像即将到来的夏季一样鲜明&#xff0c; 以至于我这样寡淡的生命&#xff0c; 竟山崩般为你着迷 —— 25.4.18 一、信息 VS 知识 二、知识图谱 1.起源 于2012年5月17日被Google正式提出&#xff0c;初衷是为了提高搜索引擎的能力&#xff0c;增强用户的搜索质量以及搜索体验 …...

Java写数据结构:栈

1.概念&#xff1a; 一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xff1a;栈的插…...

跨境电商行业新周期下的渠道突围策略

2024年初&#xff0c;跨境电商圈动荡不断&#xff0c;多家卖家平台股价大跌&#xff0c;引发行业舆论热议。而作为东南亚主战场的Shopee&#xff0c;仅仅几个月时间跌幅已达23%。在这一波冲击中&#xff0c;大多数卖家都在"止血"&#xff0c;但有棵树却逆势而上&…...

Docker如何更换镜像源提高拉取速度

在国内&#xff0c;由于网络政策和限制&#xff0c;直接访问DockerHub速度很慢&#xff0c;尤其是在拉取大型镜像时。为了解决这个问题&#xff0c;常用的方法就是更换镜像源。本文将详细介绍如何更换Docker镜像源&#xff0c;并提供当前可用的镜像源。 换源方法 方法1&#x…...

平方根倒数快速算法

一、平方根倒数算法的由来 在制作3D游戏的时候&#xff0c;曲面是由许多平面构成的&#xff0c;要求出光线在物体表面反射后的效果&#xff0c;就需要知道平面的单位法向量&#xff0c;法向量的长度的平方R很容易求出&#xff0c;单位法向量 坐标值 / R的平方根。电脑每次都要…...

详解.vscode 下的json .vscode文件夹下各个文件的作用

1.背景 看一些开源项目的时候,总是看到vscode先有不同的json文件,再次做一下总结方便之后查看 settings.json肯定不用多说了 vscode 编辑器分为 全局用户配置 和 当前工作区配置 那么.vscode文件夹下的settings.json文件夹肯定就是当前工作区配置了 在此文件对单个的项目进行配…...

【消息队列RocketMQ】二、RocketMQ 消息发送与消费:原理与实践

一、RocketMQ 消息发送原理与模式​ 1.1 消息发送原理​ RocketMQ 消息发送的核心流程围绕 Producer、NameServer 和 Broker 展开。Producer 启动时&#xff0c;会向 NameServer 请求获取 Topic 的路由信息&#xff0c;这些信息包括 Topic 对应的 Broker 列表以及 Broker 上的…...

WPF的发展历程

文章目录 WPF的发展历程引言起源与背景&#xff08;2001-2006&#xff09;从Avalon到WPF设计目标与创新理念 WPF核心技术特点与架构基础架构与渲染模型关键技术特点MVVM架构模式 WPF在现代Windows开发中的地位与前景当前市场定位与其他微软UI技术的关系未来发展前景 社区贡献与…...

新书速览|OpenCV计算机视觉开发实践:基于Qt C++

《OpenCV计算机视觉开发实践:基于Qt C》 本书内容 OpenCV是计算机视觉领域的开发者必须掌握的技术。《OpenCV计算机视觉开发实践:基于Qt C》基于 OpenCV 4.10与Qt C进行编写&#xff0c;全面系统地介绍OpenCV的使用及实战案例&#xff0c;并配套提供全书示例源码、PPT课件与作…...

本地搭建一个简易版本的 Web3 服务

一、环境搭建与工具准备 &#xff08;一&#xff09;安装 Node.js 和 npm Node.js 是一个基于 JavaScript 的运行时环境&#xff0c;npm 是其默认的包管理器。在 Web3 开发中&#xff0c;Node.js 和 npm 是必不可少的工具。 访问 Node.js 官网 并下载最新的 LTS 版本。 安装…...

电脑安装CentOS系统

前言 电脑是Windows10系统&#xff0c;安装CentOS之前要将硬盘格式化&#xff0c;这个操作会将Windows10系统以及电脑上所有资料抹除&#xff0c;操作前务必谨慎复查是否有重要资料需要备份。 准备工作 准备两个U盘&#xff0c;一台电脑。提前把镜像下载好。镜像在百度网盘里…...

【Linux专栏】zip 多个文件不带路径

Linux && Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 今天发现 Linux 解压缩的文件中&#xff0c;不光包含需要的文件&#xff0c;还保留了目录层级&#xff0c;不是想要的结果。因此&#xff0c;本文关于…...

邀请函 | 「软件定义汽车 同星定义软件」 TOSUN用户日2025·杭州站

参会邀请函 尊敬的客户及合作伙伴&#xff1a; 新能源汽车智能化浪潮席卷全球&#xff0c;杭州作为中国技术创新高地&#xff0c;正引领行业变革。为助力工程师伙伴应对行业挑战&#xff0c;解决工程难题&#xff0c;同星智能将于2025年5月9日&#xff08;周五&#xff09;在…...

start_response详解

start_response 是Python的WSGI&#xff08;Web Server Gateway Interface&#xff09;中的一个重要概念&#xff0c;它是一个可调用对象&#xff08;通常是一个函数&#xff09;&#xff0c;在WSGI应用程序里发挥着关键作用&#xff0c;下面为你详细介绍。 作用 在WSGI规范里…...

记一次 .NET某旅行社酒店管理系统 卡死分析

一&#xff1a;背景 1. 讲故事 年初有位朋友找到我&#xff0c;说他们的管理系统不响应了&#xff0c;让我帮忙看下到底咋回事? 手上也有dump&#xff0c;那就来分析吧。 二&#xff1a;为什么没有响应 1. 线程池队列有积压吗&#xff1f; 朋友的系统是一个web系统&#…...

[预备知识]1. 线性代数基础

线性代数基础 线性代数是深度学习的重要基础&#xff0c;本章节将介绍深度学习中常用的线性代数概念和操作。 1. 标量、向量、矩阵与张量 1.1 标量&#xff08;Scalar&#xff09; 标量是单个数值&#xff0c;用 x ∈ R x \in \mathbb{R} x∈R 表示。在深度学习中常用于表…...

RESTful学习笔记(二)---简单网页前后端springboot项目搭建

新建项目&#xff1a; 项目结构 Pom.xml中添加依赖&#xff1a; 要有用于启动的父进程&#xff0c;有启动依赖&#xff0c;有lombok用于自动构建getter和setter方法等 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-…...

C++ AI模型部署优化实战:基于TensorRT的高效推理引擎开发

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…...

[特殊字符] Prompt如何驱动大模型对本地文件实现自主变更:Cline技术深度解析

在AI技术快速发展的今天&#xff0c;编程方式正在经历一场革命性的变革。从传统的"人写代码"到"AI辅助编程"&#xff0c;再到"AI自主编程"&#xff0c;开发效率得到了质的提升。Cline作为一款基于VSCode的AI编程助手&#xff0c;通过其独特的pro…...

DevOps功能详解

DevOps 详解 1. 什么是 DevOps&#xff1f; DevOps 是 Development&#xff08;开发&#xff09; 和 Operations&#xff08;运维&#xff09; 的组合词&#xff0c;代表一种通过 自动化工具、协作文化 和 流程优化 来加速软件开发与交付的 方法论。其核心目标是打破开发与运维…...

忽略 CS8616 警告在 Visual Studio 2022 中【C# 8.0 】

CS8616 警告是 C# 8.0 引入的可空引用类型(NRT)相关警告&#xff0c;表示"由于可空引用类型的特性&#xff0c;某个不可为 null 的字段可能未被初始化"。 编辑项目csproj&#xff0c;直接删除<Nullable>enable</Nullable> 或者修改为disable或者annota…...

[架构之美]一键服务管理大师:Ubuntu智能服务停止与清理脚本深度解析

[架构之美]一键服务管理大师&#xff1a;Ubuntu智能服务停止与清理脚本深度解析 服务展示&#xff1a; 运行脚本&#xff1a; 剩余服务&#xff1a; 一、脚本设计背景与核心价值 在Linux服务器运维中&#xff0c;服务管理是日常操作的重要环节。本文介绍的智能服务管理脚本&a…...

23种设计模式-结构型模式之外观模式(Java版本)

Java 外观模式&#xff08;Facade Pattern&#xff09;详解 &#x1f9ed; 什么是外观模式&#xff1f; 外观模式是结构型设计模式之一&#xff0c;为子系统中的一组接口提供一个统一的高层接口&#xff0c;使得子系统更易使用。 就像是酒店前台&#xff0c;帮你处理入住、叫…...

《数据结构之美--双向链表》

引言 之前我们学习了单链表这一数据结构&#xff0c;虽然单链表的功能比较多&#xff0c;但是也存在着一些局限性&#xff0c;因为在单链表中节点的指向都是单向的&#xff0c;因此我们想从某个节点找到它的上一个节点比较困难&#xff0c;来不及再迷恋单链表了&#xff0c;接…...

如何判断设备是否支持带电插拔——从原理到实操的全面解析

点击下面图片带您领略全新的嵌入式学习路线 &#x1f525;爆款热榜 88万阅读 1.6万收藏 一、带电插拔的核心原理 带电插拔&#xff08;热插拔&#xff09;的本质是通过电气隔离设计和顺序通断控制&#xff0c;避免电流突变对设备造成损害。 • 触点分级设计&#xff1a;支持热…...