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

【Linux网络】构建类似XShell功能的TCP服务器

📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 🏳️‍🌈一、TcpServer.hpp
    • 1.1 基本结构
    • 1.2 多线程处理函数
  • 🏳️‍🌈二、Common.hpp
    • 2.1 基本结构
    • 2.2 构造、析构函数
    • 2.3 SafeCheck()
    • 2.4 Excute()
    • 2.5 HandlerCommand()
  • 🏳️‍🌈三、TcpServer.cpp
  • 🏳️‍🌈四、测试
  • 🏳️‍🌈五、整体代码
    • 5.1 TcpServer.hpp
    • 5.2 TcpServer.cpp
    • 5.3 Command.hpp
  • 👥总结


在上一篇文章中,笔者带大家实现了TCP服务器的 4种 客户端与服务端通信的模式 ,分别是单执行流模式、多进程模式、多线程模式、以及线程池模式

这一篇,我将带大家进一步理解TCP,就从用TCP实现类XShell功能服务器 ,采用的是多线程版本

🏳️‍🌈一、TcpServer.hpp

其他部分保持不变,我们添加一个处理回调函数,用来判断和执行相应的 xshell 命令

1.1 基本结构

using handler_t = std::function<std::string(int sockfd, InetAddr addr)>;class TcpServer{public:// 构造函数TcpServer(handler_t handler,uint16_t port = gport):_handler(handler), _port(port), _isrunning(false){}// 初始化void InitServer(){}// server - 2 多线程版本void Loop(){}// 析构函数~TcpServer(){}private:int _listensockfd; // 监听socketuint16_t _port;bool _isrunning;handler_t _handler;  
};

1.2 多线程处理函数

我们之前使用 Server 进行回显处理,这里将 Execute 函数的处理方法从 Server 改成 _handler就行了

// 线程函数static void* Execute(void* args){ThreadDate* td = static_cast<ThreadDate*>(args);// 子线程结束后由系统自动回收资源,无需主线程调用 pthread_joinpthread_detach(pthread_self()); // 分离新线程,无需主线程回收td->_self->_handler(td->_sockfd, td->_addr);delete td;return nullptr;}

🏳️‍🌈二、Common.hpp

2.1 基本结构

Command 类实现类似于XShell的功能,但是需要注意要让所有命令都可以执行,因为可能会导致删库等相关的问题。成员变量可以使用set容器存储允许执行命令的前缀!

class Command{public:Command(){}bool SafeCheck(const std::string& cmdstr){}std::string Excute(const std::string& cmdstr){}void HandlerCommand(int sockfd, InetAddr addr){}~Command(){}private:std::set<std::string> _safe_command;  // 允许执行的命令
};

2.2 构造、析构函数

根据自己的需要,在构造函数种将允许使用的命令插入到容器析构函数无需处理!

Command() {// 白名单_safe_command.insert("ls");_safe_command.insert("pwd");_safe_command.insert("touch");_safe_command.insert("whoami");_safe_command.insert("which");
}
~Command(){}

2.3 SafeCheck()

检查当前命令是否在白名单中

