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

[计网底层小探索]:实现并部署多线程并发Tcp服务器框架(基于生产者消费者模型的线程池结构)

在这里插入图片描述

文章目录

  • 一.网络层与传输层协议
    • sockaddr结构体继承体系(Linux体系)
    • 贯穿计算机系统的网络通信架构图示:
  • 二.实现并部署多线程并发Tcp服务器框架
    • 线程池模块
    • 序列化反序列化工具模块
    • 通信信道建立模块
    • 服务器主体模块
    • 任务回调模块(根据具体应用场景可重构)
    • Tips:DebugC++代码过程中遇到的问题记录

在这里插入图片描述

一.网络层与传输层协议

  • 网络层与传输层内置于操作系统的内核中,网络层一般使用ip协议,传输层常用协议为Tcp协议和Udp协议,Tcp协议和Udp协议拥有各自的特点和应用场景:
    在这里插入图片描述

sockaddr结构体继承体系(Linux体系)

  • sockaddr_in结构体用于存储网络通信主机进程的ip和端口号等信息
    在这里插入图片描述

贯穿计算机系统的网络通信架构图示:

在这里插入图片描述

二.实现并部署多线程并发Tcp服务器框架

小项目的完整文件的gittee链接

  • Tcp服务器架构:
    在这里插入图片描述

线程池模块

#pragma once
#include <iostream>
#include <pthread.h>
#include "log.hpp"
#include <semaphore.h>
#include <vector>
#include <cstdio>template<class T>
class RingQueue{
private:pthread_mutex_t Clock_;pthread_mutex_t Plock_;sem_t Psem_;sem_t Csem_;std::vector<T> Queue_;int Pptr_;int Cptr_;int capacity_;
public:RingQueue(int capacity = 10) : Queue_(capacity),Pptr_(0),Cptr_(0),capacity_(capacity){sem_init(&Psem_,0,capacity);sem_init(&Csem_,0,0);pthread_mutex_init(&Clock_,nullptr);pthread_mutex_init(&Plock_,nullptr);}~RingQueue(){sem_destroy(&Psem_);sem_destroy(&Csem_);pthread_mutex_destroy(&Clock_);pthread_mutex_destroy(&Plock_);}T Pop(){sem_wait(&Csem_);pthread_mutex_lock(&Clock_);T tem = Queue_[Cptr_];Cptr_++;Cptr_ %= capacity_;pthread_mutex_unlock(&Clock_);sem_post(&Psem_);return tem;}void Push(T t){sem_wait(&Psem_);pthread_mutex_lock(&Plock_);Queue_[Pptr_] = t;Pptr_++;Pptr_%= capacity_;pthread_mutex_unlock(&Plock_);sem_post(&Csem_);}
};
#pragma once
#include "sem_cp.cpp"
#include <pthread.h>
#include <iostream>
#include <string>
#include <mutex>
#include "CalTask.cpp"template<class Task>
class Thread_Pool{struct Thread_Data{int Thread_num;pthread_t tid;};
private:RingQueue<Task> Queue_;  //线程安全的环形队列std::vector<Thread_Data> thread_arr; //管理线程的容器static std::mutex lock_;            //单例锁static Thread_Pool<Task> * ptr_;    //单例指针
private:Thread_Pool(int capacity_Of_queue = 20) : Queue_(capacity_Of_queue){}Thread_Pool(const Thread_Pool<Task>& Tp) = delete;Thread_Pool<Task>& operator=(const Thread_Pool<Task> & Tp) = delete;
public:~Thread_Pool(){}//获取线程池单例-->注意C++的类模板静态成员函数需要在类体外进行定义static Thread_Pool<Task> * Getinstance();//创建多线程void Create_thread(int thread_num = 10){Thread_Data T_data;for(int i = 0 ; i < thread_num ; ++i){//注意线程池对象的this指针传递给线程pthread_create(&T_data.tid,nullptr,Routine,this);T_data.Thread_num = i + 1;thread_arr.push_back(T_data);}}//线程等待void Thread_join(){for(int i = 0 ;i < thread_arr.size() ; ++i){pthread_join(thread_arr[i].tid,nullptr);}}//向线程池中加入任务void Push(Task T){Queue_.Push(T);}void Push(Task && T){Queue_.Push(std::forward<Task>(T));}
private://线程函数-->该函数没有在类外调用,所以无须在类体外定义static void* Routine(void * args){Thread_Pool<Task> * Pool = static_cast<Thread_Pool<Task> *>(args);while(true){std::cout << "Thread prepare to work\n" << std::endl;Task Thread_Task = Pool->Queue_.Pop();//要求Task类重载()-->用于执行具体任务Thread_Task();}return nullptr;}
};//初始化静态指针
template<class Task>
Thread_Pool<Task> * Thread_Pool<Task>::ptr_ = nullptr;
template<class Task>
std::mutex Thread_Pool<Task>::lock_;//注意C++的类模板静态成员函数需要在类体外进行定义
template<class Task>
Thread_Pool<Task> * Thread_Pool<Task>::Getinstance(){if(ptr_ == nullptr){lock_.lock();if(ptr_ == nullptr){ptr_ = new Thread_Pool<Task>;}lock_.unlock();}return ptr_;
}

