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

序列化结构(protobuf)实现一个TCP服务器(C++)

Protocol Buffers(protobuf)是一种由Google开发的用于序列化结构化数据的方法,通常用于在不同应用程序之间进行数据交换或存储数据。它是一种语言无关、平台无关、可扩展的机制,可以用于各种编程语言和环境中。
1、首先建立proto文件,syntax如果不标明proto3,则会默认使用proto2版本,在后面的使用过程中需要加上包名,以防止命名空间冲突,消息体中的序号表明在序列化数据中该变量出现的顺序。如果要规定该变量只有n中可能,可以使用枚举类型,例如表示人的性别男女。编辑 protoc -I=. --cpp_out=. message.proto
protobuf3文档中文译版

syntax = "proto3";
package csj;
message MyMessage {
int32 id = 1;
string content = 2;
}

2、编写服务端,编辑 g++ -o server server.cpp message.pb.cc -lprotobuf

#include "message.pb.h" // 你的protobuf生成的头文件
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
using namespace std;// 接收protobuf消息
bool ReceiveProtobufMessage(int socket_fd, csj::MyMessage* message) {std::string serialized_message;const int BUFFER_SIZE = 1024; // 设置一个缓冲区大小char buffer[BUFFER_SIZE];ssize_t received = recv(socket_fd, buffer, BUFFER_SIZE, 0);if (received < 0) {std::cerr << "Failed to receive message." << std::endl;return false;}serialized_message.assign(buffer, received);if (!message->ParseFromString(serialized_message)) {std::cerr << "Failed to parse received message." << std::endl;return false;}return true;
}int main() {int server_fd, client_fd;struct sockaddr_in server_addr, client_addr;socklen_t client_len;server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {cerr<<"Error opening socket"<<endl;return 1;}memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(12346);if (bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {cerr<<"Error on binding"<<endl;return 1;}if (listen(server_fd, 5) < 0) {cerr<<"Error on listen"<<endl;return 1;}// std::cout << "Server listening on port " << PORT << std::endl;client_len = sizeof(client_addr);client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_len);if (client_fd < 0) {cerr<<"Error on accept"<<endl;return 1;}// 假设socket_fd是已经建立的socket连接的文件描述符while(true){csj::MyMessage message;if (!ReceiveProtobufMessage(client_fd, &message)) {std::cerr << "Failed to receive protobuf message." << std::endl;return 1;}std::cout << "Received message: " << message.id() << ", " << message.content() << std::endl;}close(client_fd);close(server_fd);return 0;
}

3、编写客户端,编辑 g++ -o client client.cpp message.pb.cc -lprotobuf

#include "message.pb.h" // 你的protobuf生成的头文件
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
using namespace std;// 发送protobuf消息
bool SendProtobufMessage(int socket_fd, const csj::MyMessage& message) {std::string serialized_message;if (!message.SerializeToString(&serialized_message)) {std::cerr << "Failed to serialize message." << std::endl;return false;}ssize_t sent = send(socket_fd, serialized_message.data(), serialized_message.size(), 0);if (sent < 0) {std::cerr << "Failed to send message." << std::endl;return false;}return true;
}int main() {int clientSocket;struct sockaddr_in serverAddress;// 创建套接字clientSocket = socket(AF_INET, SOCK_STREAM, 0);if (clientSocket == -1) {cerr << "Failed to create socket" << endl;return -1;}// 设置服务器地址和端口serverAddress.sin_family = AF_INET;serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");serverAddress.sin_port = htons(12346);// 连接服务器if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {cerr << "Failed to connect to server" << endl;return -1;}// 假设socket_fd是已经建立的socket连接的文件描述符while(true){csj::MyMessage message;cout<<"please enter id:";int id;cin>>id;cout<<"please enter content:";string content;cin>>content;message.set_id(id);message.set_content(content);if (!SendProtobufMessage(clientSocket, message)) {std::cerr << "Failed to send protobuf message." << std::endl;return 1;}}close(clientSocket);return 0;
}

当服务端两次使用同一个端口号,会出现Error on binding,这是同一时间在同一端口上启动两个TCP服务器,第二个服务器会收到端口已被占用的错误,并且无法绑定到该端口上。这是因为操作系统会阻止多个应用程序同时绑定到相同的端口上,以确保网络通信的正确性和稳定性。虽然服务端结束了,但这个接口不会立马就“让”出来,而是过一段时间由OS自动释放

相关文章:

序列化结构(protobuf)实现一个TCP服务器(C++)

Protocol Buffers&#xff08;protobuf&#xff09;是一种由Google开发的用于序列化结构化数据的方法&#xff0c;通常用于在不同应用程序之间进行数据交换或存储数据。它是一种语言无关、平台无关、可扩展的机制&#xff0c;可以用于各种编程语言和环境中。 1、首先建立proto文…...

Python中的list()和map() 用法

list() 在Python中&#xff0c;list() 是一个内置函数&#xff0c;用于创建列表&#xff08;list&#xff09;对象。它有几个不同的用途&#xff0c;但最常见的是将一个可迭代对象&#xff08;如元组、字符串、集合或其他列表&#xff09;转换为一个新的列表。 以下是一些使用…...

公网环境下如何端口映射?

公网端口映射是一种网络技术&#xff0c;它允许将本地网络中的设备暴露在公共互联网上&#xff0c;以便能够从任何地方访问这些设备。通过公网端口映射&#xff0c;用户可以通过互联网直接访问和控制局域网中的设备&#xff0c;而无需在本地网络中进行复杂的配置。 公网端口映射…...

7-36 输入年份和月份

输入一个年份和月份&#xff0c;输出这个月的天数。 输入格式: 输入年份year和月份month&#xff0c;年份和月份中间用一个空格隔开。 输出格式: 输入year年的month月对应的天数。 输入样例: 2000 2输出样例: 29输入样例: 1900 2输出样例: 28输入样例: 1900 6输出样例…...

Linux C++ 023-类模板

Linux C 023-类模板 本节关键字&#xff1a;Linux、C、类模板 相关库函数&#xff1a;getCapacity、getSize 类模板语法 类模板的作用&#xff1a;建立一个通用的类&#xff0c;类中的成员 数据类型可以不具体制定&#xff0c; 用一个虚拟的类型代表语法&#xff1a; templa…...

Android图形显示架构概览

图形显示系统作为Android系统核心的子系统&#xff0c;掌握它对于理解Android系统很有帮助&#xff0c;下面从整体上简单介绍图形显示系统的架构&#xff0c;如下图所示。 这个框架只包含了用户空间的图形组件&#xff0c;不涉及底层的显示驱动。框架主要包括以下4个图形组件。…...

算法学习17:背包问题(动态规划)

算法学习17&#xff1a;背包问题&#xff08;动态规划&#xff09; 文章目录 算法学习17&#xff1a;背包问题&#xff08;动态规划&#xff09;前言一、01背包问题&#xff1a;1.朴素版&#xff1a;&#xff08;二维&#xff09;2.优化版&#xff1a;&#xff08;一维&#xf…...

axios-mock-adapter使用

文章目录 1. 安装 axios-mock-adapter2. 引入所需的库3. 创建一个模拟适配器实例4. 定义模拟响应5. 在你的代码中使用 axios6. 在测试或开发完成后清理模拟 axios-mock-adapter 是一个用于模拟 axios HTTP 请求的库。它允许你在测试或开发过程中&#xff0c;为 axios 实例提供…...

基于单片机的家用无线火灾报警系统设计

摘 要:针对普通家庭的火灾防范需求,设计一种基于单片机的家用无线智能火灾报警系统。该系统主要由传感器、单片机、无线通信模块、GSM 模块、输入显示模块、声光报警电路和GSM 报警电路组成。系统工作时,检测部分单片机判断是否发生火灾,并将信息通过无线通信模块传…...

LangChain:索引(Indexes)--基础知识

引言 在当今信息爆炸的时代&#xff0c;如何高效地获取、处理和利用信息成为了关键。LangChain&#xff0c;作为一种先进的语言模型框架&#xff0c;提供了强大的索引功能&#xff0c;帮助用户更好地管理和应用文本数据。本文将详细介绍LangChain索引中的几个核心组件&#xf…...

Cortex-M4架构

第一章 嵌入式系统概论 1.1 嵌入式系统概念 用于控制、监视或者辅助操作机器和设备的装置&#xff0c;是一种专用计算机系统。 更宽泛的定义&#xff1a;是在产品内部&#xff0c;具有特定功能的计算机系统。 1.2 嵌入式系统组成 硬件 ①处理器&#xff1a;CPU ②存储器…...

对称排序(蓝桥杯)

文章目录 对称排序问题描述模拟 对称排序 问题描述 小蓝是一名软件工程师&#xff0c;他正在研究一种基于交换的排序算法&#xff0c;以提高排序的效率。 给定一个长度为 N 的数组 A&#xff0c;小蓝希望通过交换对称元素的方式对该数组进行排序。 具体来说&#xff0c;小蓝…...

React - 你使用过高阶组件吗

难度级别:初级及以上 提问概率:55% 高阶组件并不能单纯的说它是一个函数,或是一个组件,在React中,函数也可以做为一种组件。而高阶组件就是将一个组件做为入参,被传入一个函数或者组件中,经过一定的加工处理,最终再返回一个组件的组合…...

【C语言】结构体、枚举、联合(自定义类型)

文章目录 前言一、结构体1.结构体的声明2.结构体的自引用3.结构体变量的定义和初始化4.结构体成员的访问5.结构体内存对齐&#xff08;重点&#xff09;6.#pragma修改默认对齐数7.结构体传参 二、位段1.位段的声明2.位段的内存分配3.位段的跨平台问题 三、枚举四、联合 &#x…...

用vue.js写案例——ToDoList待办事项 (步骤和全码解析)

目录 一.准备工作 二.编写各个组件的页面结构 三.实现初始任务列表的渲染 四.新增任务 五.删除任务 六.展示未完成条数 七.切换状态-筛选数据 八.待办事项&#xff08;全&#xff09;代码 一.准备工作 在开发“ToDoList”案例之前&#xff0c;需要先完成一些准备工作&a…...

提高大型语言模型 (LLM) 性能的四种数据清理技术

原文地址&#xff1a;four-data-cleaning-techniques-to-improve-large-language-model-llm-performance 2024 年 4 月 2 日 检索增强生成&#xff08;RAG&#xff09;过程因其增强对大语言模型&#xff08;LLM&#xff09;的理解、为它们提供上下文并帮助防止幻觉的潜力而受…...

Rust 练手小项目:猜数游戏

好久没写 Rust 了&#xff0c;参考《Rust 程序设计语言》写了一下猜数游戏。差不多 40 行&#xff0c;感觉写起来真舒服。 use rand::Rng; use std::{cmp::Ordering, io};fn main() {let secret_number rand::thread_rng().gen_range(0..100);println!("[*] Guess the n…...

蓝桥杯物联网竞赛_STM32L071_16_EEPROM

仍然是没有考过的知识点 朴素的讲就是板子中一块不会因为断电重启而导致数值初始化的一片地址 要注意的是有时候容易把板子什么写错导致板子什么地址写坏了导致程序无法烧录&#xff0c;这个时候记得一直按flash键烧录&#xff0c;烧录时会报错&#xff0c;点击确定&#xff0…...

复习知识点整理

零碎语法 1.导入某个文件夹的index文件&#xff0c;index可以省略&#xff08;这里导入的是router和store文件下的index.js文件&#xff09; 2.路由懒加载 this 1.在vue文件中使用router\store对象时 this&#xff1a;普通函数的this指向vue实例对象(在没有明确指向的时候…...

7款公司电脑监控软件

7款公司电脑监控软件 研究证明&#xff0c;人们在家办公的效率比在办公室办公的效率低一半&#xff0c;其中原因是缺少监督&#xff0c;即便在公司办公&#xff0c;还存在员工偷闲的时刻&#xff0c;比如聊天、浏览无关网站、看剧、炒股等&#xff0c;企业想提高员工的工作效率…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...