bool SafeCheck(const std::string& cmdstr){for(auto& cmd : _safe_command){// 值比较命令开头if(strncmp(cmd.c_str(), cmdstr.c_str(), cmd.size()) == 0){return true;}}return false;}

2.4 Excute()

写这部分代码时,我们需要用到一个函数 - popen

popen 的作用是 ​创建子进程执行系统命令,并通过管道(Pipe)与其通信,他会启动子进程,调用 /bin/sh(或其他默认 shell)解析并执行指定的命令(如 ls -l、grep “error” 等)。

std::string Excute(const std::string& cmdstr) {// 检查是否安全,不安全返回if (!SafeCheck(cmdstr)) {return "unsafe";}std::string result;// popen 创建子进程执行系统命令,并通过管道(Pipe)与其通信// popen(const char* command, const char* type)// command: 命令字符串// type: 管道类型,"r"表示读,"w"表示写,"r+"表示读写// 返回文件指针,失败返回NULLFILE* fp = popen(cmdstr.c_str(), "r");if (fp) {// 读取子进程的输出// 一行读取char line[1024];while (fgets(line, sizeof(line), fp)) {result += line;}return result.empty() ? "success" : result; // 有些命令创建无返回值}
}

2.5 HandlerCommand()

命令处理函数是一个长服务(死循环)先接收客户端的信息,如果接收成功则处理收到的消息(命令),并将处理的结果发送给客户端,如果读到文件结尾或者接收失败则退出循环!

void HandlerCommand(int sockfd, InetAddr addr) {// 我们把它当作一个长服务while (true) {char commandbuffer[1024]; // 接收命令的缓冲区// 1. 接收消息// recv(int sockfd, void* buf, size_t len, int flags)// sockfd: 套接字描述符// buf: 接收缓冲区// len: 接收缓冲区大小// flags: 接收标志  0表示阻塞,非0表示非阻塞ssize_t n = ::recv(sockfd, commandbuffer, sizeof(commandbuffer) - 1, 0);if (n > 0) {commandbuffer[n] = 0;LOG(LogLevel::INFO) << "get command from client" << addr.AddrStr()<< ":" << commandbuffer;std::string result = Excute(commandbuffer);// 2. 发送消息// send(int sockfd, const void* buf, size_t len, int flags)// sockfd: 套接字描述符// buf: 发送缓冲区// len: 发送缓冲区大小// flags: 发送标志  0表示不阻塞,非0表示阻塞::send(sockfd, result.c_str(), result.size(), 0);}// 读到文件结尾else if (n == 0) {LOG(LogLevel::INFO) << "client " << addr.AddrStr() << " quit";break;} else {LOG(LogLevel::ERROR) << "read error from client " << addr.AddrStr();break;}}
}

🏳️‍🌈三、TcpServer.cpp

服务端主函数使用智能指针构造Server对象(参数需要加执行方法)然后调用初始化与执行函数,调用主函数使用该可执行程序 + 端口号!

需要注意的是,Command::HandlerCommand 是 ​非静态成员函数,调用时必须通过 Command 类的实例(如 cmdservice)来访问。

#include "TcpServer.hpp"
#include "Command.hpp"int main(int argc, char* argv[]){if(argc != 2){std::cerr << "Usage: " << argv[0] << " port" << std::endl;Die(1);}uint16_t port = std::stoi(argv[1]);Command cmdservice;std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(// &Command::HandlerCommand:成员函数指针。// &cmdservice:Command 对象的实例指针(this 指针)// _1 和 _2:占位符,表示回调函数接受两个参数(int sockfd 和 InetAddr addr)std::bind(&Command::HandlerCommand, &cmdservice, std::placeholders::_1, std::placeholders::_2),port);tsvr->InitServer();tsvr->Loop();return 0;
}

🏳️‍🌈四、测试

在这里插入图片描述

🏳️‍🌈五、整体代码

5.1 TcpServer.hpp

#pragma once#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"#define BACKLOG 8using namespace LogModule;
using namespace ThreadPoolModule;static const uint16_t gport = 8080;using handler_t = std::function<void(int sockfd, InetAddr addr)>;class TcpServer{public:// 构造函数TcpServer(handler_t handler,uint16_t port = gport):_handler(handler), _port(port), _isrunning(false){}// 初始化void InitServer(){// 1. 创建 socket_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);if(_listensockfd < 0){LOG(LogLevel::ERROR) << "create socket error: " << strerror(errno);Die(2);}LOG(LogLevel::INFO) << "create sockfd success: " << _listensockfd;struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = htonl(INADDR_ANY);// 2. 绑定 socketif(::bind(_listensockfd, CONV(&local), sizeof(local)) < 0){LOG(LogLevel::ERROR) << "bind socket error: " << strerror(errno);Die(3);}LOG(LogLevel::INFO) << "bind sockfd success: " << _listensockfd;// 3. 因为 tcp 是面向连接的,tcp需要未来不断地获取连接// listen 就是监听连接的意思,所以需要设置一个队列,来保存等待连接的客户端// 队列的长度为 8,表示最多可以有 8 个客户端等待连接// listen(int sockfd, int backlog)// sockfd 就是之前创建的 socket 句柄// backlog 就是队列的长度// 返回值:成功返回 0,失败返回 -1if(::listen(_listensockfd, BACKLOG) < 0){LOG(LogLevel::ERROR) << "listen socket error: " << strerror(errno);Die(4);}LOG(LogLevel::INFO) << "listen sockfd success: " << _listensockfd;}// server - 2 多线程版本// 为每个新连接分配独立的线程处理业务逻辑// (Loop 函数)通过 accept 循环监听新连接,为每个新连接创建线程(pthread_create)传递连接信息给子线程(通过 ThreadDate 结构体)// (Execute 函数)​​调用 pthread_detach 分离自身(避免主线程调用 pthread_join)执行 Server 函数处理具体业务逻辑线程结束后自动释放资源(通过 delete td)// (Server 函数)​循环读取客户端数据(read),处理业务逻辑(示例中的回显服务),发送响应(write)关闭连接(close(sockfd))void Loop(){_isrunning = true;while(_isrunning){struct sockaddr_in client;socklen_t len = sizeof(client);// 1. 获取新连接int sockfd = ::accept(_listensockfd, CONV(&client), &len);if(sockfd < 0){LOG(LogLevel::ERROR) << "accept socket error: " << strerror(errno);continue;}InetAddr cli(client);LOG(LogLevel::INFO) << "accept new connection from " << cli.AddrStr() << " sockfd: " << sockfd;// 获取成功pthread_t tid;ThreadDate* td = new ThreadDate(sockfd, this, cli);// pthread_create 第一个参数是线程id,第二个参数是线程属性,第三个参数是线程函数,第四个参数是线程函数参数pthread_create(&tid, nullptr, Execute, td);}_isrunning = false;}// 线程函数参数对象class ThreadDate{public:int _sockfd;TcpServer* _self;InetAddr _addr;public:ThreadDate(int sockfd, TcpServer* self, const InetAddr& addr): _sockfd(sockfd), _self(self), _addr(addr){}};// 线程函数static void* Execute(void* args){ThreadDate* td = static_cast<ThreadDate*>(args);// 子线程结束后由系统自动回收资源,无需主线程调用 pthread_joinpthread_detach(pthread_self()); // 分离新线程,无需主线程回收td->_self->_handler(td->_sockfd, td->_addr);delete td;return nullptr;}// 析构函数~TcpServer(){}private:int _listensockfd; // 监听socketuint16_t _port;bool _isrunning;handler_t _handler;  
};

5.2 TcpServer.cpp

#include "TcpServer.hpp"
#include "Command.hpp"int main(int argc, char* argv[]){if(argc != 2){std::cerr << "Usage: " << argv[0] << " port" << std::endl;Die(1);}uint16_t port = std::stoi(argv[1]);Command cmdservice;std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(// &Command::HandlerCommand:成员函数指针。// &cmdservice:Command 对象的实例指针(this 指针)// _1 和 _2:占位符,表示回调函数接受两个参数(int sockfd 和 InetAddr addr)std::bind(&Command::HandlerCommand, &cmdservice, std::placeholders::_1, std::placeholders::_2),port);tsvr->InitServer();tsvr->Loop();return 0;
}