序列化反序列化工具模块

  • 序列反序列化是保证通信过程中数据完整性的关键步骤,保证数据语义完整,结构完整

在这里插入图片描述

#pragma once
#include <iostream>
#include <string>// 自定义序列化反序列化协议
const std::string blank_space_sep = " ";
const std::string protocol_sep = "\n";
//封装报文
std::string Encode(std::string &content){//报文正文字节数std::string package = std::to_string(content.size());package += protocol_sep;package += content;    //用分隔符封装正文package += protocol_sep;return package;
}//解析报文package-->"正文长度"\n"正文"\n
bool Decode(std::string &package, std::string& content){size_t pos = package.find(protocol_sep);if(pos == std::string::npos) return false;//解析报文正文长度size_t Len = std::atoi(package.substr(0,pos).c_str());//确定报文是否完整size_t total_Len = pos + Len + 2;if(package.size() != total_Len) return false;//获取正文内容content = package.substr(pos+1,Len);package.erase(0,total_Len);return true;
}//用户层协议请求结构体
class Request{
public:int x;int y;char op; 
public:Request(int data1 , int data2 , char op): x(data1),y(data2),op(op){}Request(){}
public://请求结构体 序列化 成报文正文字符串 "x op y"bool Serialize(std::string& out){std::string content = std::to_string(x);content += blank_space_sep;content += op;content += blank_space_sep;content += std::to_string(y);out = content;return true;// 等价的jason代码// Json::Value root;// root["x"] = x;// root["y"] = y;// root["op"] = op;// // Json::FastWriter w;// Json::StyledWriter w;// out = w.write(root);// return true;}//报文正文字符串 反序列化 成请求结构体// "x op y"bool Deserialize(const std::string &in) {size_t left = in.find(blank_space_sep);if(left == std::string::npos)return false;x = std::stoi(in.substr(0,left).c_str());std::size_t right = in.rfind(blank_space_sep);if (right == std::string::npos)return false;y = std::atoi(in.substr(right + 1).c_str());if(left + 2 != right) return false;op = in[left+1];return true;// 等价的jason代码// Json::Value root;// Json::Reader r;// r.parse(in, root);// x = root["x"].asInt();// y = root["y"].asInt();// op = root["op"].asInt();// return true;}void DebugPrint(){std::cout << "新请求构建完成:  " << x << op << y << "=?" << std::endl;}
};//用户层协议请求回应结构体
class Response{
public:int result;int code; 
public:Response(int res , int c): result(res),code(c){}Response(){}
public://请求回应结构体 序列化 成报文正文字符串 "result code"bool Serialize(std::string& out){std::string s = std::to_string(result);s += blank_space_sep;s += std::to_string(code);out = s;return true;// 等价的jason代码// Json::Value root;// root["result"] = result;// root["code"] = code;// // Json::FastWriter w;// Json::StyledWriter w;// out = w.write(root);// return true;}//"result code"//报文正文字符串 反序列化 成请求回应结构体bool Deserialize(const std::string &in) {std::size_t pos = in.find(blank_space_sep);if (pos == std::string::npos)return false;if(pos == 0 || pos == in.size() - 1) return false;result = std::stoi(in.substr(0, pos).c_str());code = std::stoi(in.substr(pos+1).c_str());return true;// 等价的jason代码// Json::Value root;// Json::Reader r;// r.parse(in, root);// result = root["result"].asInt();// code = root["code"].asInt();// return true;}void DebugPrint(){std::cout << "结果响应完成, result: " << result << ", code: "<< code << std::endl;}
};

