前言
你有没有想过:在一个大型系统中,订单服务怎么调用用户服务的函数?它们在不同的服务器上,甚至用不同语言写的。
RPC(Remote Procedure Call) 让远程调用像本地调用一样简单。
今天我们用C语言从零实现一个RPC框架:
· 服务注册与发现
· 序列化/反序列化(自定义协议)
· 网络传输(TCP)
· 客户端代理生成
· 负载均衡(轮询/随机)
· 超时重试机制
一、RPC核心原理
- RPC调用流程
```
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 客户端 │ 1.调用 │ 客户端 │ 2.编码 │ 网络 │
│ 业务代码 │ ─────→ │ 代理 │ ─────→ │ 传输 │
└─────────┘ └─────────┘ └────┬────┘
│
│ 3.网络
▼
┌─────────┐ ┌─────────┐ ┌────┴────┐
│ 服务端 │ 5.执行 │ 服务端 │ 4.解码 │ 网络 │
│ 业务代码 │ ←───── │ 存根 │ ←───── │ 传输 │
└─────────┘ └─────────┘ └─────────┘
```
- 核心组件
组件 作用
序列化 把参数变成字节流
反序列化 把字节流变回参数
服务注册 服务提供方注册到注册中心
服务发现 客户端从注册中心获取服务地址
负载均衡 多节点之间分发请求
代理 让远程调用像本地函数一样
二、完整代码实现
- 自定义序列化协议
```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;
}
```
- 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;
}
```
- 服务注册中心
```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(®->mutex, NULL);
return reg;
}
// 注册服务
void registry_register(registry_t *reg, const char *name, const char *host, int port) {
pthread_mutex_lock(®->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(®->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(®->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(®->mutex);
return instances;
}
```
- 负载均衡器
```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;
}
```
- 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;
}
```
- 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);
}
}
```
- 示例服务
```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;
}
```
- 主函数测试
```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做什么系统~