当前位置: 首页 > 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;企业想提高员工的工作效率…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...