通信信道建立模块

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>   
#include <sys/socket.h>
#include "log.hpp"
#include <memory.h>
#include <arpa/inet.h>
#include <netinet/in.h>namespace MySocket{//Tcp通讯构建器class TcpServer{enum{UsageError = 1,SocketError,BindError,ListenError,};private:int socketfd_ = -1;std :: string ip_;uint16_t port_;int backlog_ = 10;public:TcpServer(const std::string& ip = "172.19.29.44", uint16_t port = 8081) : ip_(ip) , port_(port){}~TcpServer(){if(socketfd_ > 0) close(socketfd_);}public://确定通信协议,建立文件描述符void BuildSocket(){socketfd_ = socket(AF_INET,SOCK_STREAM,0);if(socketfd_ < 0){lg(Fatal,"socket error,%s\n",strerror(errno));exit(SocketError);}}//文件描述符与服务器ip : 端口号绑定void SocketBind(){struct sockaddr_in addr;memset(&addr,0,sizeof(addr));addr.sin_port = htons(port_);addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(ip_.c_str());if(bind(socketfd_,(const sockaddr*)&addr,sizeof(addr)) < 0){lg(Fatal,"socket bind error,%s\n",strerror(errno));exit(BindError);}lg(Info,"socket bind success\n");}//启动服务监听,等待客户端的连接void Socklisten(){if(socketfd_ <= 0){lg(Fatal,"socket error,%s\n",strerror(errno));exit(SocketError);}if(listen(socketfd_,backlog_) < 0){lg(Fatal, "listen error, %s: %d", strerror(errno), errno);exit(ListenError);}}//服务器接收客户端的连接-->并创建用于通信的文件描述符-->一个客户端连接对应一个文件描述符int SockAccept(std::string& cilent_ip, uint16_t& cilent_port){struct sockaddr_in client_addr;  // 输出型参数,用于获取用户的ip : 端口号memset(&client_addr,0,sizeof(client_addr));socklen_t Len = sizeof(client_addr);int newfd = accept(socketfd_,(struct sockaddr*)&client_addr,&Len);if(newfd < 0){lg(Warning, "accept error, %s: %d", strerror(errno), errno);return -1;}//提取客户端信息-->输出参数char ipstr[64];cilent_ip = inet_ntop(AF_INET,&client_addr.sin_addr,ipstr,sizeof(ipstr));cilent_ip = ipstr;cilent_port = ntohs(client_addr.sin_port);return newfd;}public:int Get_Server_fd(){return socketfd_;}void Close_fd(){if(socketfd_ > 0){close(socketfd_);socketfd_ = -1;}}};
};

服务器主体模块

在这里插入图片描述

