一个简单的RPC示例:服务端和客户端

server/2025/3/31 12:09:54/

前言

        RPC相关信息,可自行百度。 以下是在学习阶段的时候,借助AI的力量生成的,用于个人学习使用,无任何版权纠纷。

        运行环境:Linux。

服务端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>#pragma pack(push, 1)
struct Request {uint32_t method_id;  // 0=add, 1=multiplyint32_t a;int32_t b;
};struct Response {int32_t result;uint8_t success; // 1=成功, 0=失败
};
#pragma pack(pop)const int PORT = 8080;int main() {int server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {std::cerr << "Socket创建失败\n";return 1;}sockaddr_in address;address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (sockaddr*)&address, sizeof(address)) < 0) {std::cerr << "绑定失败\n";return 1;}if (listen(server_fd, 3) < 0) {std::cerr << "监听失败\n";return 1;}std::cout << "服务端正在监听端口 " << PORT << std::endl;while (true) {sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int client_fd = accept(server_fd, (sockaddr*)&client_addr, &client_len);if (client_fd < 0) {std::cerr << "接受连接失败\n";continue;}std::cout << "新客户端连接\n";bool keep_connection = true;while (keep_connection) {Request req;ssize_t bytes_received = read(client_fd, &req, sizeof(req));if (bytes_received != sizeof(req)) {if (bytes_received == 0) {std::cout << "客户端关闭连接\n";} else {std::cerr << "读取请求失败,接收字节数: " << bytes_received << std::endl;}keep_connection = false;break;}// 转换网络字节序到主机字节序req.method_id = ntohl(req.method_id);req.a = ntohl(req.a);req.b = ntohl(req.b);Response res;res.success = 0;switch (req.method_id) {case 0: // addstd::cout << "处理加法请求: " << req.a << " + " << req.b << std::endl;res.result = req.a + req.b;res.success = 1;break;case 1: // multiplystd::cout << "处理乘法请求: " << req.a << " * " << req.b << std::endl;res.result = req.a * req.b;res.success = 1;break;default:std::cerr << "未知方法ID: " << req.method_id << std::endl;res.success = 0;break;}// 转换result到网络字节序res.result = htonl(res.result);if (write(client_fd, &res, sizeof(res)) != sizeof(res)) {std::cerr << "发送响应失败\n";keep_connection = false;break;}}close(client_fd);std::cout << "客户端连接已关闭\n";}close(server_fd);return 0;
}

