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

【Linux系统】进程间通信:实现命名管道通信




在这里插入图片描述





认识命名管道通信

命名管道通信的结构图示:


在这里插入图片描述



图中的 ServerClient 是不同的进程, Server 负责发送数据, Client 则是接收数据,进程之间通过命名管道进行数据通信



准备工作:


创建以下文件

Server.hpp  #服务器类的头文件,包含服务器类的声明和各个函数的声明
Server.cc	#服务器类的实现文件,包含Server.hpp中声明的方法的具体实现代码。
Client.hpp	#客户端类的头文件,包含客户端类的声明和各个函数的声明
Client.cc	#客户端类的实现文件,包含Client.hpp中声明的方法的具体实现代码。
Makefile	#构建项目的Makefile文件,定义了编译规则、依赖关系、编译选项等信息,用于自动化编译过程。


Makefile


只能生成一个: 注意,我们需要形成两个可执行文件,而如果只是下面这样写,make 指令从上到下扫描只会形成一个可执行文件就停下了!

SERVER=server
CLIENT=client
CC=g++
SERVER_SRC=Server.cc
Client_SRC=Client.cc$(SERVER):$(SERVER_SRC)$(CC) -o $@ $^ -std=c++11$(CLIENT):$(Client_SRC)$(CC) -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f $(SERVER) $(CLIENT)


若想形成两个可执行文件,则需要加上下面这段:

.PHONY:all
all:$(SERVER) $(CLIENT)

原理:若想形成目标 all, 则需要获取到 $(SERVER) $(CLIENT),则需要执行后面两组操作形成两个可执行文件


SERVER=server
CLIENT=client
CC=g++
SERVER_SRC=Server.cc
Client_SRC=Client.cc.PHONY:all
all:$(SERVER) $(CLIENT)$(SERVER):$(SERVER_SRC)$(CC) -o $@ $^ -std=c++11$(CLIENT):$(Client_SRC)$(CC) -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f $(SERVER) $(CLIENT)


命名管道通信理论


我们两个进程共享同一份文件资源:

这份公共资源:一般要让指定的一个进程先行创建,其他进程再获取该资源并共享使用

  • 创建&&使用
  • 获取&&使用

本次我们会让 Server 进程创建命名管道,Client 进程只需获取并使用该文件



实现命名管道通信


创建命名管道


代码创建管道:本质也是新建文件,使用函数 mkfifo 创建命名管道 FIFO 文件,其中的mode 为创建文件的权限

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


因为共享一个文件,因此我们可以将该共享文件资源的相关信息封装成一个头文件,其实就是共享区域



创建 Comm.hpp


加入该共享文件资源的相关信息:

  • 文件名路径
  • 创建该命名管道需要的 mode

意思是:

Server 进程创建命名管道,需要指定文件路径和文件名,如 ./myfifo ,表示在当前目录下创建一个命名管道名为 myfifo

Client 进程只需获取并使用该文件,也需要指定文件路径和文件名,如 ./myfifo

那么这两个进程都需要使用同一个文件名用于创建或打开该文件,我们可以将该 “同类” 资源放在 Comm.hpp 中,表示 Server 进程和 Client 进程共享这一份即可



创建 Server


(1)由 Server 创建共享命名管道文件

就直接写在构造函数里面:创建命名管道文件

因为命名管道通信的基础是需要一个命名管道,因此, Server 类创建的同时,就应该创建一个命名管道文件,因此可以放于该类的构造函数中

在这里插入图片描述



运行结果当然是成功创建文件

在这里插入图片描述


**优化一下:**既然需要给自定义 mode,则跟着也要将缺省权限:权限掩码清零:umask(0)



(2)由 Server 释放共享命名管道文件

既然 Server 创建该命名管道文件,则也需要由该进程释放该文件

删除该命名文件的程序写法:使用函数 unlink

在这里插入图片描述


删文件的本质:就是在指定目录下,将该文件名和 inode 的映射关系移除,根据 inode 将这个文件的硬链接数 -1,当硬链接数为零时自然就会被系统释放掉该文件所有资源

对于系统命令 rm

当你使用 rm 命令删除一个文件时,实际上是将该文件名从目录中移除,断开了文件名和 inode 之间的映射关系。

这个操作并不会立即删除文件的实际数据,而是减少了该文件的 inode 的硬链接数。


这就是为什么 unlink 也可以用于删除文件


将删除文件的操作放于 Server 的析构函数处:

~Server()
{int ret = ::unlink(gfileName.c_str());if(ret < 0) {std::cerr << "unlink failed!" << '\n';}std::cout << "unlink success" << '\n';
}