#pragma once
#include "ThreadPool.cpp"
#include "TcpServer.cpp"
#include "CalTask.cpp"
#include "log.hpp"
#include <signal.h>//构建计算器服务器
class CalServer{const int size = 2048;
private:Thread_Pool<CalTask> * Pool_ptr_;MySocket::TcpServer Socket_;int Socket_fd_ = -1;
public:CalServer(const std::string& de_ip = "172.19.29.44",uint16_t de_port = 8081): Socket_(de_ip,de_port){Pool_ptr_ = Thread_Pool<CalTask>::Getinstance();if(Pool_ptr_ == nullptr){lg(Fatal,"Pool_ptr_ is nullptr\n");return;}Pool_ptr_->Create_thread();}~CalServer(){}
public://建立Tcp连接条件bool Init(){Socket_.BuildSocket();Socket_fd_ = Socket_.Get_Server_fd();if(Socket_fd_ < 0){lg(Fatal,"BuildSocket failed\n");return true;}Socket_.SocketBind();Socket_.Socklisten();lg(Info, "init server .... done");return true;}//启动服务器void Start(){signal(SIGCHLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);char ReadBuffer[size];while(true){//接受用户请求std::string client_ip;uint16_t client_port;int client_fd = Socket_.SockAccept(client_ip,client_port);if(client_fd < 0){lg(Warning,"SockAccept error\n");continue;}lg(Info, "accept a new link, sockfd: %d, clientip: %s, clientport: %d", client_fd, client_ip.c_str(), client_port);int n = read(client_fd,ReadBuffer,sizeof(ReadBuffer));ReadBuffer[n] = 0;  std::string TaskStr(ReadBuffer);printf("receives mess from client : %s",ReadBuffer);if(n < 0){lg(Warning,"read error\n");break;}CalTask task(client_fd,client_ip,client_port,TaskStr);Pool_ptr_->Push(task);}}
};

任务回调模块(根据具体应用场景可重构)

#pragma once
#include <string>
#include "ThreadPool.cpp"
#include "Protocol.cpp"enum{Div_Zero = 1,Mod_Zero,Other_Oper
};class CalTask{
private:int socketfd_;                //网络通信文件描述符std :: string ip_;            //客户端ipuint16_t port_;               //客户端端口号std::string package_;         //客户请求字符串
public:CalTask(int socketfd,const std::string& ip , uint16_t & port,std::string & str): socketfd_(socketfd),ip_(ip),port_(port),package_(str){}CalTask(){}//类一定要有默认构造函数~CalTask(){}
public://执行计算任务并将结果发送给用户void operator() (){std::cout << "Task Running ... \n" << std::endl;std::string content;//将用户发送的报文进行解包获取正文bool r = Decode(package_, content);if (!r)return;//将报文正文进行反序列化Request req;r = req.Deserialize(content);if (!r)return ;req.DebugPrint();content = ""; //构建计算结果                         Response resp = CalculatorHelper(req);resp.DebugPrint();//计算结果序列化成字符串resp.Serialize(content);//字符串正文封装成报文发送给用户std::string ResStr = Encode(content);write(socketfd_,ResStr.c_str(),ResStr.size());if(socketfd_ > 0)close(socketfd_);}private:Response CalculatorHelper(const Request &req){//构建请求回应结构体Response resp(0, 0);switch (req.op){case '+':resp.result = req.x + req.y;break;case '-':resp.result = req.x - req.y;break;case '*':resp.result = req.x * req.y;break;case '/':{if (req.y == 0)resp.code = Div_Zero;elseresp.result = req.x / req.y;}break;case '%':{if (req.y == 0)resp.code = Mod_Zero;elseresp.result = req.x % req.y;}break;default:resp.code = Other_Oper;break;}return resp;}
};

Tips:DebugC++代码过程中遇到的问题记录

  • 使用C++类模板时,若在类模板中定义了静态成员函数,且该静态成员函数在类外被调用,则该静态成员函数必须定义在类外,不然链接器无法找到函数体.
  • 注意类模板静态成员的声明格式需要加关键字temlpate<>
  • 声明类模板静态成员无需特化模版类型参数
  • 跨主机并发通信测试:
    在这里插入图片描述
    在这里插入图片描述

相关文章:

[计网底层小探索]:实现并部署多线程并发Tcp服务器框架(基于生产者消费者模型的线程池结构)

文章目录 一.网络层与传输层协议sockaddr结构体继承体系(Linux体系)贯穿计算机系统的网络通信架构图示: 二.实现并部署多线程并发Tcp服务器框架线程池模块序列化反序列化工具模块通信信道建立模块服务器主体模块任务回调模块(根据具体应用场景可重构)Tips:DebugC代码过程中遇到…...

Spring Boot 笔记 020 redis集成

1.1 安装redis Windows 下 Redis 安装与配置 教程_redis windows-CSDN博客 2.1 引入redis坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 2.2 配置…...

防火墙——计算机网络

前述基于密码的安全机制不能有效解决以下安全问题&#xff1a; 用户入侵&#xff1a; 利用系统漏洞进行未授权登录&#xff1b; 授权用户非法获取更高级别权限等。 软件入侵&#xff1a; 通过网络传播病毒、蠕虫和特洛伊木马。 拒绝服务攻击等。 解决方法&#xff1a; 防火墙&a…...

用html编写的招聘简历

用html编写的招聘简历 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</tit…...

215数组中的第K个最大元素

215数组中的第K个最大元素 题目描述 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。…...

【动态规划】【矩阵快速幂】LeetCode2851. 字符串转换

作者推荐 【深度优先搜索】【树】【有向图】【推荐】685. 冗余连接 II 涉及知识点 【矩阵快速幂】封装类及测试用例及样例 LeetCode 2851. 字符串转换 给你两个长度都为 n 的字符串 s 和 t 。你可以对字符串 s 执行以下操作&#xff1a; 将 s 长度为 l &#xff08;0 <…...

【LeetCode每日一题】单调栈 402 移掉k位数字

402. 移掉 K 位数字 给你一个以字符串表示的非负整数 num 和一个整数 k &#xff0c;移除这个数中的 k **位数字&#xff0c;使得剩下的数字最小。请你以字符串形式返回这个最小的数字。 示例 1 &#xff1a; 输入&#xff1a;num "1432219", k 3 输出&#xff…...

力扣 309. 买卖股票的最佳时机含冷冻期

题目来源&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/ C题解&#xff1a;动态规划 状态1&#xff1a;表示持有股票。更新为之前持有股票&#xff08;dp[i-1][0]&#xff09;或者不持有股票且不处于冷冻期后买入&…...

2024年刷题记录

马上要开始找实习了&#xff0c;又开始重启刷题计划了&#xff01;加油冲冲冲&#xff01;刷题的顺序follow代码随想录的60天刷题计划&#xff01;感谢FuCosmo的总结&#xff01;之前都是按照C的语法进行刷题的&#xff0c;这次也同样使用C。 Day 1 数组 这些题过年前都刷过了…...

【JGit 】简述及学习资料整理

JGit 介绍 [官网](JGit | The Eclipse Foundation): https://www.eclipse.org/jgit/ 用户指南 : https://github.com/eclipse-jgit/jgit/wiki/User-Guide JGit是一个用于Java编程语言的开源Git实现。它提供了一组Java库和API&#xff0c;使开发人员可以在他们的Java应用程序…...

python数据类型-集合set

1 集合&#xff08;set&#xff09;的定义 1.1 集合是一个无序且不重复元素的序列&#xff1a; 1&#xff09;无序&#xff1a;存储顺序和添加的顺序不一定相同&#xff0c;不支持索引、切片 2&#xff09;元素不重复&#xff1a;当添加重复元素时&#xff0c;集合会自动去重…...

excel如何指定求和

在Excel中&#xff0c;你可以使用函数来实现动态求和&#xff0c;使得当指定行的数值更新后&#xff0c;和也随之更新。具体来说&#xff0c;你可以使用SUM函数结合一些动态的引用方法。以下是一种实现方式&#xff1a; 假设你要对A列&#xff08;从A1到A10&#xff0c;以示例…...