客户端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>#pragma pack(push, 1)
struct Request {uint32_t method_id;int32_t a;int32_t b;
};struct Response {int32_t result;uint8_t success;
};
#pragma pack(pop)const char* SERVER_IP = "127.0.0.1";
const int PORT = 8080;void clear_input() {std::cin.clear();std::cin.ignore(1024, '\n');
}int main() {int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0) {std::cerr << "Socket创建失败\n";return 1;}sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {std::cerr << "地址无效\n";close(sock);return 1;}if (connect(sock, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {std::cerr << "连接失败\n";close(sock);return 1;}while (true) {std::cout << "\n==== RPC 客户端 ====\n";std::cout << "1. 加法运算\n";std::cout << "2. 乘法运算\n";std::cout << "0. 退出\n";std::cout << "请选择操作: ";int choice;if (!(std::cin >> choice)) {std::cerr << "输入无效,请重新输入\n";clear_input();continue;}if (choice == 0) {std::cout << "退出客户端\n";break;}if (choice < 1 || choice > 2) {std::cerr << "无效选项,请重新输入\n";continue;}int a, b;std::cout << "输入第一个操作数: ";if (!(std::cin >> a)) {std::cerr << "输入无效,请重新输入\n";clear_input();continue;}std::cout << "输入第二个操作数: ";if (!(std::cin >> b)) {std::cerr << "输入无效,请重新输入\n";clear_input();continue;}Request req;req.method_id = htonl(static_cast<uint32_t>(choice - 1)); // 转换为0基索引req.a = htonl(a);req.b = htonl(b);if (write(sock, &req, sizeof(req)) != sizeof(req)) {std::cerr << "发送请求失败\n";break;}Response res;if (read(sock, &res, sizeof(res)) != sizeof(res)) {std::cerr << "接收响应失败\n";break;}res.result = ntohl(res.result);if (res.success == 1) {std::cout << "\n计算结果: " << res.result << std::endl;} else {std::cerr << "服务端处理失败\n";}}close(sock);return 0;
}

效果


http://www.ppmy.cn/server/176854.html

相关文章

LeetCode[19]删除链表的倒数第N个节点

思路&#xff1a; 要想一次循环&#xff0c;一趟遍历完&#xff0c;那肯定是要想到双指针了&#xff0c;但是双指针怎么做呢&#xff1f;题目给出删除倒数第N个&#xff0c;我们如果能找到倒数第N个节点的前一个节点就行了&#xff0c;倒数第N个肯定是倒着数&#xff0c;那我们…

基于MNIST数据集完成MindSpore模型训练的入门

1、下载并处理数据集 数据集对于模型训练非常重要&#xff0c;好的数据集可以有效提高训练精度和效率。示例中用到的MNIST数据集是由10类28∗28的灰度图片组成&#xff0c;训练数据集包含60000张图片&#xff0c;测试数据集包含10000张图片。 MindSpore Vision套件提供了用于…

Redis 本地安装

首先安装&#xff1a; https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-from-source/ 进入root目录 tar -xzvf redis-stable.tar.gz cd redis-stable make然后 install sudo make install最后可以直接启动 redis-server但是此时启…

【虚幻引擎UE5】SpawnActor生成Character实例不执行AI Move To,未初始化AIController的原因和解决方法

虚幻引擎版本&#xff1a;5.5.4 问题描述 刚创建的Third Person项目里&#xff0c;定义一个BP_Enemy蓝图&#xff0c;拖拽到场景中产生的实例会追随玩家&#xff0c;但SpawnActor产生的实例会固定不动。BP_Enemy蓝图具体设计如下&#xff1a; BP_Enemy的Event Graph ​​ 又定义…

【redis】在 Spring中操作 Redis

文章目录 基础设置依赖StringRedisTemplate库的封装 运行StringList删库 SetHashZset 基础设置 依赖 需要选择这个依赖 StringRedisTemplate // 后续 redis 测试的各种方法&#xff0c;都通过这个 Controller 提供的 http 接口来触发 RestController public class MyC…

[贪心算法]买卖股票的最佳时机 买卖股票的最佳时机Ⅱ K次取反后最大化的数组和 按身高排序 优势洗牌(田忌赛马)

1.买卖股票的最佳时机 暴力解法就是两层循环&#xff0c;找出两个差值最大的即可。 优化&#xff1a;在找最小的时候不用每次都循环一遍&#xff0c;只要在i向后走的时候&#xff0c;每次记录一下最小的值即可 class Solution { public:int maxProfit(vector<int>& p…

C++11QT复习

文章目录 QT C 培训Day1 环境安装和入门&#xff08;2025.03.05&#xff09;Qt 自带的编译器Qt 的编译脚本&#xff1a;qmake / CMake**示例&#xff1a;Test.pro 文件** Qt 的版本控制系统C 中的头文件C 中的命名空间C 中的编译、链接、运行 Day2 C语法和工程实践&#xff08;…

CAM350-14.6学习笔记-1:导入Gerber文件

CAM350-14.6学习笔记-1:导入Gerber文件 使用自动导入器导入Gerber1&#xff1a;导航栏Home下面的Import——Automatic Import——选择文件路径——Next2&#xff1a;设置每层的类型&#xff1a;3&#xff1a;设置叠层4&#xff1a;弹出层别显示框及Gerber显示 按照Allegro输出的…