【Linux网络与网络编程】05.应用层自定义协议序列化和反序列化
前言
本篇博客通过网络计算器的实现来帮助各位理解应用层自定义协议以及序列化和反序列化。
一、认识自定义协议&&序列化和反序列化
我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序都是在应用层。前面我们说到:协议是一种 "约定"。socket api 的接口在读写数据时,都是按 "字符串" 的方式来发送接收的。如果我们要传输一些 "结构化的数据" 怎么办呢?
例如,我们需要实现一个服务器版的计算器。我们需要客户端把要计算的两个加数发过去,然后由服务器进行计算,最后再把结果返回给客户端。
约定方案一:
• 客户端发送一个形如"1+1"的字符串
• 这个字符串中有两个整型操作数
• 两个数字之间会有一个字符是运算符
• 数字和运算符之间没有空格
约定方案二:
• 定义结构体来表示我们需要交互的信息
• 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体
这个过程叫做 "序列化" 和 "反序列化"。
无论我们采用方案一还是方案二,抑或是还是其他的方案。只要保证一端发送时构造的数据,在另一端能够正确的进行解析就是可以的。这种约定就是应用层协议。
二、理解 tcp 全双工&&面向字节流
在我们创建sockfd时,操作系统会自动创建两个缓冲区——发送缓冲区和接收缓冲区。所以,发送消息的本质是把数据拷贝到发送缓冲区,接收消息的本质就是把数据从接收缓冲区拷贝拿到。而这两个动作是可以同时进行的,即TCP全双工。
源码剖析:
TCP协议即传输控制协议,它控制着实际数据什么时候发,发多少,出错了怎么办,故而它是面向字节流的。
三、自定义协议实现网络计算器
首先我们需要定制协议+序列化与反序列化。
上面要实现序列化和反序列化,有两种方案:
1. 自己做:x + oper(+ - * /) + y,做空格的字符串分割就行
2. xml && json && protobuf
这里我们为了增加可读性,建议将结构化数据转化为 json(jsoncpp) 的字符串,这篇文章主要是关于第二种方案
//Protocol.hpp
#pragma once
#include <string>
#include <jsoncpp/json/json.h>
#include "Log.hpp"using namespace LogMudule;// 接收
class Request
{
public:Request() = default;Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper){}// 序列化bool Serialize(std::string &out_string){Json::Value root;root["x"] = _x;root["y"] = _y;root["oper"] = _oper;out_string = root.toStyledString();return true;}// 反序列化bool Deserialize(std::string &in_string){Json::Value root;Json::Reader reader;bool parsingSuccessful = reader.parse(in_string, root);if (!parsingSuccessful){LOG(LogLevel::ERROR) << "Failed to parse JSON: " << reader.getFormattedErrorMessages();return false;}_x = root["x"].asInt();_y = root["y"].asInt();_oper = root["oper"].asInt();return true;}int X() const { return _x; }int Y() const { return _y; }int Oper() const { return _oper; }~Request(){}private:int _x;int _y;char _oper;
};// 应答
class Response
{
public:Response() :_result(0),_code(0){}Response(int result, int code) : _result(result), _code(code){}// 序列化bool Serialize(std::string &out_string){Json::Value root;root["result"] = _result;root["code"] = _code;out_string = root.toStyledString();// LOG(LogLevel::DEBUG)<<out_string;return true;}// 反序列化bool Deserialize(std::string &in_string){Json::Value root;Json::Reader reader;bool parsingSuccessful = reader.parse(in_string, root);if (!parsingSuccessful){LOG(LogLevel::ERROR) << "Failed to parse JSON: " << reader.getFormattedErrorMessages();return false;}_result = root["result"].asInt();_code = root["code"].asInt();return true;}int Result() { return _result; }int Code() { return _code; }void SetResult(int result){_result=result;}void SetCode(int code){_code=code;}~Response() {}private:int _result; // 结果int _code; // 错误码
};const static std::string sep = "\r\n";// 封包
bool EnCode(std::string &message, std::string *package)
{if (message.size() == 0)return false;//转成17\r\nmessage\r\n的格式*package = std::to_string(message.size()) + sep + message + sep;return true;
}
// 解包
bool Decode(std::string &package, std::string *content)
{auto pos = package.find(sep);if (pos == std::string::npos)return false;std::string content_length_str = package.substr(0, pos);int content_length = std::stoi(content_length_str);int full_length = content_length_str.size() + content_length + 2 * sep.size();if (package.size() < full_length)return false;*content = package.substr(pos + sep.size(), content_length);// package erasepackage.erase(0, full_length);return true;
}
完成协议的编写之后,我们顺手写我们的计算逻辑:
//Calculator.hpp
#pragma once
#include <string>
#include "Protocol.hpp"class Calculator
{
public:Calculator(){}Response Execute(const Request &req){Response resp;switch (req.Oper()){case '+':resp.SetResult(req.X() + req.Y());break;case '-':resp.SetResult(req.X() - req.Y());break;case '*':resp.SetResult(req.X() * req.Y());break;case '/':{if (req.Y() == 0){resp.SetCode(1); // 1 就是除0}else{resp.SetResult(req.X() / req.Y());}}break;case '%':{if (req.Y() == 0){resp.SetCode(2); // 2 就是mod 0}else{resp.SetResult(req.X() % req.Y());}}break;default:resp.SetCode(3); // 3 用户发来的计算类型,无法识别break;}return resp;}~Calculator(){}
};
接下来编写我们的服务端代码:
这里的服务端教之前的TCP服务端相比只有执行的方法不同,其他并无二异。
//TCPSever.hpp
#pragma once
#include <string>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"using namespace LogMudule;
using namespace ThreadPoolModual;const static uint16_t defaultport = 8888;//回调函数
using work_t =std::function<std::string(std::string&)>;class TCPSever
{void Service(int sockfd){//package充当缓冲区std:: string package;char buff[1024];while(true){int n=::recv(sockfd,buff,sizeof(buff)-1,0);if(n>0){buff[n]=0;package+=buff;//必须是+=,这样才能保证发送过来的数据被加入到缓冲区//读取到的数据计算返回结果std::string result=_work(package);if(result.empty()) continue;//这里表明上面的报文不完整没法解析::send(sockfd,result.c_str(),result.size(),0);}else if(n==0){//表示读到了文件末尾LOG(LogLevel::INFO)<<"Client Quit……";break;}else{LOG(LogLevel::ERROR)<<"read error";break;}}}// 线程分离管理struct ThreadData{int _sockfd;TCPSever *_self;};static void *Handler(void *args){pthread_detach(pthread_self());ThreadData *data = (ThreadData *)args;data->_self->Service(data->_sockfd);return nullptr;}public:TCPSever(work_t work ,uint16_t port = defaultport) : _work(work),_addr(port){// 创建套接字int n = _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (n < 0){LOG(LogLevel::FATAL) << "socket failed";exit(1);}LOG(LogLevel::INFO) << "socket succeed";// 绑定n = ::bind(_listensockfd, _addr.NetAddr(), _addr.Len());if (n < 0){LOG(LogLevel::FATAL) << "bind failed";exit(1);}LOG(LogLevel::INFO) << "bind succeed";// 开始监听n = ::listen(_listensockfd, 5);if (n < 0){LOG(LogLevel::FATAL) << "listen failed";exit(1);}LOG(LogLevel::INFO) << "listen succeed";}void Run(){while (true){// 获取连接struct sockaddr_in connected_addr;socklen_t len = sizeof(connected_addr);int sockfd = ::accept(_listensockfd, (struct sockaddr *)&connected_addr, &len);if (sockfd < 0){LOG(LogLevel::ERROR) << "accept failed";continue;}InetAddr peer(connected_addr);LOG(LogLevel::INFO) << "accept succeed connected is " << peer.Addr() << " sockfd is " << sockfd;ThreadData *data = new ThreadData;data->_sockfd = sockfd;data->_self = this;pthread_t tid;pthread_create(&tid, nullptr, Handler, data);}}~TCPSever(){::close(_listensockfd);}private:int _listensockfd;InetAddr _addr;work_t _work;
};
而服务端的主函数这里我们需要注入执行方法:
//TCPSever.cc
#include "TCPSever.hpp"
#include "Protocol.hpp"
#include "Calculator.hpp"std::string Work(std::string& package)
{std::string message;std::string ret;//解包,循环获取直到不能解析为止while(Decode(package,&message)){if(message.empty()) break;//反序列化Request req;if(!req.Deserialize(message))break;//计算结果Response res=Calculator().Execute(req);//序列化res.Serialize(message);//封包EnCode(message,&message);//添加到结果缓存ret+=message;}return ret;
}int main()
{std::unique_ptr<TCPSever> ts_ptr = std::make_unique<TCPSever>(Work);ts_ptr->Run();return 0;
}
完成服务端之后我们继续客户端的编写,这里我将前面的客户端代码进行抽离,头文件中仅仅增加了执行方法的注入,由主函数传递方法交由Run函数执行:
//TCPClient.hpp
#pragma once
#include <functional>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include "Log.hpp"
#include "InetAddr.hpp"using namespace LogMudule;
const static std::string defaultip="127.0.0.1";
const static int defaultport=8888;using work_t=std::function<void(int)>;class TCPClient
{
public:TCPClient(work_t work,std::string ip,uint16_t port):_work(work),_dst_addr({ip,port}){//创建套接字_sockfd=::socket(AF_INET,SOCK_STREAM,0);if(_sockfd<0){LOG(LogLevel::FATAL)<<"socket failed";exit(1);}LOG(LogLevel::INFO)<<"socket succeed";//不需要绑定}void Run(){int n=::connect(_sockfd,_dst_addr.NetAddr(),_dst_addr.Len());if(n<0){LOG(LogLevel::ERROR)<<"connect failed";exit(3);}LOG(LogLevel::INFO)<<"connect succeed";while(true){_work(_sockfd);}}~TCPClient(){::close(_sockfd);}private:int _sockfd;InetAddr _dst_addr;work_t _work;
};
//TCPClient.cc
#include <memory>
#include "TCPClient.hpp"
#include "Protocol.hpp"void Work(int sockfd)
{// 获取输入int x, y;char oper;std::cout << "Please input x:";std::cin >> x;std::cout << "Please input y:";std::cin >> y;std::cout << "Please input oper:";std::cin >> oper;// 序列化Request req(x, y, oper);std::string package;req.Serialize(package);//封包std::string message;EnCode(package,&message);// 发送消息::send(sockfd, message.c_str(), message.size(), 0);// 接收结果char buff[1024];int n = ::recv(sockfd, buff, sizeof(buff), 0);if (n > 0){buff[n] = 0;std::string result = buff;//解包Decode(result,&message);// 反序列化Response res;res.Deserialize(message);LOG(LogLevel::DEBUG)<<"result:"<<res.Result()<<":code:"<<res.Code();}
}int main(int argc, char *argv[])
{if (argc != 3){std::cout << "Usgae Error" << std::endl;exit(-1);}std::string ip = argv[1];uint16_t port = std::stoi(argv[2]);std::unique_ptr<TCPClient> c_ptr = std::make_unique<TCPClient>(Work,ip, port);c_ptr->Run();return 0;
}
其实编写实现之后我们发现其逻辑不过如下图:
相关文章:
【Linux网络与网络编程】05.应用层自定义协议序列化和反序列化
前言 本篇博客通过网络计算器的实现来帮助各位理解应用层自定义协议以及序列化和反序列化。 一、认识自定义协议&&序列化和反序列化 我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序都是在应用层。前面我们说到:协议是一种…...
搭建K8S-1.23
0、简介 这里只用3台服务器来做一个简单的集群 地址主机名192.168.160.40kuber-master-1192.168.160.41kuber-master-2192.168.160.42kuber-node-1 1、关闭三个服务 (1)防火墙 systemctl stop firewalld (2)Selinux setenf…...
解决Spring Boot Test中的ByteBuddy类缺失问题
目录 解决Spring Boot Test中的ByteBuddy类缺失问题前奏问题描述问题解决第一步:移除ByteBuddy的特定版本号第二步:更新maven-surefire-plugin配置第三步:清理并重新构建项目 结语 解决Spring Boot Test中的ByteBuddy类缺失问题 前奏 今天&…...
npm 项目命名规则
以下是 npm 项目命名规则的详细说明: 一、核心命名规则 必须使用小写字母 名称中不能包含大写字母。原因: 跨平台兼容性(如 Linux 区分大小写,而 Windows 不区分)。避免命令行和 URL 中的大小写冲突(例如包…...
#SVA语法滴水穿石# (012)关于 first_match、throughout、within 的用法
我们今天学习, SystemVerilog 断言(SVA)中 first_match、throughout、within 运算符。 1. first_match 定义与作用 功能:在可能产生 多个匹配结果 的复合序列(如 or 或重复操作符)中,仅选择第…...
基于springboot+vue的二手车交易系统
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...
洛谷P11999.投入严厉地本地
洛谷P11999.投入严厉地本地 题目 题目解析及思路 题目要求根据两个字符串s和t,反推出一个映射集合f,其中s的每一个长度为k的子串都可以映射成单个字符或空字符 算出最终映射集合有多少个空字符,用全排列函数去搜索所有情况,判断…...
低代码开发平台:飞帆中新增控件、修改他人控件
飞帆是一个自由的控件平台。所有的网页都由控件搭建而成。 在我的资源、我的控件中,点击新增可以新增控件 对于他人的控件,点击复制控件展开,点击复制到我的控件 飞帆中的控件是使用 Vue2 来实现的...
Openstack指南
什么是云计算 概念 云计算是一种基于互联网的计算方式,通过这种方式,共享的软硬件资源和信息,可以按需求提供给计算机和其他设备。用户不需要了解”云“中的基础设施细节,不必具有相应的专业知识,也无需直接控制。云…...
[自制调试工具]构建高效调试利器:Debugger 类详解
一、引言 在软件开发的漫漫征程中,调试就像是一位忠诚的伙伴,时刻陪伴着开发者解决代码里的各类问题。为了能更清晰地了解程序运行时变量的状态,我们常常需要输出各种变量的值。而 Debugger 类就像是一个贴心的调试助手,它能帮我…...
【网络IP】原生IP是什么?如何获取海外原生IP?
一、什么是原生IP 原生IP地址是互联网服务提供商(ISP)直接分配给用户的真实IP地址,无需代理或转发。这类IP的注册国家与IP所在服务器的注册地相符。这种IP地址直接与用户的设备或网络关联,不会被任何中间服务器或代理转发或隐藏。…...
【小沐学Web3D】three.js 加载三维模型(React Three Fiber)
文章目录 1、简介1.1 Three.js1.2 React Three Fiber 2、测试2.1 初始化环境2.2 app.js修改(显示内置立方体)2.3 app.js修改(显示内置球体)2.4 app.js修改(显示自定义立方体)2.5 app.js修改(显示…...
HTTP查询参数示例(XMLHttpRequest查询参数)(带查询参数的HTTP接口示例——以python flask接口为例)flask查询接口
文章目录 HTTP查询参数请求示例接口文档——获取城市列表代码示例效果 带查询参数的HTTP接口示例——以python flask接口为例app.pyREADME.md运行应用API示例客户端示例关键实现说明:运行方法: HTTP查询参数请求示例 接口文档——获取城市列表 代码示例…...
【玩泰山派】1、mac上使用串口连接泰山派
文章目录 前言picocom工具连接泰山派安装picocom工具安装ch340的驱动串口工具接线使用picocom连接泰山派 参考 前言 windows上面有xshell这个好用的工具可以使用串口连接板子,在mac上好像没找到太好的工具,只能使用命令行工具去搞了。 之前查找说mac上…...
【玩泰山派】0、mac utm安装windows10
文章目录 前言安装过程utm安装下载windows ios镜像安装windows系统解决共享文件夹拷贝受限问题 参考 前言 使用mac开发泰山派,但是买的泰山派没有emmc,只有sd卡,要使用瑞芯微的sd卡烧录工具,这个工具好像只支持windows࿰…...
html 给文本两端加虚线自适应
效果图: <div class"separator">文本 </div>.separator {width: 40%;border-style: dashed;display: flex;align-items: center;color: #e2e2e2;font-size: 14px;line-height: 20px;border-color: #e2e2e2;border-width: 0; }.separator::bef…...
Android学习总结之应用启动流程(从点击图标到界面显示)
一、用户交互触发:Launcher 到 AMS 的跨进程通信 1. Launcher 处理点击事件(应用层) 当用户点击手机桌面上的应用图标时,Launcher(桌面应用)首先捕获点击事件。每个图标对应一个启动 Intent(通…...
Vue2与Vue3不同
Vue3 设计思想与核心变化详解 一、Vue3 设计思想与 Vue2 差异对比 响应式系统重构Vue2 实现(基于 Object.defineProperty) // 在 Vue2 中,通过 data 选项返回一个对象,对象中的属性会被 Object.defineProperty 转换为响应式数据…...
《Java实战:素数检测算法优化全解析——从暴力枚举到筛法进阶》
文章目录 摘要一、需求分析二、基础实现代码与问题原始代码(暴力枚举法)问题分析 三、优化版代码与解析优化1:平方根范围剪枝优化2:偶数快速跳过完整优化代码 四、性能对比五、高阶优化:埃拉托斯特尼筛法算法思想代码实…...
解决报错:node:internal/errors:496 ErrorCaptureStackTrace(err);
报错信息 我使用npm init vuelatest创建项目时出现如下报错 node:internal/errors:496 ErrorCaptureStackTrace(err); ^ TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module “file:///D:/develop/nodejs/node_cache/_npx/2f7e7bff16d1c534/node_modules/create-vue/loc…...
【Linux笔记】进程管理章节笔记
一、进程与线程的概念 1、进程 1)概念 进程是程序的执行实例,拥有独立的资源(如内存、文件描述符等)。每个进程在创建时会被分配唯一的进程ID,即为PID,也叫进程编号。 2)特点 资源隔离&#…...
使用Webpack搭建React项目:从零开始
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 🍚 蓝桥云课签约作者、…...
使用Cusor 生成 Figma UI 设计稿
一、开发环境 系统:MacOS 软件版本: Figma(网页或APP版) 注:最好是app版,网页版figma 没有选项 import from manifest app下载地址:Figma Downloads | Web Design App for Desktops & …...
前端 vs 后端:技术分工详解——从用户界面到系统逻辑的全解析
前端(Frontend) 和 后端(Backend) 是软件开发中两个核心概念,分别对应用户直接交互的部分和系统背后的逻辑处理部分。它们共同构成完整的应用程序,但分工不同。 目录 一、前端(Frontend…...
CentOS 7上配置SQL Server链接其他SQL Server服务器
概述 本文介绍在CentOS 7系统上运行的SQL Server如何链接访问其他SQL Server服务器的详细步骤,包括驱动安装、配置和连接测试。 安装必要组件 1. 安装ODBC驱动 # 安装基础ODBC组件 sudo yum install unixODBC unixODBC-devel# 添加Microsoft仓库 curl https://p…...
Scade One - 将MBD技术从少数高安全领域向更广泛的安全嵌入式软件普及
Scade One是继Scade Suite version 6自2008年起发展近20年后的首次主要改进版本。在Scade One发布的同时,Scade团队发布了一系列介绍Scade One的博客。本篇Scade One - Democratizing model-based development是其中的一部分。在后面的内容中,将复述博客…...
第十二章:容器间网络_《凤凰架构:构建可靠的大型分布式系统》
第十二章 容器间网络 一、Linux网络虚拟化基础 1. 网络命名空间(Network Namespace) 隔离网络栈:每个网络命名空间拥有独立的IP地址、路由表、防火墙规则等网络配置。实现方式:通过ip netns命令管理,容器启动时自动创…...
详解七大排序
目录 一.直接插入排序 (1)基本思想 (2)算法步骤 (3)代码实现 (4)算法特性 (5)算法优化 (6)示例演示 二.希尔排序 (…...
第八章 Python基础进阶-数据可视化(终)
此章节练习主要分为:折线图、地图、柱状图,若用户只是学习Python的基础语法知识,可以不看此章节。 主要是讲解第三方包PyEcharts技术,Python数据的可视化操作。 一.json数据格式 json的概念: (1&#x…...
【Hadoop3.1.4】完全分布式集群搭建
一、虚拟机的建立与连接 1.建立虚拟机 详情见【Linux】虚拟机的安装 把上面三个参数改掉 2.连接虚拟机 具体见【Linux】远程连接虚拟机防火墙 二、修改主机名 在Centos7中直接使用root用户执行hostnamectl命令修改,重启(reboot)后永久生…...
NLP简介及其发展历史
自然语言处理(Natural Language Processing,简称NLP)是人工智能和计算机科学领域中的一个重要分支,致力于实现人与计算机之间自然、高效的语言交流。本文将介绍NLP的基本概念以及其发展历史。 一、什么是自然语言处理?…...
Java异步编程中的CompletableFuture介绍、常见错误及最佳实践
一、Future接口的局限性 Java 5引入的Future接口为异步编程提供了基础支持,但其设计存在明显局限性,导致复杂场景下难以满足需求: 阻塞获取结果 必须通过future.get()阻塞线程等待结果,无法实现真正的非阻塞: Executo…...
基于FLask的共享单车需求数据可视化分析系统
【FLask】基于FLask的共享单车需求数据可视化分析系统 (完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统能够整合并处理大量共享单车使用数据,通过直观的可视化手段࿰…...
vue2项目中,多个固定的请求域名 和 通过url动态获取到的ip域名 封装 axios
vue2 使用场景:项目中,有固定的请求域名,而有某些接口是其他域名 /utils/request.js 固定请求域名 import axios from axios import Vue from vuelet baseURL switch (window.location.hostname) {case localhost: // 本地case 127.0.0.1…...
【嵌入式学习3】基于python的tcp客户端、服务器
目录 1、tcp客户端 2、tcp服务器 3、服务器多次连接客户端、多次接收信息 1、tcp客户端 """ tcp:客户端 1. 导入socket模块 2. 创建socket套接字 3. 建立tcp连接(和服务端建立连接) 4. 开始发送数据(到服务端) 5. 关闭套接字 """ import soc…...
tomcat构建源码环境
一. IDEA运行Tomcat8源码 参考网址:https://blog.csdn.net/yekong1225/article/details/81000446 Tomcat作为J2EE的开源实现,其代码具有很高的参考价值,我们可以从中汲取很多的知识。作为Java后端程序员,相信有很多人很想了解…...
你用的是Bing吗?!
🔥【深度解析】微软Bing革命性升级!Copilot Search上线:从此搜索≠找链接,而是直接生成答案! 💡 你是否厌倦了这样的搜索体验? 搜索「Python处理JSON」,在10个网页间反复跳转想对比…...
拍摄的婚庆视频有些DAT的视频文件打不开怎么办
3-12 现在的婚庆公司大多提供结婚的拍摄服务,或者有一些第三方公司做这方面业务,对于视频拍摄来说,有时候会遇到这样一种问题,就是拍摄下来的视频文件,然后会有一两个视频文件是损坏的,播放不了࿰…...
Oracle Cloud (OCI) 服务器最新控制台启用 IPv6 超详细图文指南(2025最新实践)
本文为原作者发布到第三方平台,更多内容参考: 🚀 Oracle Cloud (OCI) 服务器最新控制台启用 IPv6 超详细图文指南(2025最新实践) 随着 IPv6 的普及,IPv6的优秀特性能为你的 OCI 云服务器提升网络性能和路由效率,并提升兼容性。本指南将引导你在 Oracle Cloud Infrast…...
YOLO环境搭建,win11+wsl2+ubuntu24+cuda12.6+idea
提示:环境搭建 文章目录 前言一、 win11 gpu 驱动更新1.1 下载驱动3. 验证, 二、配置子系统 ubuntu2.1 安装 cuda 三、配置 anaconda四、idea 配置使用 wsl ubuntu conda 环境 前言 提示:版本 win11 wsl2 ubuntu24 idea 2024 子系统跳过&…...
类 和 对象 的介绍
对象的本质是一种新的数据类型。类是一个模型,对象是类的一个具体化实例。为类创建实例也就是创建对象。 一、类(class) 类决定一个对象将是什么样的(有什么属性、功能)。类和变量一样,有名字。 1.创建类 …...
机器学习(1)—线性回归
文章目录 1. 算法定义2. 模型形式2.1. 简单线性回归(单变量):2.2. 多元线性回归(多变量): 3. 基本原理3.1. 误差函数:3.2. 求解回归系数 4. 假设条件5. 模型评估6. 优缺点7. 扩展方法8. 应用场景…...
macOS下SourceInsight的替代品
macOS 推荐的几款开源、轻量级、且功能类似于 SourceInsight 的源码阅读工具(排除 VS Code): 1. Zeal(离线文档 简单代码导航) 官网/GitHub: https://zealdocs.org/特点: 轻量级离线文档浏览器࿰…...
form实现pdf文件转换成jpg文件
说明: 我希望将pdf文件转换成jpg文件 请去下载并安装 Ghostscript,gs10050w64.exe 配置环境变量:D:\Program Files\gs\gs10.05.0\bin 本地pdf路径:C:\Users\wangrusheng\Documents\name.pdf 输出文件目录:C:\Users\wan…...
聊天室项目之http知识
一.http的核心组成部分(都分成请求的和响应的) 1.起始行:请求------------------------ 方法(Method):GET、POST、PUT、DELETE 等。 请求目标(Request Target):URL 路径…...
kubeadm部署 Kubernetes(k8s) 高可用集群 V1.28.2
1. 安装要求 在开始之前,部署Kubernetes集群机器需要满足以下几个条件: 10台机器,操作系统Openeuler22.03 LTS SP4硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多,docker 数据卷单独挂…...
BUUCTF-web刷题篇(12)
21.easy_tornado Tornado大致可以分为四个主要组成部分: 一个web框架(包括RequestHandler创建Web应用程序的子类,以及各种支持类)。 HTTPServerHTTP(和AsyncHTTPClient)的客户端和服务器端实现。 一个异…...
基于 Netty 框架的 Java TCP 服务器端实现,用于启动一个 TCP 服务器来处理客户端的连接和数据传输
代码: package com.example.tpson_tcp;import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; imp…...
【Kafka基础】Kafka配置文件关键参数解析与单机生产环境配置指南
1 Kafka配置文件概述 Apache Kafka的配置文件是控制其行为的关键所在,合理的配置能够显著提升性能、可靠性和可维护性。Kafka主要涉及两个核心配置文件: server.properties:Broker主配置文件zookeeper.properties:ZooKeeper配置文…...
Kafka 漏消费和重复消费问题
Kafka 虽然是一个高可靠、高吞吐的消息系统,但如果使用不当,**“漏消费”和“重复消费”**问题是非常容易发生的,尤其在业务系统中会造成数据丢失、重复写库等严重问题。 🎯 一句话理解: Kafka 本身提供 “至多一次”…...