服务端实时推送技术之SSE(Server-Send Events)

文章目录 前言一、解决方案&#xff1a;1、传统实时处理方案&#xff1a;2、HTML5 标准引入的实时处理方案&#xff1a;3、第三方推送&#xff1a; 二、SSE1.引入库1、客户端&#xff1a; 2.服务端&#xff1a;三、业务实践&#xff1a;能否做到精准投递&#xff1f; 总结 前言…...

使用IntelliJ IDEA查看接口的全部实现方法

在大型Java项目中&#xff0c;经常会使用接口和抽象类进行代码设计。为了更好地了解代码结构和功能&#xff0c;我们需要快速查看一个接口的所有实现类。IntelliJ IDEA提供了一些方便的方法来实现这一目标。 1. 点击查看接口的实现子类 在IDEA中&#xff0c;你可以轻松地查看…...

阿里云幻兽帕鲁服务器操作系统类型怎么选择?

使用阿里云服务器搭建幻兽帕鲁操作系统类型选Windows还是Linux&#xff1f;如果对Linux熟悉就选择Linux&#xff0c;相对于windows&#xff0c;Linux更少占用系统资源&#xff1b;如果对Linux不熟悉&#xff0c;首选Windows。事实上&#xff0c;阿里云提供的幻兽帕鲁服务器通过…...

Codeforces Round 927 (Div. 3) LR-remainders的题解

原题描述&#xff1a; C.LR-remains 每次测试时限&#xff1a;2 秒 每次测试的内存限制&#xff1a;256 兆字节 输入&#xff1a;标准输入 输出&#xff1a;标准输出 样例1输入&#xff1a; 4 4 6 3 1 4 2 LRRL 5 1 1 1 1 1 1 LLLLL 6 8 1 2 3 4 5 6 RLLLRR 1 10000 1000…...

HarmonyOS—@Observed装饰器和@ObjectLink嵌套类对象属性变化

Observed装饰器和ObjectLink装饰器&#xff1a;嵌套类对象属性变化 概述 ObjectLink和Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步&#xff1a; 被Observed装饰的类&#xff0c;可以被观察到属性的变化&#xff1b;子组件中ObjectLink装饰器装饰的状…...

The method toList() is undefined for the type Stream

The method toList() is undefined for the type Stream &#xff08;JDK16&#xff09; default List<T> toList() { return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray()))); }...

vue+element (el-progress)标签 隐藏百分比(%) ,反向显示 ,自定义颜色, demo 复制粘贴拿去用

1 效果: 2 页面代码: <el-row :gutter"10" ><el-col :span"12"><el-card ><div class"fourqu"><div><span slot"title">{{推送任务TOP5}}</span></div></div><div class&…...

Android轻量级进程间通信Messenger源码分析

一. 概述 Android中比较有代表性的两大通信机制&#xff1a;1. 线程间Handler通信 2. 进程间Binder通信&#xff0c;本篇文章中我们在理解AIDL原理的基础上来解读一下Messenger的源代码&#xff0c; 并结合示例Demo加深理解。 在看本篇文章前&#xff0c;建议先查阅一下笔者的…...

人脸识别快速上手:Retinaface+CurricularFace镜像教程,简单易学

人脸识别快速上手&#xff1a;RetinafaceCurricularFace镜像教程&#xff0c;简单易学 1. 理解人脸识别黄金组合 在开始动手之前&#xff0c;我们先花两分钟了解Retinaface和CurricularFace这对黄金搭档&#xff1a; Retinaface&#xff1a;就像一位专业的摄影师&#xff0c…...

万象视界灵坛保姆级教程:Bright-Pixel UI下上传图片+输入神谕标签全流程

万象视界灵坛保姆级教程&#xff1a;Bright-Pixel UI下上传图片输入神谕标签全流程 1. 教程概述 万象视界灵坛是一款基于OpenAI CLIP技术的高级多模态智能感知平台&#xff0c;通过独特的Bright-Pixel UI设计&#xff0c;将复杂的图像语义分析转化为直观有趣的交互体验。本教…...