5.3 Command.hpp

#pragma once#include <iostream>
#include <set>
#include <cstring>
#include <cstdio>#include "InetAddr.hpp"
#include "Log.hpp"using namespace LogModule;class Command{public:Command(){// 白名单_safe_command.insert("ls");_safe_command.insert("pwd");_safe_command.insert("touch");_safe_command.insert("whoami");_safe_command.insert("which");}bool SafeCheck(const std::string& cmdstr){for(auto& cmd : _safe_command){// 值比较命令开头if(strncmp(cmd.c_str(), cmdstr.c_str(), cmd.size()) == 0){return true;}}return false;}std::string Excute(const std::string& cmdstr){// 检查是否安全,不安全返回if(!SafeCheck(cmdstr)){return "unsafe";}std::string result;FILE* fp = popen(cmdstr.c_str(), "r");if(fp){char line[1024];while(fgets(line, sizeof(line), fp)){result += line;}return result.empty() ? "success" : result; // 有些命令创建无返回值}return "Execute error";}std::string Excute(std::string& cmdstr){// 检查是否安全,不安全返回if(!SafeCheck(cmdstr)){return "unsafe";}std::string result;// popen 创建子进程执行系统命令,并通过管道(Pipe)与其通信// popen(const char* command, const char* type)// command: 命令字符串// type: 管道类型,"r"表示读,"w"表示写,"r+"表示读写// 返回文件指针,失败返回NULLFILE* fp = popen(cmdstr.c_str(), "r");if(fp){// 读取子进程的输出// 一行读取char line[1024];while(fgets(line, sizeof(line), fp)){result += line;}return result.empty() ? "success" : result; // 有些命令创建无返回值}}void HandlerCommand(int sockfd, InetAddr addr){// 我们把它当作一个长服务while(true){char commandbuffer[1024];   // 接收命令的缓冲区// 1. 接收消息// recv(int sockfd, void* buf, size_t len, int flags)// sockfd: 套接字描述符// buf: 接收缓冲区// len: 接收缓冲区大小// flags: 接收标志  0表示阻塞,非0表示非阻塞ssize_t n = ::recv(sockfd, commandbuffer, sizeof(commandbuffer) - 1, 0);    if(n > 0){commandbuffer[n] = 0;LOG(LogLevel::INFO) << "get command from client" << addr.AddrStr() << ":" << commandbuffer;std::string result = Excute(commandbuffer);// 2. 发送消息// send(int sockfd, const void* buf, size_t len, int flags)// sockfd: 套接字描述符// buf: 发送缓冲区// len: 发送缓冲区大小// flags: 发送标志  0表示不阻塞,非0表示阻塞::send(sockfd, result.c_str(), result.size(), 0);}// 读到文件结尾else if(n == 0){LOG(LogLevel::INFO) << "client " << addr.AddrStr() << " quit";break;}else{LOG(LogLevel::ERROR) << "read error from client " << addr.AddrStr();break;}}}~Command(){}private:std::set<std::string> _safe_command;  // 允许执行的命令
};

