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

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

前言

        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=multiply
    int32_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: // add
                    std::cout << "处理加法请求: " << req.a << " + " << req.b << std::endl;
                    res.result = req.a + req.b;
                    res.success = 1;
                    break;
                case 1: // multiply
                    std::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;
}

效果

相关文章:

  • 【mysql】查事务进程
  • gstreamer之GstVideoDecoder源码剖析
  • Spark DataFrame、Dataset 和 SQL 解析原理深入解析(万字长文多张原理图)
  • 计算机二级web易错点(3)-选择题
  • qwen2.5总览
  • 基于 YOLOv8 的瓷砖缺陷检测:从数据准备到模型部署的全流程实战
  • 探索具身多模态大模型:开发、数据集和未来方向(下)
  • Python----数据分析(Pandas三:一维数组Series的数据操作:数据清洗,数据转换,数据排序,数据筛选,数据拼接)
  • 市长海报/ Mayor‘s posters
  • MySQL 锁
  • 浅谈StarRocks SQL性能检查与调优
  • 判断字符串是否为回文(信息学奥赛一本通-1146)
  • 算法刷题整理合集(四)
  • ai-1 搭建python
  • 熔断和降级的区别,具体使用场景有哪些?
  • 笔试-广度优先搜索BFS-信号强度
  • 手机端Flutter、React Native与原生安卓、iOS交互的方案及设计原理
  • 数据结构与算法-图论-拓扑排序
  • An error occurred: ‘numpy.ndarray‘ object has no attribute ‘clone‘
  • 创建表空间和表
  • 新城市志|上海再攻坚,营商环境没有最好只有更好
  • 上海发布首份直播电商行业自律公约,禁止虚假宣传、商业诋毁
  • 远离军事前线的另一面暗斗:除了“断水”,印度还试图牵制对巴国际援助
  • “仓促、有限”,美英公布贸易协议框架,两国分别获得了什么?
  • 上海楼市“银四”兑现:新房市场高端改善领跑,二手房量价企稳回升
  • 五角大楼要裁一批四星上将