建立命名管道的通信,需要先创建一个命名管道,当通信结束后,需要删除该命名管道文件

这些关于命名管道通信的 ”环境配置“ 操作,可以额外封装成一个 Init

注:其实是否需要封装 Init 类 都可以,看自己选择,喜欢原来那样在 Server 类中创建和删除该文件也行



封装 Init


  • 封装到 Init :为了代码直观性,我们将创建和关闭管道的工作封装成一个 Init 类,而不是在 Server 类中
  • 封装 Init 类后,同时定义一个全局变量 Init init :该全局变量生命周期随程序,当程序执行时,文件自动创建,当程序结束时,文件自动销毁,这样更加容易理解
  • Server 还算作文件创建者:这个 Init 类是放到 Server.hpp 中的,意在还是让 Server 作为文件创建者

class Init
{
public:Init(){// 创建共享命名管道文件// int mkfifo(const char *pathname, mode_t mode);umask(0);int ret = ::mkfifo(gfileName.c_str(), gmode);if(ret < 0) {std::cerr << "mkfifo failed!" << '\n';}std::cout << "mkfifo is successfully created" << '\n';sleep(3);}~Init(){int ret = ::unlink(gfileName.c_str());if(ret < 0) {std::cerr << "unlink failed!" << '\n';}std::cout << "unlink success" << '\n';}
};Init init;  // 定义全局变量


Server 类的打开和关闭管道文件

Server 类 和 Client 类本质上就是要读写操作一个管道文件,因此就需要获取该管道文件的 fd,则将 fd 设置为类成员会方便很多

class Server
{
public:Server(): _fd(g_default_fd){}~Server(){}// 打开文件函数bool OpenPipe(){// int open(const char *pathname, int flags);_fd = ::open(gfileName.c_str(), O_RDONLY); // 只读方式打开:默认文件一定存在if (_fd < 0){std::cerr << "open pipe filed !" << '\n';return false;}return true;}// 关闭文件函数void ClosePipe(){if (_fd > 0)::close(_fd);}private: int _fd;
};


Server 类的接收数据函数

Server 需要从命名管道中读取由 Client 发送的数据

// 接收数据函数
// 编程规范
// std::string *: 输出型参数
// const std::string & : 输入型参数
// std::string & : 输入输出型参数
int RecvPipe(std::string *out)
{char buff[1024];// ssize_t read(int fd, void *buf, size_t count);ssize_t n = read(_fd, buff, sizeof(buff)-1); // -1目的:读字符串数据出来最后一位留作 '\0'if(n < 0) {std::cerr << "read pipe filed !" << '\n';return -1;}else if(n > 0){buff[n] = 0;*out = buff;}return n;
}


封装 Client

该类为客户端类,总体上和 Server 类差不多,唯一不同的是: Client 类是写数据的类,会有一个写数据的函数

#pragma once#include "Comm.hpp"class Client
{
public:Client(): _fd(g_default_fd){}~Client(){}// 打开文件bool OpenPipe(){// int open(const char *pathname, int flags);_fd = ::open(gfileName.c_str(), O_WRONLY); // 只写方式打开:作为写端if (_fd < 0){std::cerr << "open pipe filed !" << '\n';return false;}return true;}// 关闭文件void ClosePipe(){if (_fd > 0)::close(_fd);}// 发送数据// std::string & : 输入输出型参数int SendPipe(std::string &in){//ssize_t write(int fd, const void *buf, size_t count);ssize_t n = write(_fd, in.c_str(), in.size());if(n < 0){std::cerr << "write pipe filed !" << '\n';return -1;}return n;}private: int _fd;
};


初步通信


client.cc client 端循环写入

server.cc server 端循环读出



实现通信

client 端没有写入信息,则 server 端阻塞等待数据

在这里插入图片描述



代码演示效果如下:

注意, server 端是读端,负责读取数据与创建管道文件,因此需要先运行 server

然后再运行 client 端,否则 client 端打不开管道文件



解释一下这些程序的使用:client 进程,我们人为手动键盘输入一些字符,回车确认后,在 server 进程就会收到你输入的消息


在这里插入图片描述




关于为什么不能使用 cin

使用 cin >> message; 会遇到一个问题:当输入包含空格的字符串时,cin
只会读取第一个单词,而剩余的部分会留在输入流中。这会导致后续的循环中 cin 继续读取剩余的部分,从而导致 "Please Enter#: " 被连续打印多次。



上面的代码仅仅是一个基本轮廓框架,还有比较多的bug和细节需要填补:


填补细节和修 Bug


1、当我们关闭 client 端时,你会发现 server 端死循环了!!

这是因为,管道文件写端关闭,读端读到 n=0 本应该退出,但是我们的死循环逻辑中没有这个,因此在 server 端的代码中可以加上


while (true)
{cout << "Client Say#: ";int n = server.RecvPipe(&message);if (n > 0){cout << message << '\n';}else {cout << "读取结束!" << '\n';break;}
}
cout << "client quit, me too!" << '\n';

在这里插入图片描述



2、优化细节:封装 server 端 和 client 端重复的 OpenPipe()ClosePipe()

你可以发现 server 端 和 client 端都有一个 OpenPipe()ClosePipe() ,其中的代码大部分是重复的,我们可以将重复的代码抽取出来封装成共享的函数,然后两端调用即可,这样二次封装既减少代码重复,又可以增加可读性


实际的操作: 将重复部分抽取出来封装成 OpenPipe()ClosePipe() ,在 server 类 和 client 类中设计新的 ”专属“ 函数来调用这两个重复的 OpenPipe()ClosePipe() ,如在 serverOpenPipeForRead() 函数中调用 OpenPipe(gForRead)



server

这里的 gForReadopen 函数的选项,定义成了全局数据,后面有具体讲解

// 打开文件
bool OpenPipeForRead()
{_fd = OpenPipe(gForRead);if(_fd < 0) return false;return true;
}// 关闭文件
void ClosePipeRead()
{ClosePipe(_fd);
}


client

这里的 gForWriteopen 函数的选项,定义成了全局数据,后面有具体讲解

// 打开文件
bool OpenPipeForWrite()
{_fd = OpenPipe(gForWrite);if(_fd < 0) return false;return true;
}// 关闭文件
void ClosePipeWrited()
{ClosePipe(_fd);
}



公共代码部分:Comm.hpp

通过定义两种 flags,满足读写端的需求

const int gForRead = O_RDONLY;
const int gForWrite = O_WRONLY;int OpenPipe(int flags)
{// int open(const char *pathname, int flags);int fd = ::open(gfileName.c_str(), flags);if (fd < 0){std::cerr << "open pipe filed !" << '\n';return -1;}return fd;
}// 关闭文件
void ClosePipe(int fd)
{if (fd > 0)::close(fd);
}

管道通信,需要先存在读端,然后写端才能正常运行,若没有读端,则写端不会被打开

若写端打开了,读端关闭了或没打开(即不存在),则写端也会直接被释放!

若读端打开了,写端关闭了或没打开(即不存在),则读端会阻塞等待写端打开并写入数据

因此在管道通信中,需要确保读端优先被打开


3、一个超级细节的点:若读端打开文件时,写端还没打开,读端的 open 函数会阻塞住,等待写端打开文件

观察前面的代码,在管道通信中,我们需要先通过 Server 端读端,创建并打开文件,再通过 Client 端写端打开文件,才能进行读写通信。

对于管道通信,写端关闭,同时读端会读到 n=0 ,则读端关闭



此时就引出一个问题:

问题:在我们前面的代码中, Server 端读端打开文件,而 Client 端写端没有打开文件之前, Server 端的读端不会被系统关闭呢?

答:因为此时 Server 端的读端是阻塞住了!open 函数内部检测到该文件的引用计数为 1(即读端打开),此时不会将读端关闭,因为写端连文件都没打开,又何谈是读端没有读取到数据的问题,写端连文件都没打开,因此就不属于前面讲的管道那种场景(写端关闭&&读端会读到 n=0 则读端关闭)

此时,读端会在 open 函数出阻塞等待,等待第二个进程打开该管道文件,系统知道这个管道文件一定要两个文件打开才能进行通信,因此就需要等待



总结来说:

读端打开文件,写端未打开文件,引用计数 1,open 函数识别到此时文件状态是:只有一个进程操作该文件,则阻塞等待

读端打开文件,写端也打开文件,引用计数 2,open 函数识别到此时文件状态是:有两个进程操作该文件,当写端关闭时,引用计数从 2 变为 1,读端读到 n=0 就关闭管道与读端进程



验证一下:

我在 Server 端打开文件的 open 函数前后都加上一个打印标记

Server server;
cout << "Pos 1" << '\n';
server.OpenPipeForRead();
cout << "Pos 2" << '\n';

在这里插入图片描述


观察动图,你可以发现,当写端 Client 没有启动时, Server 端读端只会打印 Pos 1,而不会打印 Pos 2,说明 Server 端读端阻塞在 open 函数处,而不会继续往后执行

只有当 写端 Client 启动,打开文件后,才会继续打印 Pos 2



完整代码


Client.hpp

#pragma once#include "Comm.hpp"class Client
{
public:Client(): _fd(g_default_fd){}~Client(){}// 打开文件bool OpenPipeForWrite(){_fd = OpenPipe(gForWrite);if(_fd < 0) return false;return true;}// 关闭文件void ClosePipeWrited(){ClosePipe(_fd);}// 发送数据// std::string & : 输入输出型参数int SendPipe(std::string &in){//ssize_t write(int fd, const void *buf, size_t count);ssize_t n = write(_fd, in.c_str(), in.size());if(n < 0){std::cerr << "write pipe filed !" << '\n';return -1;}return n;}private: int _fd;
};


Client.cc

#include<iostream>
#include<cstdio>
#include "Client.hpp"
using namespace std;int main()
{Client client;client.OpenPipeForWrite();string message;while(true){cout << "Please Enter#: ";//cin >> message;//这里不建议使用cin, 当你要输入的命令有空格, cin 将字符串分成好几段,然后读取就有buggetline(std::cin, message);client.SendPipe(message);}client.ClosePipeWrited();return 0;
}


Server.hpp
#pragma once#include "Comm.hpp"class Init
{
public:Init(){// 创建共享命名管道文件// int mkfifo(const char *pathname, mode_t mode);umask(0);int ret = ::mkfifo(gfileName.c_str(), gmode);if (ret < 0){std::cerr << "mkfifo failed!" << '\n';}std::cout << "mkfifo is successfully created" << '\n';sleep(3);}~Init(){int ret = ::unlink(gfileName.c_str());if (ret < 0){std::cerr << "unlink failed!" << '\n';}std::cout << "unlink success" << '\n';}
};Init init; // 定义全局变量class Server
{
public:Server(): _fd(g_default_fd){}~Server(){}// 打开文件bool OpenPipeForRead(){_fd = OpenPipe(gForRead);if(_fd < 0) return false;return true;}// 关闭文件void ClosePipeRead(){ClosePipe(_fd);}// 接收数据// 编程规范// std::string *: 输出型参数// const std::string & : 输入型参数// std::string & : 输入输出型参数int RecvPipe(std::string *out){char buff[1024];// ssize_t read(int fd, void *buf, size_t count);ssize_t n = read(_fd, buff, sizeof(buff)-1); // -1目的:读字符串数据出来最后一位留作 '\0'if(n < 0) {std::cerr << "read pipe filed !" << '\n';return -1;}else if(n > 0){buff[n] = 0;*out = buff;}return n;}private: int _fd;
};



Server.cc
#include <iostream>
#include "Server.hpp"
using namespace std;int main()
{Server server;server.OpenPipeForRead();string message;while (true){cout << "Client Say#: ";int n = server.RecvPipe(&message);if (n > 0){cout << message << '\n';}else {cout << "读取结束!" << '\n';break;}}cout << "client quit, me too!" << '\n';server.ClosePipeRead();return 0;
}


Comm.hpp
#pragma once#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>const std::string gfileName = "./myfifo";
const mode_t gmode = 0600;
const int g_default_fd = -1; // 默认的管道 fd
const int gForRead = O_RDONLY;
const int gForWrite = O_WRONLY;int OpenPipe(int flags)
{// int open(const char *pathname, int flags);int fd = ::open(gfileName.c_str(), flags);if (fd < 0){std::cerr << "open pipe filed !" << '\n';return -1;}return fd;
}// 关闭文件
void ClosePipe(int fd)
{if (fd > 0)::close(fd);
}



Makefile
SERVER=server 
CLIENT=client
CC=g++
SERVER_SRC=Server.cc 
CLIENT_SRC=Client.cc .PHONY:all
all:$(SERVER) $(CLIENT)$(SERVER):$(SERVER_SRC)$(CC) -o $@ $^ -std=c++11
$(CLIENT):$(CLIENT_SRC)$(CC) -o $@ $^ -std=c++11.PHONY:clean 
clean:rm -rf $(SERVER) $(CLIENT)


相关文章:

【Linux系统】进程间通信:实现命名管道通信

认识命名管道通信 命名管道通信的结构图示&#xff1a; 图中的 Server 和 Client 是不同的进程&#xff0c; Server 负责发送数据&#xff0c; Client 则是接收数据&#xff0c;进程之间通过命名管道进行数据通信 准备工作&#xff1a; 创建以下文件 Server.hpp #服务器类的…...

IT服务管理平台(ITSM):构建高效运维体系的基石

IT服务管理平台(ITSM):构建高效运维体系的基石 在数字化转型浪潮的推动下,企业对IT服务的依赖日益加深,如何高效管理和优化IT服务成为企业面临的重要课题。IT服务管理平台(ITSM)应运而生,以其系统化的管理方法和工具,助力企业实现IT服务的规范化、高效化和智能化。本…...

SSM开发(八) MyBatis解决方法重载

目录 一、Mybatis能否支持方法重载? 二、解决 MyBatis 方法重载问题的几种方法 解决方法一: (注解方式) 将重载方法命名为不同的方法名 解决方法二:采用@SelectProvider注解 解决方法三:使用 MyBatis 的 标签和动态 SQL 来构建不同参数的 SQL 查询 三、总结 一、Myb…...

AIGC时代的Vue或React前端开发

在AIGC&#xff08;人工智能生成内容&#xff09;时代&#xff0c;Vue开发正经历着深刻的变革。以下是对AIGC时代Vue开发的详细分析&#xff1a; 一、AIGC技术对Vue开发的影响 代码生成与自动化 AIGC技术使得开发者能够借助智能工具快速生成和优化Vue代码。例如&#xff0c;通…...

【实践案例】使用Dify构建文章生成工作流【在线搜索+封面图片生成+内容标题生成】

文章目录 概述开始节点图片封面生成关键词实时搜索主题参考生成文章详情和生成文章标题测试完整工作流运行测试结果 概述 使用Dify构建文章生成工作流&#xff0c;使用工具包括&#xff1a;使用 Tavily 执行的搜索查询&#xff0c;使用Flux生成封面图片&#xff0c;使用Stable…...

使用 Context API 管理临时状态,避免 Redux/Zustand 的持久化陷阱

在开发 React Native 应用时&#xff0c;我们经常需要管理全局状态&#xff0c;比如用户信息、主题设置、网络状态等。而对于某些临时状态&#xff0c;例如 数据同步进行中的状态 (isSyncing)&#xff0c;我们应该选择什么方式来管理它&#xff1f; 在项目开发过程中&#xff…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.26 统计圣殿:从描述统计到推断检验

1.26 统计圣殿&#xff1a;从描述统计到推断检验 目录 #mermaid-svg-3nz11PRr47fVfGWZ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3nz11PRr47fVfGWZ .error-icon{fill:#552222;}#mermaid-svg-3nz11PRr47fVfGWZ…...

C# 添加、替换、提取、或删除Excel中的图片

在Excel中插入与数据相关的图片&#xff0c;能将关键数据或信息以更直观的方式呈现出来&#xff0c;使文档更加美观。此外&#xff0c;对于已有图片&#xff0c;你有事可能需要更新图片以确保信息的准确性&#xff0c;或者将Excel 中的图片单独保存&#xff0c;用于资料归档、备…...

商密测评题库详解:商用密码应用安全性评估从业人员考核题库详细解析(9)

1. 申请商用密码测评机构需提交材料考点 根据《商用密码应用安全性测评机构管理办法(试行)》,申请成为商用密码应用安全性测评机构的单位应当提交的材料不包括( )。 A. 从事与普通密码相关工作情况的说明 B. 开展测评工作所需的软硬件及其他服务保障设施配备情况 C. 管…...

开源项目Umami网站统计MySQL8.0版本Docker+Linux安装部署教程

Umami是什么&#xff1f; Umami是一个开源项目&#xff0c;简单、快速、专注用户隐私的网站统计项目。 下面来介绍如何本地安装部署Umami项目&#xff0c;进行你的网站统计接入。特别对于首次使用docker的萌新有非常好的指导、参考和帮助作用。 Umami的github和docker镜像地…...

模型I/O功能之模型包装器

文章目录 模型包装器分类LLM模型包装器、聊天模型包装器 截至2023年7月&#xff0c;LangChain支持的大语言模型已经超过了50种&#xff0c;这其中包括了来自OpenAI、Meta、Google等顶尖科技公司的大语言模型&#xff0c;以及各类优秀的开源大语言模型。对于这些大语言模型&…...

免杀国内主流杀软的恶意样本分析

目录下存在愤怒的小鸟.exe和fun.dll文件&#xff0c;最新版火绒&#xff0c;windows defender&#xff0c;腾讯电脑管家&#xff0c;360静态扫描都未发现恶意程序 动态执行&#xff0c;杀软也未拦截 上传到virustotal网站分析恶意程序&#xff0c;只有三个引擎检测出来 die分析…...

Cloudreve:Star22.3k,免费开源的网盘,支持多种存储方式,它允许用户快速搭建个人或团队的私有云存储服务。

嗨&#xff0c;大家好&#xff0c;我是小华同学&#xff0c;关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 Cloudreve是一个基于Web的文件管理和分享系统&#xff0c;它允许用户快速搭建个人或团队的私有云存储服务。该项目以其高度的可定制性和灵活性&#x…...

【高内聚】设计模式是如何让软件更好做到高内聚的?

高内聚&#xff08;High Cohesion&#xff09;是指模块内部的元素紧密协作&#xff0c;共同完成一个明确且相对独立的功能。就像高效的小团队&#xff0c;成员们目标一致&#xff0c;相互配合默契。 低耦合&#xff08;Loose Coupling&#xff09;是指模块之间的依赖较少&#…...

第一个3D程序!

运行效果 CPP #include <iostream> #include <fstream> #include <string> #include <cmath>#include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/…...

基础项目实战——学生管理系统(c++)

目录 前言一、功能菜单界面二、类与结构体的实现三、录入学生信息四、删除学生信息五、更改学生信息六、查找学生信息七、统计学生人数八、保存学生信息九、读取学生信息十、打印所有学生信息十一、退出系统十二、文件拆分结语 前言 这一期我们来一起学习我们在大学做过的课程…...

【PyTorch】6.张量形状操作:在深度学习的 “魔方” 里,玩转张量形状

目录 1. reshape 函数的用法 2. transpose 和 permute 函数的使用 4. squeeze 和 unsqueeze 函数的用法 5. 小节 个人主页&#xff1a;Icomi 专栏地址&#xff1a;PyTorch入门 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&am…...

OpenEuler学习笔记(十六):搭建postgresql高可用数据库环境

以下是在OpenEuler系统上搭建PostgreSQL高可用数据环境的一般步骤&#xff0c;通常可以使用流复制&#xff08;Streaming Replication&#xff09;或基于Patroni等工具来实现高可用&#xff0c;以下以流复制为例&#xff1a; 安装PostgreSQL 配置软件源&#xff1a;可以使用O…...

记录一次Sqoop从MySQL导入数据到Hive问题的排查经过

个人博客地址:记录一次Sqoop从MySQL导入数据到Hive问题的排查经过 | 一张假钞的真实世界 问题描述 MySQL中原始数据有790W+的记录数,在Sqoop抽取作业成功的情况下在Hive中只有500W左右的记录数。 排查过程 数据导入脚本Log 通过Log可以发现以下信息: 该Sqoop任务被分解…...

什么是集成学习

什么是集成学习 集成学习是一种分布式机器学习框架&#xff0c;通过构建多个学习器并将其结合起来完成学习任务。由于在实际应用中单一的学习器往往不能达到理想的学习效果&#xff0c;且有时单一学习器会导致过拟合&#xff0c;因此使用多个学习器进行集成学习往往能够达到更好…...

VSCode+Continue实现AI辅助编程

Continue是一款功能强大的AI辅助编程插件&#xff0c;可连接多种大模型&#xff0c;支持代码设计优化、错误修正、自动补全、注释编写等功能&#xff0c;助力开发人员提高工作效率与代码质量。以下是其安装和使用方法&#xff1a; 一、安装VSCode 参见&#xff1a; vscode安…...

Springboot如何使用面向切面编程AOP?

Springboot如何使用面向切面编程AOP? 在 Spring Boot 中使用面向切面编程&#xff08;AOP&#xff09;非常简单&#xff0c;Spring Boot 提供了对 AOP 的自动配置支持。以下是详细的步骤和示例&#xff0c;帮助你快速上手 Spring Boot 中的 AOP。 1. 添加依赖 首先&#xff…...

ThreadLocal源码解析

文章目录 一、概述二、get()方法三、set()方法四、可能导致的内存泄漏问题五、remove六、思考&#xff1a;为什么要将ThreadLocalMap的value设置为强引用&#xff1f; 一、概述 ThreadLocal是线程私有的&#xff0c;独立初始化的变量副本。存放在和线程进行绑定的ThreadLocalMa…...

Maven的单元测试

1. 单元测试的基本概念 单元测试&#xff08;Unit Testing&#xff09; 是一种软件测试方法&#xff0c;专注于测试程序中的最小可测试单元——通常是单个类或方法。通过单元测试&#xff0c;可以确保每个模块按预期工作&#xff0c;从而提高代码的质量和可靠性。 2.安装和配…...

深度学习 Pytorch 深层神经网络

在之前已经学习了三种单层神经网络&#xff0c;分别为实现线性方程的回归网络&#xff0c;实现二分类的逻辑回归&#xff08;二分类网络&#xff09;&#xff0c;以及实现多分类的softmax回归&#xff08;多分类网络&#xff09;。从本节开始&#xff0c;我们将从单层神经网络展…...

【python】三帧差法实现运动目标检测

三帧差法是一种常用的运动目标检测方法&#xff0c;它通过比较连续三帧图像之间的差异来检测运动物体。这种方法尤其适用于背景变化较小的场景。 目录 1 方案 2 实践 ① 代码 ② 效果图 1 方案 具体步骤如下&#xff1a; ① 读取视频流&#xff1a;使用cv2.VideoCapture()…...

机器人抓取与操作经典规划算法(深蓝)——2

1 经典规划算法 位姿估计&#xff1a;&#xff08;1&#xff09;相机系位姿 &#xff08;2&#xff09;机器人系位姿 抓取位姿&#xff1a;&#xff08;1&#xff09;抓取位姿计算 &#xff08;2&#xff09;抓取评估和优化 路径规划&#xff1a;&#xff08;1&#xff09;笛卡…...

WGCLOUD服务器资源监控软件使用笔记 - Token is error是什么错误

[wgcloud-agent]2025/01/30 10:41:30 WgcloudAgent.go:90: 主机监控信息上报server开始 [wgcloud-agent]2025/01/30 10:41:30 WgcloudAgent.go:99: 主机监控信息上报server返回信息: {"result":"Token is error"} 这个错误是因为agent配置的wgToken和serv…...

在排序数组中查找元素的第一个和最后一个位置(力扣)

一.题目介绍 二.题目解析 使用二分进行查找 2.1处理边界情况 如果数组为空&#xff0c;直接返回 [-1, -1]&#xff0c;因为无法找到目标值。 int[] ret new int[2]; ret[0] ret[1] -1; if (nums.length 0) return ret; 2.2查找左端点&#xff08;目标值开始位置&#…...

Kafka的消息协议

引言 在学习MQTT消息协议的时候我常常思考kafka的消息协议是什么&#xff0c;怎么保证消息的可靠性和高性能传输的&#xff0c;接下来我们一同探究一下 Kafka 在不同的使用场景和组件交互中用到了多种协议&#xff0c;以下为你详细介绍&#xff1a; 内部通信协议 Kafka 使用…...

Vue 3 30天精进之旅:Day 09 - 组合式API

在Vue 3中&#xff0c;组合式API&#xff08;Composition API&#xff09;是一个引入的新特性&#xff0c;它为开发者提供了一种更灵活的方式来构建和组织组件。与传统的选项API相比&#xff0c;组合式API更注重逻辑的复用和逻辑的组合&#xff0c;让我们更容易处理大型应用中的…...

Day28(补)-【AI思考】-AI会不会考虑自己的需求?

文章目录 AI会不会考虑自己的需求&#xff1f;一、**技术本质&#xff1a;深度≠理解**二、**传播机制&#xff1a;热搜如何制造幻觉**三、**伦理考量&#xff1a;为何必须"撇清"**关键结论 AI会不会考虑自己的需求&#xff1f; 让思想碎片重焕生机的灵魂&#xff1a…...

JavaScript 进阶(下)

原型 what 首先&#xff0c;构造函数通过原型分配的函数是所有对象所 共享的。 然后&#xff0c;JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象 这个对象可以挂载函数&#xff0c;对象实…...

selenium自动化测试框架——面试题整理

目录 1. 什么是 Selenium&#xff1f;它的工作原理是什么&#xff1f; 2. Selenium 主要组件 3. 常见 WebDriver 驱动 4. Selenium 如何驱动浏览器&#xff1f; 5. WebDriver 协议是什么&#xff1f; 6. Page Object 模式与 Page Factory 7. 如何判断元素是否可见&#x…...

CF1098F Ж-function

【题意】 给你一个字符串 s s s&#xff0c;每次询问给你 l , r l, r l,r&#xff0c;让你输出 s s s l , r sss_{l,r} sssl,r​中 ∑ i 1 r − l 1 L C P ( s s i , s s 1 ) \sum_{i1}^{r-l1}LCP(ss_i,ss_1) ∑i1r−l1​LCP(ssi​,ss1​)。 【思路】 和前一道题一样&#…...

数据库备份、主从、集群等配置

数据库备份、主从、集群等配置 1 MySQL1.1 docker安装MySQL1.2 主从复制1.2.1 主节点配置1.2.2 从节点配置1.2.3 创建用于主从同步的用户1.2.4 开启主从同步1.2.4 主从同步验证 1.3 主从切换1.3.1 主节点设置只读&#xff08;在192.168.1.151上操作&#xff09;1.3.2 检查主从数…...

电脑要使用cuda需要进行什么配置

在电脑上使用CUDA&#xff08;NVIDIA的并行计算平台和API&#xff09;&#xff0c;需要进行以下配置和准备&#xff1a; 1. 检查NVIDIA显卡支持 确保你的电脑拥有支持CUDA的NVIDIA显卡。 可以在NVIDIA官方CUDA支持显卡列表中查看显卡型号是否支持CUDA。 2. 安装NVIDIA显卡驱动…...

【Unity3D】实现横版2D游戏——攀爬绳索(简易版)

目录 GeneRope.cs 场景绳索生成类 HeroColliderController.cs 控制角色与单向平台是否忽略碰撞 HeroClampController.cs 控制角色攀爬 OnTriggerEnter2D方法 OnTriggerStay2D方法 OnTriggerExit2D方法 Update方法 开始攀爬 结束攀爬 Sensor_HeroKnight.cs 角色触发器…...

JS 时间格式大全(含大量示例)

在 JS 中&#xff0c;处理时间和日期是常见的需求。无论是展示当前时间、格式化日期字符串&#xff0c;还是进行时间计算&#xff0c;JavaScript 都提供了丰富的 API 来满足这些需求。本文将详细介绍如何使用 JavaScript 生成各种时间格式&#xff0c;从基础到高级&#xff0c;…...

opencv裁剪视频区域

import cv2 # 打开视频文件 video_path input.mp4 cap cv2.VideoCapture(video_path) # 获取视频的帧率、宽度和高度 fps int(cap.get(cv2.CAP_PROP_FPS)) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 定义裁剪区…...

C++ deque(1)

1.deque介绍 deque的扩容不像vector那样麻烦 直接新开一个buffer 不用重新开空间再把数据全部移过去 deque本质上是一个指针数组和vector<vector>不一样&#xff0c;vector<vector>本质上是一个vector对象数组&#xff01;并且vector<vector>的buffer是不一…...

MapReduce概述

目录 1. MapReduce概述2. MapReduce的功能2.1 数据划分和计算任务调度2.2 数据/代码互定位2.3 系统优化2.4 出错检测和恢复 3. MapReduce处理流程4. MapReduce编程基础参考 1. MapReduce概述 MapReduce是面向大数据并行处理的计算模型、框架和平台:   1. 基于集群的高性能并行…...

DOM操作中childNodes与children的差异及封装方案

引言 在JavaScript的DOM操作中&#xff0c;childNodes和children是开发者常用的属性&#xff0c;但它们在浏览器中的行为差异可能导致兼容性问题。尤其是在处理空白符&#xff08;如换行符\n&#xff09;时&#xff0c;某些浏览器&#xff08;如Chrome和Edge&#xff09;会将空…...

在线课堂小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

分布式系统架构怎么搭建?

分布式系统架构 互联网企业的业务飞速发展&#xff0c;促使系统架构不断变化。总体来说&#xff0c;系统架构大致经历了单体应用架构—垂直应用架构—分布式架构—SOA架构—微服务架构的演变&#xff0c;很多互联网企业的系统架构已经向服务化网格&#xff08;Service Mesh&am…...

大模型知识蒸馏技术(2)——蒸馏技术发展简史

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl2006年模型压缩研究 知识蒸馏的早期思想可以追溯到2006年,当时Geoffrey Hinton等人在模型压缩领域进行了开创性研究。尽管当时深度学习尚未像今天这样广泛普及,但Hinton的研究已经为知识迁移和模…...

C++初阶 -- 泛型编程(函数模板、类模板)入门

目录 一、泛型编程 1.1 介绍 二、函数模板 2.1 函数模板的概念 2.2 函数模板的格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.4.1 隐式实例化 2.4.2 显式实例化 2.5 模板参数的匹配原则 三、类模板 3.1 类模板的使用格式 3.2 类模板的实例化 一、泛型编程 在有…...

[EAI-027] RDT-1B: a Diffusion Foundation Model for Bimanual Manipulation

Paper Card 论文标题&#xff1a;RDT-1B: a Diffusion Foundation Model for Bimanual Manipulation 论文作者&#xff1a;Songming Liu, Lingxuan Wu, Bangguo Li, Hengkai Tan, Huayu Chen, Zhengyi Wang, Ke Xu, Hang Su, Jun Zhu 论文链接&#xff1a;https://arxiv.org/ab…...

MongoDB常见的运维工具总结介绍

MongoDB 提供了一些强大的运维工具&#xff0c;帮助管理员进行数据库监控、备份、恢复、性能优化等操作。以下是一些常见的 MongoDB 运维工具及其功能介绍&#xff1a; 1. MongoDB Atlas 功能&#xff1a;MongoDB Atlas 是 MongoDB 官方的云托管数据库服务&#xff0c;它提供…...

dify实现原理分析-rag-数据检索的实现

数据检索的总体执行步骤 数据检索总体步骤如下&#xff1a; #mermaid-svg-YCRNdSE7T1d0Etyj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-YCRNdSE7T1d0Etyj .error-icon{fill:#552222;}#mermaid-svg-YCRNdSE7T1d…...