👥总结

本篇博文对 【Linux网络】构建类似XShell功能的TCP服务器 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

相关文章:

【Linux网络】构建类似XShell功能的TCP服务器

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…...

Spring Boot 配置源详解(完整版)

Spring Boot 配置源详解&#xff08;完整版&#xff09; 一、配置源加载顺序与优先级 配置源类型优先级顺序&#xff08;从高到低&#xff09;对应配置类/接口是否可覆盖典型文件/来源命令行参数&#xff08;--keyvalue&#xff09;1&#xff08;最高&#xff09;SimpleComman…...

JDK 17 与 Spring Cloud Gateway 新特性实践指南

一、环境要求与版本选择 1. JDK 17 的必要性 最低版本要求&#xff1a;Spring Boot 3.x 及更高版本&#xff08;如 3.4&#xff09;强制要求 JDK 17&#xff0c;以支持 Java 新特性&#xff08;如密封类、模式匹配&#xff09;和性能优化。JDK 17 核心特性&#xff1a; 密封类…...

异构迁移学习(无创脑机接口中的跨脑电帽迁移学习)

本文介绍BCI中的跨脑电帽的迁移学习最新算法。 (发表于2025 arxiv,应该属于投稿阶段,这个场景具有非常不错的研究意义和前景) 最新跨脑电帽异构算法github开源代码 SDDA算法原文 一、脑机接口绪论 脑机接口(BCI)指在人或动物大脑与外部设备之间创建的直接连接,通过脑…...

puppeteer注入浏览器指纹过CDP

一、背景 通过puppeteer爬取目标网站时&#xff0c;经常会被对方网站检测到&#xff0c;比如原生puppeteerCDP特征非常明显&#xff0c;另外指纹如果一直不变&#xff0c;也会引发风控 二、实现 通过以下几行代码即可轻松过大部分检测点&#xff0c;并且能够切换指纹&#x…...

1.8软考系统架构设计师:系统架构设计师概述 - 练习题附答案及超详细解析

系统架构设计师概述综合知识单选题 每道题均附有答案解析&#xff1a; 架构设计师的定义、职责和任务 1、系统架构设计师的核心职责是&#xff1a; A. 编写具体功能模块的代码 B. 制定系统整体架构和技术选型 C. 管理项目预算和进度 D. 直接对接客户进行销售支持 答案&#x…...

软件项目实施全流程及交付物清单

需求分析 -> 概要设计 -> 详细设计 -> 开发实现 -> 测试 -> 部署 -> 运维 一、确认项目目标、范围和团队成员 二、收集和分析客户需求&#xff0c;确定需求规格 三、制定详细的项目计划&#xff0c;包括时间表、资源计划、预算 四、系统架构设计&#xf…...

【2025计算机网络-面试常问】http和https区别是什么,http的内容有哪些,https用的是对称加密还是非对称加密,流程是怎么样的

HTTP与HTTPS全面对比及HTTPS加密流程详解 一、HTTP与HTTPS核心区别 特性HTTPHTTPS协议基础明文传输HTTP SSL/TLS加密层默认端口80443加密方式无加密混合加密&#xff08;非对称对称&#xff09;证书要求不需要需要CA颁发的数字证书安全性易被窃听、篡改、冒充防窃听、防篡改…...

