从零实现一个RPC框架:远程调用与服务治理

前言

你有没有想过:在一个大型系统中,订单服务怎么调用用户服务的函数?它们在不同的服务器上,甚至用不同语言写的。

RPC(Remote Procedure Call) 让远程调用像本地调用一样简单。

今天我们用C语言从零实现一个RPC框架:

· 服务注册与发现

· 序列化/反序列化(自定义协议)

· 网络传输(TCP)

· 客户端代理生成

· 负载均衡(轮询/随机)

· 超时重试机制


一、RPC核心原理

  1. RPC调用流程

```

┌─────────┐ ┌─────────┐ ┌─────────┐

│ 客户端 │ 1.调用 │ 客户端 │ 2.编码 │ 网络 │

│ 业务代码 │ ─────→ │ 代理 │ ─────→ │ 传输 │

└─────────┘ └─────────┘ └────┬────┘

│ 3.网络

┌─────────┐ ┌─────────┐ ┌────┴────┐

│ 服务端 │ 5.执行 │ 服务端 │ 4.解码 │ 网络 │

│ 业务代码 │ ←───── │ 存根 │ ←───── │ 传输 │

└─────────┘ └─────────┘ └─────────┘

```

  1. 核心组件

组件 作用

序列化 把参数变成字节流

反序列化 把字节流变回参数

服务注册 服务提供方注册到注册中心

服务发现 客户端从注册中心获取服务地址

负载均衡 多节点之间分发请求

代理 让远程调用像本地函数一样


二、完整代码实现

  1. 自定义序列化协议

```c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <pthread.h>

#include <errno.h>

#include <time.h>

// 消息类型

#define MSG_REQUEST 0x01

#define MSG_RESPONSE 0x02

#define MSG_HEARTBEAT 0x03

// 序列化类型

#define TYPE_NULL 0

#define TYPE_INT 1

#define TYPE_LONG 2

#define TYPE_STRING 3

#define TYPE_ARRAY 4

// RPC消息头

typedef struct {

unsigned char magic; // 魔数 0xAA

unsigned char type; // 消息类型

unsigned short seq; // 序列号

unsigned int body_len; // 包体长度

} rpc_header_t;

// RPC请求

typedef struct {

char service64; // 服务名

char method64; // 方法名

char **args; // 参数列表

int arg_count;

} rpc_request_t;

// RPC响应

typedef struct {

int error_code; // 0成功,非0错误码

char error_msg256; // 错误信息

void *result; // 返回值

int result_type; // 返回值类型

} rpc_response_t;

// 序列化缓冲区

typedef struct {

unsigned char *data;

int capacity;

int position;

} serialize_buffer_t;

serialize_buffer_t *serialize_create(int capacity) {

serialize_buffer_t *buf = malloc(sizeof(serialize_buffer_t));

buf->data = malloc(capacity);

buf->capacity = capacity;

buf->position = 0;

return buf;

}

void serialize_destroy(serialize_buffer_t *buf) {

free(buf->data);

free(buf);

}

void serialize_write_int(serialize_buffer_t *buf, int val) {

if (buf->position + 5 > buf->capacity) {

buf->capacity *= 2;

buf->data = realloc(buf->data, buf->capacity);

}

buf->databuf-\>position++ = TYPE_INT;

*(int*)(buf->data + buf->position) = htonl(val);

buf->position += 4;

}

void serialize_write_string(serialize_buffer_t *buf, const char *str) {

int len = str ? strlen(str) : 0;

if (buf->position + 5 + len > buf->capacity) {

buf->capacity = buf->position + 5 + len + 1024;

buf->data = realloc(buf->data, buf->capacity);

}

buf->databuf-\>position++ = TYPE_STRING;

*(int*)(buf->data + buf->position) = htonl(len);

buf->position += 4;

if (len > 0) {

memcpy(buf->data + buf->position, str, len);

buf->position += len;

}

}

int serialize_read_int(serialize_buffer_t *buf, int *val) {

if (buf->position + 5 > buf->capacity) return -1;

if (buf->databuf-\>position++ != TYPE_INT) return -1;

*val = ntohl(*(int*)(buf->data + buf->position));

buf->position += 4;

return 0;

}

int serialize_read_string(serialize_buffer_t *buf, char **str) {

if (buf->position + 1 > buf->capacity) return -1;

if (buf->databuf-\>position++ != TYPE_STRING) return -1;

int len = ntohl(*(int*)(buf->data + buf->position));

buf->position += 4;

*str = malloc(len + 1);

memcpy(*str, buf->data + buf->position, len);

(*str)len = '\0';

buf->position += len;

return 0;

}

```

  1. RPC请求编码/解码