OpenClaw调试进阶:百川2-13B-4bits量化模型响应日志分析

OpenClaw调试进阶&#xff1a;百川2-13B-4bits量化模型响应日志分析 1. 为什么需要关注模型响应日志 上周我在用OpenClaw对接百川2-13B-4bits量化模型时&#xff0c;遇到了一个奇怪的现象&#xff1a;自动化任务执行到一半突然中断&#xff0c;控制台只显示"模型响应异常…...

Pixel Fashion Atelier新手教程:RPG式交互界面操作全图解

Pixel Fashion Atelier新手教程&#xff1a;RPG式交互界面操作全图解 1. 认识像素时装锻造坊 Pixel Fashion Atelier是一款独特的AI图像生成工具&#xff0c;它将传统的AI绘图技术与复古日系RPG游戏界面完美融合。不同于市面上常见的暗色调AI工具&#xff0c;这款应用采用了明…...

2026年Java程序员冲大厂有何经验套路?

前几天&#xff0c;跟个老朋友吃饭&#xff0c;他最近想跳槽去大厂&#xff0c;觉得压力很大&#xff0c;问我能不能分享些所谓的经验套路。每次有这类请求&#xff0c;都觉得有些有趣&#xff0c;不知道你发现没有大家身边真的有很多人不知道怎么面试&#xff0c;也不知道怎么…...

OpenClaw+Qwen2.5-VL-7B省钱方案:自建多模态接口替代GPT-4V

OpenClawQwen2.5-VL-7B省钱方案&#xff1a;自建多模态接口替代GPT-4V 1. 为什么选择本地多模态方案 去年我在开发一个智能内容管理工具时&#xff0c;频繁调用GPT-4V处理截图和文档解析&#xff0c;每月账单轻松突破2000元。最痛心的是&#xff0c;80%的简单图片识别任务其实…...

根据给定文本内容,适合的标题可以是:“‘三泵排水电气控制系统及组态设计的梯形图、接线图原理图”...

自动排水控制设计3泵排水三泵排水电气控制系统排水组态 我们主要的后发送的产品有&#xff0c;带解释的梯形图接线图原理图图纸&#xff0c;io分配&#xff0c;组态画面每逢暴雨天&#xff0c;物业师傅盯着排水泵的手机都要刷出火星子——生怕哪台泵罢工&#xff0c;地下室直…...

Mojo调用PyTorch模型推理却遭遇内存泄漏?——国家级实验室验证的4层内存隔离架构首次公开

第一章&#xff1a;Mojo调用PyTorch模型推理却遭遇内存泄漏&#xff1f;——国家级实验室验证的4层内存隔离架构首次公开在高性能AI边缘部署场景中&#xff0c;Mojo语言通过其零开销FFI机制调用PyTorch C前端&#xff08;LibTorch&#xff09;实现低延迟推理&#xff0c;但实测…...

Electron 14+ 开发必看:WebContentsView 实战指南(含与 BrowserView 对比)

Electron 14 开发实战&#xff1a;WebContentsView 深度解析与性能优化 如果你正在使用 Electron 14 开发跨平台桌面应用&#xff0c;那么 WebContentsView 绝对是你需要重点掌握的核心组件。作为 Electron 团队在 14 版本引入的全新视图系统&#xff0c;WebContentsView 不仅解…...

当SPC焕发新生:云质信息重构制造质量管理新范式

传统SPC&#xff1a;那些让人头疼的“老毛病”说实话&#xff0c;很多企业斥巨资引入的SPC软件&#xff0c;实际使用体验与高级版Excel相差无几。数据需手动导入&#xff0c;图表需逐一点选生成&#xff0c;想要进行跨维度分析&#xff0c;更是要先将数据导出&#xff0c;借助其…...