从梯度消失到百层网络:ResNet 是如何改变深度学习成为经典的?

自AlexNet赢得2012年ImageNet竞赛以来&#xff0c;每个新的获胜架构通常都会增加更多层数以降低错误率。一段时间内&#xff0c;增加层数确实有效&#xff0c;但随着网络深度的增加&#xff0c;深度学习中一个常见的问题——梯度消失或梯度爆炸开始出现。 梯度消失问题会导致梯…...

2025.4.26总结

今天把马良老师的《职场十二法则》看完后&#xff0c;感触极大&#xff0c;这们课程就是一场职场启蒙课。 虽然看过不少关于职场的书籍&#xff0c;但大多数是关于职场进阶&#xff0c;方法方面的。并没有解答“面对未来二三十年的职场生涯&#xff0c;我该怎么去看待自己的工…...

Uni-App 多端电子合同开源项目介绍

项目概述 本项目是一款基于 uni-app框架开发的多端电子合同管理平台&#xff0c;旨在为企业及个人用户提供高效、安全、便捷的电子合同签署与管理服务。项目创新性地引入了 “证据链”与“非证据链”两种签署模式&#xff0c;满足不同场景下的签署需求&#xff0c;支持多种签署…...

多语言笔记系列:共享数据

在笔记中共享数据(变量) 使用 .NET 交互式内核&#xff0c;可以在单个笔记本中以多种语言编写代码。为了利用每种语言的不同优势&#xff0c;您会发现在它们之间共享数据很有用。即一种语言的变量&#xff0c;可以在其它语言中使用。 默认情况下&#xff0c;.NET Interactive …...

如何使用SeedProd创建无缝的WordPress维护页面

不管您刚接触 WordPress &#xff0c;还是经验丰富的站长&#xff0c;SeedProd 都是创建网站维护页面的得力助手。通过SeedProd&#xff0c;您可以轻松创建一个与网站风格一致、功能齐全的维护页面&#xff0c;让您的用户在网站维护期间也能感受到您的专业与关怀。本文将为您提…...

使用Python设置excel单元格的字体(font值)

一、前言 通过使用Python的openpyxl库&#xff0c;来操作excel单元格&#xff0c;设置单元格的字体&#xff0c;也就是font值。 把学习的过程分享给大家。大佬勿喷&#xff01; 二、程序展示 1、新建excel import openpyxl from openpyxl.styles import Font wb openpyxl.…...

【PCB工艺】推挽电路及交越失真

推挽电路(Push-Pull Circuit) 推挽电路(Push-Pull Circuit) 是一种常用于功率放大、电机驱动、音频放大等场合的电路结构,具有输出对称、效率高、失真小等优点。 什么是推挽电路? 推挽是指:由两种极性相反的器件(如 NPN 和 PNP、NMOS 和 PMOS)交替导通,一个“推”电…...

告别手动映射:在 Spring Boot 3 中优雅集成 MapStruct

在日常的后端开发中&#xff0c;我们经常需要在不同的对象之间进行数据转换&#xff0c;例如将数据库实体&#xff08;Entity&#xff09;转换为数据传输对象&#xff08;DTO&#xff09;发送给前端&#xff0c;或者将接收到的 DTO 转换为实体进行业务处理或持久化。手动进行这…...

uv run 都做了什么?

uv run 都做了什么&#xff1f; uv run <命令> [参数...] 的主要作用是&#xff1a;在一个由 uv 管理或发现的 Python 虚拟环境中&#xff0c;执行你指定的 <命令>。它会临时配置一个子进程的环境&#xff0c;使其表现得如同该虚拟环境已经被激活一样。这意味着&am…...

求解,如何控制三相无刷电机?欢迎到访评论

问题&#xff1a;通过一个集成的TF2104芯片控制H桥上桥臂和下桥臂&#xff0c;如何控制&#xff1f;还是说得需要PWM_UH和PWM_UL分开控制&#xff1f;...

Java ThreadLocal与内存泄漏

当我们利用 ThreadLocal 来管理数据时&#xff0c;我们不可避免地会面临内存泄漏的风险。 原因在于 ThreadLocal 的工作方式。当我们在当前线程的 ThreadLocalMap 中存储一个值时&#xff0c;一旦这个值不再需要&#xff0c;释放它就变得至关重要。如果不这样做&#xff0c;那么…...