```c

// 编码RPC请求

unsigned char *encode_request(rpc_request_t *req, int *out_len) {

serialize_buffer_t *buf = serialize_create(1024);

serialize_write_string(buf, req->service);

serialize_write_string(buf, req->method);

serialize_write_int(buf, req->arg_count);

for (int i = 0; i < req->arg_count; i++) {

serialize_write_string(buf, req->argsi);

}

*out_len = buf->position;

unsigned char *data = malloc(*out_len);

memcpy(data, buf->data, *out_len);

serialize_destroy(buf);

return data;

}

// 解码RPC请求

rpc_request_t *decode_request(unsigned char *data, int len) {

serialize_buffer_t *buf = serialize_create(len);

memcpy(buf->data, data, len);

buf->capacity = len;

rpc_request_t *req = calloc(1, sizeof(rpc_request_t));

serialize_read_string(buf, &req->service);

serialize_read_string(buf, &req->method);

serialize_read_int(buf, &req->arg_count);

req->args = malloc(sizeof(char*) * req->arg_count);

for (int i = 0; i < req->arg_count; i++) {

serialize_read_string(buf, &req->argsi);

}

serialize_destroy(buf);

return req;

}

// 编码RPC响应

unsigned char *encode_response(rpc_response_t *resp, int *out_len) {

serialize_buffer_t *buf = serialize_create(1024);

serialize_write_int(buf, resp->error_code);

serialize_write_string(buf, resp->error_msg);

serialize_write_int(buf, resp->result_type);

if (resp->result_type == TYPE_STRING && resp->result) {

serialize_write_string(buf, (char*)resp->result);

} else if (resp->result_type == TYPE_INT) {

serialize_write_int(buf, *(int*)resp->result);

}

*out_len = buf->position;

unsigned char *data = malloc(*out_len);

memcpy(data, buf->data, *out_len);

serialize_destroy(buf);

return data;

}

```

  1. 服务注册中心

```c

// 服务实例

typedef struct service_instance {

char name64;

char host32;

int port;

int weight;

int healthy;

time_t last_heartbeat;

struct service_instance *next;

} service_instance_t;

// 注册中心

typedef struct registry {

service_instance_t *services;

pthread_mutex_t mutex;

} registry_t;

registry_t *registry_create() {

registry_t *reg = malloc(sizeof(registry_t));

reg->services = NULL;

pthread_mutex_init(&reg->mutex, NULL);

return reg;

}

// 注册服务

void registry_register(registry_t *reg, const char *name, const char *host, int port) {

pthread_mutex_lock(&reg->mutex);

service_instance_t *inst = malloc(sizeof(service_instance_t));

strcpy(inst->name, name);

strcpy(inst->host, host);

inst->port = port;

inst->weight = 100;

inst->healthy = 1;

inst->last_heartbeat = time(NULL);

inst->next = reg->services;

reg->services = inst;

pthread_mutex_unlock(&reg->mutex);

printf("服务注册: %s -> %s:%d\n", name, host, port);

}

// 服务发现

service_instance_t **registry_discover(registry_t *reg, const char *name, int *count) {

pthread_mutex_lock(&reg->mutex);

service_instance_t *tmp = reg->services;

int cnt = 0;

while (tmp) {

if (strcmp(tmp->name, name) == 0 && tmp->healthy) {

cnt++;

}

tmp = tmp->next;

}

service_instance_t **instances = malloc(sizeof(service_instance_t*) * cnt);

tmp = reg->services;

int idx = 0;

while (tmp) {

if (strcmp(tmp->name, name) == 0 && tmp->healthy) {

instancesidx++ = tmp;

}

tmp = tmp->next;

}

*count = cnt;

pthread_mutex_unlock(&reg->mutex);

return instances;

}

```

  1. 负载均衡器

```c

// 负载均衡算法

typedef enum {

LB_ROUND_ROBIN,

LB_RANDOM,

LB_WEIGHTED

} lb_algorithm_t;

typedef struct {

lb_algorithm_t algorithm;

int current_index;

pthread_mutex_t mutex;

} load_balancer_t;

load_balancer_t *lb_create(lb_algorithm_t algo) {

load_balancer_t *lb = malloc(sizeof(load_balancer_t));

lb->algorithm = algo;

lb->current_index = 0;

pthread_mutex_init(&lb->mutex, NULL);

return lb;

}

// 选择实例

service_instance_t *lb_select(load_balancer_t *lb, service_instance_t **instances, int count) {

if (count == 0) return NULL;

pthread_mutex_lock(&lb->mutex);

int idx = 0;

switch (lb->algorithm) {

case LB_ROUND_ROBIN:

idx = lb->current_index % count;

lb->current_index++;

break;

case LB_RANDOM:

idx = rand() % count;

break;

case LB_WEIGHTED:

{

int total_weight = 0;

for (int i = 0; i < count; i++) {

total_weight += instancesi->weight;

}

int random_weight = rand() % total_weight;

int sum = 0;

for (int i = 0; i < count; i++) {

sum += instancesi->weight;

if (random_weight < sum) {

idx = i;

break;

}

}

break;

}

}

pthread_mutex_unlock(&lb->mutex);

return instancesidx;

}

```

  1. RPC客户端

```c

// RPC客户端

typedef struct {

registry_t *registry;

load_balancer_t *lb;

int timeout_ms;

int retry_count;

} rpc_client_t;

rpc_client_t *rpc_client_create(registry_t *reg, lb_algorithm_t algo) {

rpc_client_t *client = malloc(sizeof(rpc_client_t));

client->registry = reg;

client->lb = lb_create(algo);

client->timeout_ms = 3000;

client->retry_count = 3;

return client;

}

// 发送RPC请求

int rpc_call(rpc_client_t *client, const char *service, const char *method,

char **args, int arg_count, void **result) {

// 服务发现

int inst_count;

service_instance_t **instances = registry_discover(client->registry, service, &inst_count);

if (inst_count == 0) {

free(instances);

return -1;

}

// 负载均衡选择实例

service_instance_t *inst = lb_select(client->lb, instances, inst_count);

free(instances);

// 构建请求

rpc_request_t req;

strcpy(req.service, service);

strcpy(req.method, method);

req.args = args;

req.arg_count = arg_count;

int body_len;

unsigned char *body = encode_request(&req, &body_len);

// 构建消息包

rpc_header_t header;

header.magic = 0xAA;

header.type = MSG_REQUEST;

header.seq = rand() & 0xFFFF;

header.body_len = body_len;

int ret = -1;

for (int retry = 0; retry < client->retry_count; retry++) {

// 连接服务器

int sock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_port = htons(inst->port);

inet_pton(AF_INET, inst->host, &addr.sin_addr);

if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {

close(sock);

continue;

}

// 发送请求

send(sock, &header, sizeof(header), 0);

send(sock, body, body_len, 0);

// 接收响应

rpc_header_t resp_header;

if (recv(sock, &resp_header, sizeof(resp_header), 0) != sizeof(resp_header)) {

close(sock);

continue;

}

unsigned char *resp_body = malloc(resp_header.body_len);

recv(sock, resp_body, resp_header.body_len, 0);

// 解码响应

rpc_response_t resp;

decode_response(resp_body, &resp);

if (resp.error_code == 0) {

*result = resp.result;

ret = 0;

}

free(resp_body);

close(sock);

if (ret == 0) break;

}

free(body);

return ret;

}

```

  1. RPC服务端