365打卡第R3周: RNN-心脏病预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 &#x1f3e1; 我的环境&#xff1a; 语言环境&#xff1a;Python3.10 编译器&#xff1a;Jupyter Lab 深度学习环境&#xff1a;torch2.5.1 torchvision0…...

1.1.1 用于排序规则的IComparable接口使用介绍

在C#中&#xff0c;IComparable 是一个核心接口&#xff0c;用于定义对象的自然排序规则。实现该接口的类可以指定其实例如何与其他实例比较大小&#xff0c;从而支持排序操作&#xff08;如 Array.Sort()、List.Sort()&#xff09;. 1. 该接口CompareTo返回值含义&#xff1a;…...

【实战】基于强化学习的 Agent 训练框架全流程拆解

一、引言 在人工智能蓬勃发展的今天&#xff0c;强化学习&#xff08;Reinforcement Learning, RL&#xff09;作为让智能体&#xff08;Agent&#xff09;在复杂环境中自主学习并做出最优决策的核心技术&#xff0c;正日益受到关注。从游戏领域中击败人类顶尖选手的 AlphaGo&a…...

【音视频】⾳频处理基本概念及⾳频重采样

一、重采样 1.1 什么是重采样 所谓的重采样&#xff0c;就是改变⾳频的采样率、sample format、声道数等参数&#xff0c;使之按照我们期望的参数输出。 1.2 为什么要重采样 为什么要重采样? 当然是原有的⾳频参数不满⾜我们的需求&#xff0c;⽐如在FFmpeg解码⾳频的时候…...

Prompt 结构化提示工程

Prompt 结构化提示工程 目前ai开发工具都大同小异&#xff0c;随着deepseek的流行&#xff0c;ai工具的能力都差不太多&#xff0c;功能基本都覆盖到了。而prompt能力反而是需要更加关注的&#xff08;说白了就是能不能把需求清晰的输出成文档&#xff09;。因此大家可能需要加…...

设计心得——数据结构的意义

一、数据结构 在老一些的程序员中&#xff0c;可能都听说过&#xff0c;程序其实就是数据结构算法这种说法。它是由尼克劳斯维特在其著作《算法数据结构程序》中提出的&#xff0c;然后在一段时期内这种说法非常流行。这里不谈论其是否正确&#xff0c;只是通过这种提法&#…...

【Pandas】pandas DataFrame rdiv

Pandas2.2 DataFrame Binary operator functions 方法描述DataFrame.add(other)用于执行 DataFrame 与另一个对象&#xff08;如 DataFrame、Series 或标量&#xff09;的逐元素加法操作DataFrame.add(other[, axis, level, fill_value])用于执行 DataFrame 与另一个对象&…...

Pycharm 代理配置

Pycharm 代理配置 文章目录 Pycharm 代理配置1. 设置系统代理1.1 作用范围1.2 使用场景1.3 设置步骤 2. 设置 python 运行/调试代理2.1 作用范围2.2 使用场景2.3 设置步骤 Pycharm 工具作为一款强大的 IDE&#xff0c;其代理配置在实际开发中也是必不可少的&#xff0c;下面介绍…...

GPU 加速库(CUDA/cuDNN)

现代数字图像处理与深度学习任务对计算效率提出极高要求&#xff0c;GPU 加速库通过硬件并行计算能力大幅提升数据处理速度。 一、CUDA 并行计算架构深度解析 1. 架构设计与硬件协同 CPU-GPU 异构计算模型CPU 作为主机端&#xff0c;主要负责逻辑控制、任务调度以及数据预处…...

Spring Native:GraalVM原生镜像编译与性能优化

文章目录 引言一、Spring Native与GraalVM基础1.1 GraalVM原理与优势1.2 Spring Native架构设计 二、原生镜像编译实践2.1 构建配置与过程2.2 常见问题与解决方案 三、性能优化技巧3.1 内存占用优化3.2 启动时间优化3.3 实践案例分析 总结 引言 微服务架构的普及推动了轻量级、…...

JAVA JVM面试题

你的项目中遇到什么问题需要jvm调优&#xff0c;怎么调优的&#xff0c;堆的最小值和最大值设置为什么不设置成一样大&#xff1f; 在项目中&#xff0c;JVM调优通常源于以下典型问题及对应的调优思路&#xff0c;同时关于堆内存参数&#xff08;-Xms/-Xmx&#xff09;的设置逻…...