```c

// 服务函数类型

typedef void* (*service_func_t)(char **args, int arg_count, int *error_code, char *error_msg);

// 服务方法

typedef struct service_method {

char name64;

service_func_t func;

struct service_method *next;

} service_method_t;

// 服务

typedef struct service {

char name64;

service_method_t *methods;

struct service *next;

} service_t;

// RPC服务器

typedef struct {

registry_t *registry;

service_t *services;

int port;

pthread_mutex_t mutex;

} rpc_server_t;

// 注册服务方法

void rpc_register_method(rpc_server_t *server, const char *service,

const char *method, service_func_t func) {

pthread_mutex_lock(&server->mutex);

// 查找或创建服务

service_t *svc = server->services;

while (svc && strcmp(svc->name, service) != 0) {

svc = svc->next;

}

if (!svc) {

svc = malloc(sizeof(service_t));

strcpy(svc->name, service);

svc->methods = NULL;

svc->next = server->services;

server->services = svc;

}

// 添加方法

service_method_t *m = malloc(sizeof(service_method_t));

strcpy(m->name, method);

m->func = func;

m->next = svc->methods;

svc->methods = m;

pthread_mutex_unlock(&server->mutex);

printf("注册方法: %s.%s\n", service, method);

}

// 处理请求

void handle_rpc_request(rpc_server_t *server, int client_fd) {

rpc_header_t header;

if (recv(client_fd, &header, sizeof(header), 0) != sizeof(header)) {

return;

}

if (header.magic != 0xAA) {

return;

}

unsigned char *body = malloc(header.body_len);

recv(client_fd, body, header.body_len, 0);

rpc_request_t *req = decode_request(body, header.body_len);

// 查找服务方法

service_t *svc = server->services;

while (svc && strcmp(svc->name, req->service) != 0) {

svc = svc->next;

}

rpc_response_t resp;

memset(&resp, 0, sizeof(resp));

resp.error_code = 0;

if (svc) {

service_method_t *m = svc->methods;

while (m && strcmp(m->name, req->method) != 0) {

m = m->next;

}

if (m) {

// 执行方法

void *result = m->func(req->args, req->arg_count,

&resp.error_code, resp.error_msg);

if (resp.error_code == 0) {

resp.result = result;

resp.result_type = TYPE_STRING; // 假设返回字符串

}

} else {

resp.error_code = 404;

strcpy(resp.error_msg, "Method not found");

}

} else {

resp.error_code = 404;

strcpy(resp.error_msg, "Service not found");

}

// 发送响应

int body_len;

unsigned char *resp_body = encode_response(&resp, &body_len);

rpc_header_t resp_header;

resp_header.magic = 0xAA;

resp_header.type = MSG_RESPONSE;

resp_header.seq = header.seq;

resp_header.body_len = body_len;

send(client_fd, &resp_header, sizeof(resp_header), 0);

send(client_fd, resp_body, body_len, 0);

free(body);

free(resp_body);

// 清理请求

for (int i = 0; i < req->arg_count; i++) {

free(req->argsi);

}

free(req->args);

free(req);

}

// 启动RPC服务器

void rpc_server_run(rpc_server_t *server) {

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

int opt = 1;

setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_addr.s_addr = INADDR_ANY;

addr.sin_port = htons(server->port);

bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));

listen(server_fd, 128);

printf("RPC服务器启动,端口: %d\n", server->port);

// 向注册中心注册

registry_register(server->registry, "myservice", "127.0.0.1", server->port);

while (1) {

int client_fd = accept(server_fd, NULL, NULL);

if (client_fd < 0) continue;

handle_rpc_request(server, client_fd);

close(client_fd);

}

}

```

  1. 示例服务

```c

// 加法服务

void *add_service(char **args, int arg_count, int *error_code, char *error_msg) {

int a = atoi(args0);

int b = atoi(args1);

int *result = malloc(sizeof(int));

*result = a + b;

printf("执行 add(%d, %d) = %d\n", a, b, *result);

*error_code = 0;

return result;

}

// 字符串拼接服务

void *concat_service(char **args, int arg_count, int *error_code, char *error_msg) {

char *result = malloc(256);

strcpy(result, args0);

strcat(result, args1);

printf("执行 concat(%s, %s) = %s\n", args0, args1, result);

*error_code = 0;

return result;

}

```

  1. 主函数测试

```c

int main(int argc, char *argv\[\]) {

if (argc < 2) {

printf("用法: %s server|client\n", argv0);

return 1;

}

if (strcmp(argv1, "server") == 0) {

// 服务端

registry_t *reg = registry_create();

rpc_server_t *server = malloc(sizeof(rpc_server_t));

server->registry = reg;

server->services = NULL;

server->port = 9000;

pthread_mutex_init(&server->mutex, NULL);

// 注册服务方法

rpc_register_method(server, "calculator", "add", add_service);

rpc_register_method(server, "string", "concat", concat_service);

// 启动服务器

rpc_server_run(server);

} else {

// 客户端

registry_t *reg = registry_create();

// 手动注册服务(实际可通过注册中心自动发现)

registry_register(reg, "calculator", "127.0.0.1", 9000);

registry_register(reg, "string", "127.0.0.1", 9000);

rpc_client_t *client = rpc_client_create(reg, LB_ROUND_ROBIN);

// 调用远程方法

char *args1\[\] = {"10", "20"};

int *result1;

if (rpc_call(client, "calculator", "add", args1, 2, (void**)&result1) == 0) {

printf("远程调用 add(10, 20) = %d\n", *result1);

free(result1);

}

char *args2\[\] = {"Hello ", "World!"};

char *result2;

if (rpc_call(client, "string", "concat", args2, 2, (void**)&result2) == 0) {

printf("远程调用 concat = %s\n", result2);

free(result2);

}

}

return 0;

}

```


三、编译和运行

编译

```bash

gcc -o rpc_server rpc.c -lpthread

```

运行服务端

```bash

./rpc server

```

运行客户端

```bash

./rpc client

```


四、RPC vs REST

特性 RPC REST

协议 自定义/TCP HTTP

性能 高 中

可读性 差 好

跨语言 需要序列化协议 天然支持

适用场景 内部微服务 对外开放API


五、总结

通过这篇文章,你学会了:

· RPC的核心原理(序列化、网络传输、动态代理)

· 自定义序列化协议

· 服务注册与发现

· 负载均衡算法(轮询、随机、加权)

· 超时重试机制

· 完整的客户端和服务端实现

RPC是微服务架构的基石。掌握它,你就理解了Dubbo、gRPC的底层原理。

下一篇预告:《从零实现一个消息队列:生产消费与持久化》


评论区分享一下你想用RPC做什么系统~

相关推荐
困意少年1 小时前
从统一初始化到移动语义:C++11 为什么是现代 C++ 的起点
c++
stolentime2 小时前
CF2066D1 Club of Young Aircraft Builders (easy version)题解
c++·算法·动态规划·组合数学
Jun6262 小时前
QT(1)-C/C++库生成和调用
c语言·开发语言·c++·qt
小欣加油2 小时前
leetcode41 缺失的第一个正数
数据结构·c++·算法·leetcode
智者知已应修善业2 小时前
【51单片机按键控制1分钟正计时倒计时暂停复位】2024-1-2
c++·经验分享·笔记·算法·51单片机
QT-Neal2 小时前
C++ 编译过程详解
c++
Littlehero_1212 小时前
QT自定义控件之热换站远程监控系统
c++·qt
努力努力再努力wz2 小时前
【Qt入门系列】一文掌握 Qt 常用显示类控件:QLCDNumber、QProgressBar 与 QCalendarWidget
c语言·开发语言·数据结构·数据库·c++·git·qt
C++ 老炮儿的技术栈3 小时前
如何利用 OpenCV 将图像显示在对话框窗口上
c语言·c++·人工智能·qt·opencv·计算机视觉·github