12 changed files with 1393 additions and 1284 deletions
@ -1,166 +1,166 @@ |
|||||
# RPC Demo Project |
# RPC Demo Project
|
||||
|
|
||||
这是一个用C语言实现的简单RPC(Remote Procedure Call)框架,可以在Linux环境下运行。这个框架允许客户端程序远程调用服务器上的函数,就像调用本地函数一样。 |
这是一个用C语言实现的简单RPC(Remote Procedure Call)框架,可以在Linux环境下运行。这个框架允许客户端程序远程调用服务器上的函数,就像调用本地函数一样。 |
||||
|
|
||||
## 项目结构 |
## 项目结构
|
||||
|
|
||||
``` |
``` |
||||
├── include/ # 头文件目录 |
├── include/ # 头文件目录 |
||||
│ ├── rpc_common.h # 公共定义和工具函数 |
│ ├── rpc_common.h # 公共定义和工具函数 |
||||
│ ├── rpc_transport.h # 网络传输层接口 |
│ ├── rpc_transport.h # 网络传输层接口 |
||||
│ └── rpc_message.h # 消息序列化和反序列化 |
│ └── rpc_message.h # 消息序列化和反序列化 |
||||
├── src/ # 源代码目录 |
├── src/ # 源代码目录 |
||||
│ ├── rpc_common.c # 公共函数实现 |
│ ├── rpc_common.c # 公共函数实现 |
||||
│ ├── rpc_transport.c # 传输层实现 |
│ ├── rpc_transport.c # 传输层实现 |
||||
│ ├── rpc_message.c # 消息处理实现 |
│ ├── rpc_message.c # 消息处理实现 |
||||
│ ├── rpc_server.c # RPC服务器实现 |
│ ├── rpc_server.c # RPC服务器实现 |
||||
│ ├── rpc_client.c # RPC客户端实现 |
│ ├── rpc_client.c # RPC客户端实现 |
||||
│ └── CMakeLists.txt # 源代码CMake配置 |
│ └── CMakeLists.txt # 源代码CMake配置 |
||||
├── cmake/ # CMake模块目录 |
├── cmake/ # CMake模块目录 |
||||
├── CMakeLists.txt # 主CMake配置文件 |
├── CMakeLists.txt # 主CMake配置文件 |
||||
└── README.md # 项目说明文档 |
└── README.md # 项目说明文档 |
||||
``` |
``` |
||||
|
|
||||
## 功能特性 |
## 功能特性
|
||||
|
|
||||
- 支持基本数据类型的远程函数调用(int、float、double、string、bool、void) |
- 支持基本数据类型的远程函数调用(int、float、double、string、bool、void) |
||||
- 支持多参数和返回值 |
- 支持多参数和返回值 |
||||
- 基于TCP/IP协议的网络通信 |
- 基于TCP/IP协议的网络通信 |
||||
- 多线程服务器设计,支持并发请求 |
- 多线程服务器设计,支持并发请求 |
||||
- 使用CMake构建系统 |
- 使用CMake构建系统 |
||||
|
|
||||
## 编译和构建 |
## 编译和构建
|
||||
|
|
||||
### Linux 平台 |
### Linux 平台
|
||||
|
|
||||
在Linux环境下,使用以下命令编译项目: |
在Linux环境下,使用以下命令编译项目: |
||||
|
|
||||
```bash |
```bash |
||||
# 创建构建目录 |
# 创建构建目录
|
||||
mkdir build && cd build |
mkdir build && cd build |
||||
|
|
||||
# 运行CMake配置 |
# 运行CMake配置
|
||||
cmake .. |
cmake .. |
||||
|
|
||||
# 编译项目 |
# 编译项目
|
||||
make |
make |
||||
|
|
||||
# 安装(可选) |
# 安装(可选)
|
||||
make install |
make install |
||||
``` |
``` |
||||
|
|
||||
### Windows 平台 |
### Windows 平台
|
||||
|
|
||||
1. 确保已安装 CMake(3.10 或更高版本)和 Visual Studio 2017 或更高版本 |
1. 确保已安装 CMake(3.10 或更高版本)和 Visual Studio 2017 或更高版本 |
||||
2. 使用提供的构建脚本(以管理员身份运行命令提示符): |
2. 使用提供的构建脚本(以管理员身份运行命令提示符): |
||||
|
|
||||
```batch |
```batch |
||||
build_windows.bat |
build_windows.bat |
||||
``` |
``` |
||||
|
|
||||
3. 构建完成后,可执行文件将位于 `install\bin\` 目录下 |
3. 构建完成后,可执行文件将位于 `install\bin\` 目录下 |
||||
|
|
||||
或者手动构建: |
或者手动构建: |
||||
|
|
||||
```batch |
```batch |
||||
mkdir build_windows |
mkdir build_windows |
||||
cd build_windows |
cd build_windows |
||||
cmake .. -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=..\install |
cmake .. -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=..\install |
||||
cmake --build . --config Release |
cmake --build . --config Release |
||||
cmake --build . --config Release --target install |
cmake --build . --config Release --target install |
||||
``` |
``` |
||||
|
|
||||
### 运行示例 |
### 运行示例
|
||||
|
|
||||
无论是在Linux还是Windows平台上,运行示例的方式相同: |
无论是在Linux还是Windows平台上,运行示例的方式相同: |
||||
|
|
||||
1. 首先启动服务器: |
1. 首先启动服务器: |
||||
```bash |
```bash |
||||
cd install/bin |
cd install/bin |
||||
./rpc_server # Linux |
./rpc_server # Linux |
||||
rpc_server.exe # Windows |
rpc_server.exe # Windows |
||||
``` |
``` |
||||
|
|
||||
2. 在另一个终端启动客户端: |
2. 在另一个终端启动客户端: |
||||
```bash |
```bash |
||||
cd install/bin |
cd install/bin |
||||
./rpc_client # Linux |
./rpc_client # Linux |
||||
rpc_client.exe # Windows |
rpc_client.exe # Windows |
||||
``` |
``` |
||||
|
|
||||
3. 客户端将连接到服务器并执行两个示例操作: |
3. 客户端将连接到服务器并执行两个示例操作: |
||||
- 调用远程加法函数 `add(10, 20)` |
- 调用远程加法函数 `add(10, 20)` |
||||
- 调用远程函数获取服务器信息 `get_server_info()` |
- 调用远程函数获取服务器信息 `get_server_info()` |
||||
|
|
||||
4. 查看终端输出以确认操作是否成功完成 |
4. 查看终端输出以确认操作是否成功完成 |
||||
|
|
||||
## 使用示例 |
## 使用示例
|
||||
|
|
||||
### 启动服务器 |
### 启动服务器
|
||||
|
|
||||
```bash |
```bash |
||||
./bin/rpc_server |
./bin/rpc_server |
||||
``` |
``` |
||||
|
|
||||
服务器将在8080端口上监听客户端连接。 |
服务器将在8080端口上监听客户端连接。 |
||||
|
|
||||
### 运行客户端 |
### 运行客户端
|
||||
|
|
||||
```bash |
```bash |
||||
./bin/rpc_client |
./bin/rpc_client |
||||
``` |
``` |
||||
|
|
||||
客户端将连接到服务器并调用两个示例函数: |
客户端将连接到服务器并调用两个示例函数: |
||||
- `add(10, 20)` - 远程加法运算 |
- `add(10, 20)` - 远程加法运算 |
||||
- `get_server_info()` - 获取服务器信息 |
- `get_server_info()` - 获取服务器信息 |
||||
|
|
||||
## 自定义扩展 |
## 自定义扩展
|
||||
|
|
||||
### 注册新的远程函数 |
### 注册新的远程函数
|
||||
|
|
||||
要在服务器端添加新的远程函数,您需要: |
要在服务器端添加新的远程函数,您需要: |
||||
|
|
||||
1. 实现函数处理器 |
1. 实现函数处理器 |
||||
2. 使用`rpc_register_function`注册函数 |
2. 使用`rpc_register_function`注册函数 |
||||
|
|
||||
示例: |
示例: |
||||
|
|
||||
```c |
```c |
||||
// 函数实现 |
// 函数实现 |
||||
example_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
example_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
||||
// 函数逻辑 |
// 函数逻辑 |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
// 注册函数 |
// 注册函数 |
||||
rpc_param_type_t example_params[] = {RPC_TYPE_INT, RPC_TYPE_STRING}; |
rpc_param_type_t example_params[] = {RPC_TYPE_INT, RPC_TYPE_STRING}; |
||||
rpc_register_function("example_func", example_handler, RPC_TYPE_STRING, example_params, 2); |
rpc_register_function("example_func", example_handler, RPC_TYPE_STRING, example_params, 2); |
||||
``` |
``` |
||||
|
|
||||
### 客户端调用新函数 |
### 客户端调用新函数
|
||||
|
|
||||
在客户端调用新注册的函数: |
在客户端调用新注册的函数: |
||||
|
|
||||
```c |
```c |
||||
rpc_param_t params[2]; |
rpc_param_t params[2]; |
||||
rpc_param_t return_value; |
rpc_param_t return_value; |
||||
|
|
||||
// 设置参数 |
// 设置参数 |
||||
rpc_init_param(¶ms[0], RPC_TYPE_INT); |
rpc_init_param(¶ms[0], RPC_TYPE_INT); |
||||
params[0].value.int_val = 123; |
params[0].value.int_val = 123; |
||||
|
|
||||
rpc_init_param(¶ms[1], RPC_TYPE_STRING); |
rpc_init_param(¶ms[1], RPC_TYPE_STRING); |
||||
params[1].value.string_val = "example string"; |
params[1].value.string_val = "example string"; |
||||
|
|
||||
// 设置返回值 |
// 设置返回值 |
||||
rpc_init_param(&return_value, RPC_TYPE_STRING); |
rpc_init_param(&return_value, RPC_TYPE_STRING); |
||||
|
|
||||
// 调用远程函数 |
// 调用远程函数 |
||||
int ret = rpc_call(client, "example_func", params, 2, &return_value); |
int ret = rpc_call(client, "example_func", params, 2, &return_value); |
||||
``` |
``` |
||||
|
|
||||
## 注意事项 |
## 注意事项
|
||||
|
|
||||
- 本项目是一个教学示例,可能不适合在生产环境中使用 |
- 本项目是一个教学示例,可能不适合在生产环境中使用 |
||||
- 当前实现中,字符串参数和返回值的处理使用了简单的内存管理策略,在实际应用中可能需要更复杂的处理 |
- 当前实现中,字符串参数和返回值的处理使用了简单的内存管理策略,在实际应用中可能需要更复杂的处理 |
||||
- 错误处理机制相对简单,实际应用中可能需要更完善的错误处理 |
- 错误处理机制相对简单,实际应用中可能需要更完善的错误处理 |
||||
@ -1,61 +1,61 @@ |
|||||
@echo off |
@echo off |
||||
|
|
||||
REM Windows平台构建脚本 |
REM Windows平台构建脚本 |
||||
|
|
||||
REM 配置参数 |
REM 配置参数 |
||||
set BUILD_DIR=build_windows |
set BUILD_DIR=build_windows |
||||
set CMAKE_GENERATOR="Visual Studio 17 2022" |
set CMAKE_GENERATOR="Visual Studio 17 2022" |
||||
set INSTALL_PREFIX=install |
set INSTALL_PREFIX=install |
||||
|
|
||||
REM 检查命令行参数 |
REM 检查命令行参数 |
||||
:parse_args |
:parse_args |
||||
if "%1"=="--clean" ( |
if "%1"=="--clean" ( |
||||
echo Cleaning build directory... |
echo Cleaning build directory... |
||||
if exist %BUILD_DIR% rmdir /s /q %BUILD_DIR% |
if exist %BUILD_DIR% rmdir /s /q %BUILD_DIR% |
||||
if exist %INSTALL_PREFIX% rmdir /s /q %INSTALL_PREFIX% |
if exist %INSTALL_PREFIX% rmdir /s /q %INSTALL_PREFIX% |
||||
shift |
shift |
||||
) |
) |
||||
|
|
||||
REM 创建构建目录 |
REM 创建构建目录 |
||||
if not exist %BUILD_DIR% mkdir %BUILD_DIR% |
if not exist %BUILD_DIR% mkdir %BUILD_DIR% |
||||
|
|
||||
REM 运行CMake配置 |
REM 运行CMake配置 |
||||
pushd %BUILD_DIR% |
pushd %BUILD_DIR% |
||||
echo Running CMake configuration... |
echo Running CMake configuration... |
||||
cmake .. -G %CMAKE_GENERATOR% -DCMAKE_INSTALL_PREFIX=../%INSTALL_PREFIX% |
cmake .. -G %CMAKE_GENERATOR% -DCMAKE_INSTALL_PREFIX=../%INSTALL_PREFIX% |
||||
if %ERRORLEVEL% neq 0 ( |
if %ERRORLEVEL% neq 0 ( |
||||
echo CMake configuration failed! |
echo CMake configuration failed! |
||||
popd |
popd |
||||
exit /b 1 |
exit /b 1 |
||||
) |
) |
||||
|
|
||||
REM 构建项目 |
REM 构建项目 |
||||
echo Building project... |
echo Building project... |
||||
cmake --build . --config Release |
cmake --build . --config Release |
||||
if %ERRORLEVEL% neq 0 ( |
if %ERRORLEVEL% neq 0 ( |
||||
echo Build failed! |
echo Build failed! |
||||
popd |
popd |
||||
exit /b 1 |
exit /b 1 |
||||
) |
) |
||||
|
|
||||
REM 安装项目 |
REM 安装项目 |
||||
echo Installing project... |
echo Installing project... |
||||
cmake --build . --config Release --target install |
cmake --build . --config Release --target install |
||||
if %ERRORLEVEL% neq 0 ( |
if %ERRORLEVEL% neq 0 ( |
||||
echo Installation failed! |
echo Installation failed! |
||||
popd |
popd |
||||
exit /b 1 |
exit /b 1 |
||||
) |
) |
||||
|
|
||||
popd |
popd |
||||
|
|
||||
echo Build completed successfully! |
echo Build completed successfully! |
||||
echo Server executable: %INSTALL_PREFIX%\bin\rpc_server.exeecho Client executable: %INSTALL_PREFIX%\bin\rpc_client.exe |
echo Server executable: %INSTALL_PREFIX%\bin\rpc_server.exeecho Client executable: %INSTALL_PREFIX%\bin\rpc_client.exe |
||||
echo |
echo |
||||
echo To run the server: |
echo To run the server: |
||||
cd %INSTALL_PREFIX%\bin |
cd %INSTALL_PREFIX%\bin |
||||
echo rpc_server.exe |
echo rpc_server.exe |
||||
|
|
||||
echo |
echo |
||||
echo Then in another terminal: |
echo Then in another terminal: |
||||
echo rpc_client.exe |
echo rpc_client.exe |
||||
@ -0,0 +1,108 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
转换项目中的所有文件编码为UTF-8无BOM格式(Linux兼容) |
||||
|
""" |
||||
|
|
||||
|
import os |
||||
|
import codecs |
||||
|
|
||||
|
def convert_file_to_utf8_no_bom(file_path): |
||||
|
"""将单个文件转换为UTF-8无BOM格式""" |
||||
|
try: |
||||
|
# 尝试自动检测文件编码并读取内容 |
||||
|
with open(file_path, 'rb') as f: |
||||
|
content = f.read() |
||||
|
|
||||
|
# 尝试几种常见的编码格式 |
||||
|
encodings = ['utf-8', 'utf-8-sig', 'gbk', 'gb2312', 'latin-1'] |
||||
|
text = None |
||||
|
|
||||
|
for encoding in encodings: |
||||
|
try: |
||||
|
text = content.decode(encoding) |
||||
|
break |
||||
|
except UnicodeDecodeError: |
||||
|
continue |
||||
|
|
||||
|
if text is None: |
||||
|
# 如果无法解码,使用二进制模式复制 |
||||
|
print(f"警告: 无法解码文件 {file_path},使用二进制模式复制") |
||||
|
with open(file_path + '.tmp', 'wb') as f: |
||||
|
f.write(content) |
||||
|
os.replace(file_path + '.tmp', file_path) |
||||
|
return False |
||||
|
|
||||
|
# 以UTF-8无BOM格式写入文件 |
||||
|
with open(file_path + '.tmp', 'w', encoding='utf-8') as f: |
||||
|
f.write(text) |
||||
|
|
||||
|
# 替换原文件 |
||||
|
os.replace(file_path + '.tmp', file_path) |
||||
|
|
||||
|
print(f"已转换: {file_path}") |
||||
|
return True |
||||
|
|
||||
|
except Exception as e: |
||||
|
print(f"错误: 转换文件 {file_path} 失败 - {str(e)}") |
||||
|
return False |
||||
|
|
||||
|
def main(): |
||||
|
"""主函数""" |
||||
|
# 设置项目根目录 |
||||
|
project_root = os.path.dirname(os.path.abspath(__file__)) |
||||
|
|
||||
|
# 定义需要转换的文件列表 |
||||
|
files_to_convert = [ |
||||
|
# 根目录下的文件 |
||||
|
'.gitignore', |
||||
|
'CMakeLists.txt', |
||||
|
'README.md', |
||||
|
'build.sh', |
||||
|
'build_windows.bat', |
||||
|
'test_cmake_config.cmd', |
||||
|
'test_compile.cmd', |
||||
|
|
||||
|
# include目录下的文件 |
||||
|
os.path.join('include', 'rpc_common.h'), |
||||
|
os.path.join('include', 'rpc_message.h'), |
||||
|
os.path.join('include', 'rpc_transport.h'), |
||||
|
|
||||
|
# src目录下的文件 |
||||
|
os.path.join('src', 'CMakeLists.txt'), |
||||
|
os.path.join('src', 'rpc_client.c'), |
||||
|
os.path.join('src', 'rpc_common.c'), |
||||
|
os.path.join('src', 'rpc_message.c'), |
||||
|
os.path.join('src', 'rpc_server.c'), |
||||
|
os.path.join('src', 'rpc_transport.c') |
||||
|
] |
||||
|
|
||||
|
print(f"开始转换项目文件编码为UTF-8无BOM格式(Linux兼容)...") |
||||
|
print(f"项目根目录: {project_root}") |
||||
|
print("=" * 60) |
||||
|
|
||||
|
# 转换每个文件 |
||||
|
success_count = 0 |
||||
|
error_count = 0 |
||||
|
|
||||
|
for file_rel_path in files_to_convert: |
||||
|
file_abs_path = os.path.join(project_root, file_rel_path) |
||||
|
|
||||
|
if os.path.exists(file_abs_path): |
||||
|
if convert_file_to_utf8_no_bom(file_abs_path): |
||||
|
success_count += 1 |
||||
|
else: |
||||
|
error_count += 1 |
||||
|
else: |
||||
|
print(f"警告: 文件不存在 - {file_abs_path}") |
||||
|
error_count += 1 |
||||
|
|
||||
|
print("=" * 60) |
||||
|
print(f"转换完成!成功: {success_count}, 失败: {error_count}") |
||||
|
print("所有文件已转换为UTF-8无BOM格式,可以在Linux环境下正常使用。") |
||||
|
|
||||
|
# 让窗口保持打开状态 |
||||
|
input("按Enter键退出...") |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
main() |
||||
@ -1,59 +1,59 @@ |
|||||
/*
|
/*
|
||||
* rpc_message.h |
* rpc_message.h |
||||
* 定义RPC消息的序列化和反序列化接口 |
* 定义RPC消息的序列化和反序列化接口 |
||||
*/ |
*/ |
||||
|
|
||||
#ifndef RPC_MESSAGE_H |
#ifndef RPC_MESSAGE_H
|
||||
#define RPC_MESSAGE_H |
#define RPC_MESSAGE_H
|
||||
|
|
||||
#include "rpc_common.h" |
#include "rpc_common.h"
|
||||
#include "rpc_transport.h" |
#include "rpc_transport.h"
|
||||
|
|
||||
/* 消息类型枚举 */ |
/* 消息类型枚举 */ |
||||
typedef enum { |
typedef enum { |
||||
RPC_MESSAGE_REQUEST, // 请求消息
|
RPC_MESSAGE_REQUEST, // 请求消息
|
||||
RPC_MESSAGE_RESPONSE // 响应消息
|
RPC_MESSAGE_RESPONSE // 响应消息
|
||||
} rpc_message_type_t; |
} rpc_message_type_t; |
||||
|
|
||||
/* RPC消息头部 */ |
/* RPC消息头部 */ |
||||
typedef struct { |
typedef struct { |
||||
rpc_message_type_t type; // 消息类型
|
rpc_message_type_t type; // 消息类型
|
||||
uint32_t payload_size; // 负载大小
|
uint32_t payload_size; // 负载大小
|
||||
} rpc_message_header_t; |
} rpc_message_header_t; |
||||
|
|
||||
/* RPC消息结构 */ |
/* RPC消息结构 */ |
||||
typedef struct { |
typedef struct { |
||||
rpc_message_header_t header; // 消息头部
|
rpc_message_header_t header; // 消息头部
|
||||
union { |
union { |
||||
rpc_request_t request; // 请求消息
|
rpc_request_t request; // 请求消息
|
||||
rpc_response_t response; // 响应消息
|
rpc_response_t response; // 响应消息
|
||||
} payload; // 消息负载
|
} payload; // 消息负载
|
||||
} rpc_message_t; |
} rpc_message_t; |
||||
|
|
||||
/* 消息处理函数声明 */ |
/* 消息处理函数声明 */ |
||||
|
|
||||
// 序列化请求消息到缓冲区
|
// 序列化请求消息到缓冲区
|
||||
int rpc_serialize_request(const rpc_request_t* request, void* buffer, size_t buffer_size); |
int rpc_serialize_request(const rpc_request_t* request, void* buffer, size_t buffer_size); |
||||
|
|
||||
// 反序列化缓冲区到请求消息
|
// 反序列化缓冲区到请求消息
|
||||
int rpc_deserialize_request(const void* buffer, size_t buffer_size, rpc_request_t* request); |
int rpc_deserialize_request(const void* buffer, size_t buffer_size, rpc_request_t* request); |
||||
|
|
||||
// 序列化响应消息到缓冲区
|
// 序列化响应消息到缓冲区
|
||||
int rpc_serialize_response(const rpc_response_t* response, void* buffer, size_t buffer_size); |
int rpc_serialize_response(const rpc_response_t* response, void* buffer, size_t buffer_size); |
||||
|
|
||||
// 反序列化缓冲区到响应消息
|
// 反序列化缓冲区到响应消息
|
||||
int rpc_deserialize_response(const void* buffer, size_t buffer_size, rpc_response_t* response); |
int rpc_deserialize_response(const void* buffer, size_t buffer_size, rpc_response_t* response); |
||||
|
|
||||
// 发送请求消息
|
// 发送请求消息
|
||||
int rpc_send_request(rpc_transport_t* transport, const rpc_request_t* request); |
int rpc_send_request(rpc_transport_t* transport, const rpc_request_t* request); |
||||
|
|
||||
// 接收请求消息
|
// 接收请求消息
|
||||
int rpc_recv_request(rpc_transport_t* transport, rpc_request_t* request); |
int rpc_recv_request(rpc_transport_t* transport, rpc_request_t* request); |
||||
|
|
||||
// 发送响应消息
|
// 发送响应消息
|
||||
int rpc_send_response(rpc_transport_t* transport, const rpc_response_t* response); |
int rpc_send_response(rpc_transport_t* transport, const rpc_response_t* response); |
||||
|
|
||||
// 接收响应消息
|
// 接收响应消息
|
||||
int rpc_recv_response(rpc_transport_t* transport, rpc_response_t* response); |
int rpc_recv_response(rpc_transport_t* transport, rpc_response_t* response); |
||||
|
|
||||
#endif /* RPC_MESSAGE_H */ |
#endif /* RPC_MESSAGE_H */ |
||||
@ -1,77 +1,77 @@ |
|||||
/*
|
/*
|
||||
* rpc_transport.h |
* rpc_transport.h |
||||
* 定义RPC传输层的接口,负责处理网络通信 |
* 定义RPC传输层的接口,负责处理网络通信 |
||||
*/ |
*/ |
||||
|
|
||||
#ifndef RPC_TRANSPORT_H |
#ifndef RPC_TRANSPORT_H
|
||||
#define RPC_TRANSPORT_H |
#define RPC_TRANSPORT_H
|
||||
|
|
||||
#include "rpc_common.h" |
#include "rpc_common.h"
|
||||
|
|
||||
/* 根据不同平台包含不同的头文件 */ |
/* 根据不同平台包含不同的头文件 */ |
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
#include <winsock2.h> |
#include <winsock2.h>
|
||||
#include <ws2tcpip.h> |
#include <ws2tcpip.h>
|
||||
#pragma comment(lib, "ws2_32.lib") |
#pragma comment(lib, "ws2_32.lib")
|
||||
|
|
||||
/* Windows平台的类型定义 */ |
/* Windows平台的类型定义 */ |
||||
typedef SOCKET socket_t; |
typedef SOCKET socket_t; |
||||
#define INVALID_SOCKET_VALUE INVALID_SOCKET |
#define INVALID_SOCKET_VALUE INVALID_SOCKET
|
||||
#define CLOSE_SOCKET(s) closesocket(s) |
#define CLOSE_SOCKET(s) closesocket(s)
|
||||
|
|
||||
/* Windows平台初始化和清理函数 */ |
/* Windows平台初始化和清理函数 */ |
||||
int rpc_winsock_init(); |
int rpc_winsock_init(); |
||||
void rpc_winsock_cleanup(); |
void rpc_winsock_cleanup(); |
||||
#else |
#else
|
||||
/* Linux/Unix平台的头文件 */ |
/* Linux/Unix平台的头文件 */ |
||||
#include <sys/socket.h> |
#include <sys/socket.h>
|
||||
#include <netinet/in.h> |
#include <netinet/in.h>
|
||||
#include <arpa/inet.h> |
#include <arpa/inet.h>
|
||||
#include <unistd.h> |
#include <unistd.h>
|
||||
|
|
||||
/* Linux/Unix平台的类型定义 */ |
/* Linux/Unix平台的类型定义 */ |
||||
typedef int socket_t; |
typedef int socket_t; |
||||
#define INVALID_SOCKET_VALUE (-1) |
#define INVALID_SOCKET_VALUE (-1)
|
||||
#define CLOSE_SOCKET(s) close(s) |
#define CLOSE_SOCKET(s) close(s)
|
||||
|
|
||||
/* Linux/Unix平台不需要特殊的初始化和清理 */ |
/* Linux/Unix平台不需要特殊的初始化和清理 */ |
||||
#define rpc_winsock_init() 0 |
#define rpc_winsock_init() 0
|
||||
#define rpc_winsock_cleanup() |
#define rpc_winsock_cleanup()
|
||||
#endif |
#endif
|
||||
|
|
||||
/* 传输上下文 */ |
/* 传输上下文 */ |
||||
typedef struct { |
typedef struct { |
||||
socket_t socket_fd; // 套接字文件描述符
|
socket_t socket_fd; // 套接字文件描述符
|
||||
struct sockaddr_in address; // 地址信息
|
struct sockaddr_in address; // 地址信息
|
||||
} rpc_transport_t; |
} rpc_transport_t; |
||||
|
|
||||
/* 服务器上下文 */ |
/* 服务器上下文 */ |
||||
typedef struct { |
typedef struct { |
||||
socket_t server_fd; // 服务器套接字文件描述符
|
socket_t server_fd; // 服务器套接字文件描述符
|
||||
struct sockaddr_in address; // 服务器地址信息
|
struct sockaddr_in address; // 服务器地址信息
|
||||
} rpc_server_t; |
} rpc_server_t; |
||||
|
|
||||
/* 传输层函数声明 */ |
/* 传输层函数声明 */ |
||||
|
|
||||
// 初始化服务器
|
// 初始化服务器
|
||||
int rpc_server_init(rpc_server_t* server, const char* host, uint16_t port, int backlog); |
int rpc_server_init(rpc_server_t* server, const char* host, uint16_t port, int backlog); |
||||
|
|
||||
// 服务器等待连接
|
// 服务器等待连接
|
||||
int rpc_server_accept(rpc_server_t* server, rpc_transport_t* transport); |
int rpc_server_accept(rpc_server_t* server, rpc_transport_t* transport); |
||||
|
|
||||
// 关闭服务器
|
// 关闭服务器
|
||||
void rpc_server_close(rpc_server_t* server); |
void rpc_server_close(rpc_server_t* server); |
||||
|
|
||||
// 初始化客户端传输
|
// 初始化客户端传输
|
||||
int rpc_client_init(rpc_transport_t* transport, const char* server_host, uint16_t server_port); |
int rpc_client_init(rpc_transport_t* transport, const char* server_host, uint16_t server_port); |
||||
|
|
||||
// 发送数据
|
// 发送数据
|
||||
int rpc_transport_send(rpc_transport_t* transport, const void* data, size_t data_size); |
int rpc_transport_send(rpc_transport_t* transport, const void* data, size_t data_size); |
||||
|
|
||||
// 接收数据
|
// 接收数据
|
||||
int rpc_transport_recv(rpc_transport_t* transport, void* buffer, size_t buffer_size); |
int rpc_transport_recv(rpc_transport_t* transport, void* buffer, size_t buffer_size); |
||||
|
|
||||
// 关闭传输连接
|
// 关闭传输连接
|
||||
void rpc_transport_close(rpc_transport_t* transport); |
void rpc_transport_close(rpc_transport_t* transport); |
||||
|
|
||||
#endif /* RPC_TRANSPORT_H */ |
#endif /* RPC_TRANSPORT_H */ |
||||
@ -1,55 +1,55 @@ |
|||||
# 输出目录设置由顶层CMakeLists.txt控制 |
# 输出目录设置由顶层CMakeLists.txt控制
|
||||
# 以下设置已被禁用,使用顶层设置 |
# 以下设置已被禁用,使用顶层设置
|
||||
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) |
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) |
# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) |
# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
|
||||
# RPC共享库 |
# RPC共享库
|
||||
add_library(rpc_common STATIC |
add_library(rpc_common STATIC |
||||
rpc_common.c |
rpc_common.c
|
||||
rpc_message.c |
rpc_message.c
|
||||
rpc_transport.c |
rpc_transport.c
|
||||
) |
)
|
||||
|
|
||||
# RPC服务器 |
# RPC服务器
|
||||
add_executable(rpc_server |
add_executable(rpc_server |
||||
rpc_server.c |
rpc_server.c
|
||||
) |
)
|
||||
|
|
||||
# 根据不同平台链接不同的库 |
# 根据不同平台链接不同的库
|
||||
if(WIN32) |
if(WIN32)
|
||||
target_link_libraries(rpc_server |
target_link_libraries(rpc_server |
||||
rpc_common |
rpc_common
|
||||
ws2_32 # Windows套接字库 |
ws2_32 # Windows套接字库
|
||||
) |
)
|
||||
else() |
else()
|
||||
target_link_libraries(rpc_server |
target_link_libraries(rpc_server |
||||
rpc_common |
rpc_common
|
||||
pthread |
pthread
|
||||
) |
)
|
||||
endif() |
endif()
|
||||
|
|
||||
# RPC客户端 |
# RPC客户端
|
||||
add_executable(rpc_client |
add_executable(rpc_client |
||||
rpc_client.c |
rpc_client.c
|
||||
) |
)
|
||||
|
|
||||
# 根据不同平台链接不同的库 |
# 根据不同平台链接不同的库
|
||||
if(WIN32) |
if(WIN32)
|
||||
target_link_libraries(rpc_client |
target_link_libraries(rpc_client |
||||
rpc_common |
rpc_common
|
||||
ws2_32 # Windows套接字库 |
ws2_32 # Windows套接字库
|
||||
) |
)
|
||||
else() |
else()
|
||||
target_link_libraries(rpc_client |
target_link_libraries(rpc_client |
||||
rpc_common |
rpc_common
|
||||
pthread |
pthread
|
||||
) |
)
|
||||
endif() |
endif()
|
||||
|
|
||||
# 安装目标 |
# 安装目标
|
||||
install(TARGETS rpc_common rpc_server rpc_client |
install(TARGETS rpc_common rpc_server rpc_client |
||||
RUNTIME DESTINATION bin |
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib |
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib |
ARCHIVE DESTINATION lib
|
||||
) |
) |
||||
@ -1,97 +1,97 @@ |
|||||
/*
|
/*
|
||||
* rpc_common.c |
* rpc_common.c |
||||
* 实现RPC框架的公共工具函数 |
* 实现RPC框架的公共工具函数 |
||||
*/ |
*/ |
||||
|
|
||||
#include "rpc_common.h" |
#include "rpc_common.h"
|
||||
|
|
||||
/*
|
/*
|
||||
* 初始化RPC参数 |
* 初始化RPC参数 |
||||
*/ |
*/ |
||||
void rpc_init_param(rpc_param_t* param, rpc_param_type_t type) { |
void rpc_init_param(rpc_param_t* param, rpc_param_type_t type) { |
||||
if (!param) return; |
if (!param) return; |
||||
|
|
||||
param->type = type; |
param->type = type; |
||||
switch (type) { |
switch (type) { |
||||
case RPC_TYPE_INT: |
case RPC_TYPE_INT: |
||||
param->value.int_val = 0; |
param->value.int_val = 0; |
||||
break; |
break; |
||||
case RPC_TYPE_FLOAT: |
case RPC_TYPE_FLOAT: |
||||
param->value.float_val = 0.0f; |
param->value.float_val = 0.0f; |
||||
break; |
break; |
||||
case RPC_TYPE_DOUBLE: |
case RPC_TYPE_DOUBLE: |
||||
param->value.double_val = 0.0; |
param->value.double_val = 0.0; |
||||
break; |
break; |
||||
case RPC_TYPE_STRING: |
case RPC_TYPE_STRING: |
||||
param->value.string_val = NULL; |
param->value.string_val = NULL; |
||||
break; |
break; |
||||
case RPC_TYPE_BOOL: |
case RPC_TYPE_BOOL: |
||||
param->value.bool_val = false; |
param->value.bool_val = false; |
||||
break; |
break; |
||||
case RPC_TYPE_VOID: |
case RPC_TYPE_VOID: |
||||
default: |
default: |
||||
break; |
break; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 释放参数数组中动态分配的资源 |
* 释放参数数组中动态分配的资源 |
||||
*/ |
*/ |
||||
void rpc_free_params(rpc_param_t* params, int count) { |
void rpc_free_params(rpc_param_t* params, int count) { |
||||
if (!params || count <= 0) return; |
if (!params || count <= 0) return; |
||||
|
|
||||
for (int i = 0; i < count; i++) { |
for (int i = 0; i < count; i++) { |
||||
if (params[i].type == RPC_TYPE_STRING && params[i].value.string_val) { |
if (params[i].type == RPC_TYPE_STRING && params[i].value.string_val) { |
||||
free((void*)params[i].value.string_val); |
free((void*)params[i].value.string_val); |
||||
params[i].value.string_val = NULL; |
params[i].value.string_val = NULL; |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 释放请求消息中动态分配的资源 |
* 释放请求消息中动态分配的资源 |
||||
*/ |
*/ |
||||
void rpc_free_request(rpc_request_t* request) { |
void rpc_free_request(rpc_request_t* request) { |
||||
if (!request) return; |
if (!request) return; |
||||
|
|
||||
rpc_free_params(request->args, request->args_count); |
rpc_free_params(request->args, request->args_count); |
||||
request->args_count = 0; |
request->args_count = 0; |
||||
request->func_name[0] = '\0'; |
request->func_name[0] = '\0'; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 释放响应消息中动态分配的资源 |
* 释放响应消息中动态分配的资源 |
||||
*/ |
*/ |
||||
void rpc_free_response(rpc_response_t* response) { |
void rpc_free_response(rpc_response_t* response) { |
||||
if (!response) return; |
if (!response) return; |
||||
|
|
||||
if (response->return_type == RPC_TYPE_STRING && response->return_value.string_val) { |
if (response->return_type == RPC_TYPE_STRING && response->return_value.string_val) { |
||||
free((void*)response->return_value.string_val); |
free((void*)response->return_value.string_val); |
||||
response->return_value.string_val = NULL; |
response->return_value.string_val = NULL; |
||||
} |
} |
||||
|
|
||||
response->result_code = 0; |
response->result_code = 0; |
||||
response->return_type = RPC_TYPE_VOID; |
response->return_type = RPC_TYPE_VOID; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 将错误码转换为字符串 |
* 将错误码转换为字符串 |
||||
*/ |
*/ |
||||
const char* rpc_error_to_string(int error_code) { |
const char* rpc_error_to_string(int error_code) { |
||||
switch (error_code) { |
switch (error_code) { |
||||
case RPC_SUCCESS: |
case RPC_SUCCESS: |
||||
return "Success"; |
return "Success"; |
||||
case RPC_ERROR: |
case RPC_ERROR: |
||||
return "General error"; |
return "General error"; |
||||
case RPC_NET_ERROR: |
case RPC_NET_ERROR: |
||||
return "Network error"; |
return "Network error"; |
||||
case RPC_TIMEOUT: |
case RPC_TIMEOUT: |
||||
return "Timeout error"; |
return "Timeout error"; |
||||
case RPC_INVALID_ARGS: |
case RPC_INVALID_ARGS: |
||||
return "Invalid arguments"; |
return "Invalid arguments"; |
||||
case RPC_FUNC_NOT_FOUND: |
case RPC_FUNC_NOT_FOUND: |
||||
return "Function not found"; |
return "Function not found"; |
||||
default: |
default: |
||||
return "Unknown error"; |
return "Unknown error"; |
||||
} |
} |
||||
} |
} |
||||
@ -1,191 +1,191 @@ |
|||||
/*
|
/*
|
||||
* rpc_message.c |
* rpc_message.c |
||||
* 实现RPC消息的序列化和反序列化功能 |
* 实现RPC消息的序列化和反序列化功能 |
||||
*/ |
*/ |
||||
|
|
||||
#include "rpc_message.h" |
#include "rpc_message.h"
|
||||
#include "rpc_transport.h" |
#include "rpc_transport.h"
|
||||
|
|
||||
/*
|
/*
|
||||
* 序列化请求消息到缓冲区 |
* 序列化请求消息到缓冲区 |
||||
*/ |
*/ |
||||
int rpc_serialize_request(const rpc_request_t* request, void* buffer, size_t buffer_size) { |
int rpc_serialize_request(const rpc_request_t* request, void* buffer, size_t buffer_size) { |
||||
if (!request || !buffer || buffer_size < sizeof(rpc_request_t)) { |
if (!request || !buffer || buffer_size < sizeof(rpc_request_t)) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 复制请求消息到缓冲区
|
// 复制请求消息到缓冲区
|
||||
memcpy(buffer, request, sizeof(rpc_request_t)); |
memcpy(buffer, request, sizeof(rpc_request_t)); |
||||
|
|
||||
// 注意:这里简化了字符串参数的序列化,实际上可能需要更复杂的处理
|
// 注意:这里简化了字符串参数的序列化,实际上可能需要更复杂的处理
|
||||
// 在实际应用中,可能需要计算字符串的总长度并动态分配足够的缓冲区
|
// 在实际应用中,可能需要计算字符串的总长度并动态分配足够的缓冲区
|
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 反序列化缓冲区到请求消息 |
* 反序列化缓冲区到请求消息 |
||||
*/ |
*/ |
||||
int rpc_deserialize_request(const void* buffer, size_t buffer_size, rpc_request_t* request) { |
int rpc_deserialize_request(const void* buffer, size_t buffer_size, rpc_request_t* request) { |
||||
if (!buffer || !request || buffer_size < sizeof(rpc_request_t)) { |
if (!buffer || !request || buffer_size < sizeof(rpc_request_t)) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 从缓冲区复制请求消息
|
// 从缓冲区复制请求消息
|
||||
memcpy(request, buffer, sizeof(rpc_request_t)); |
memcpy(request, buffer, sizeof(rpc_request_t)); |
||||
|
|
||||
// 注意:这里简化了字符串参数的反序列化
|
// 注意:这里简化了字符串参数的反序列化
|
||||
// 在实际应用中,可能需要处理字符串的动态分配和复制
|
// 在实际应用中,可能需要处理字符串的动态分配和复制
|
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 序列化响应消息到缓冲区 |
* 序列化响应消息到缓冲区 |
||||
*/ |
*/ |
||||
int rpc_serialize_response(const rpc_response_t* response, void* buffer, size_t buffer_size) { |
int rpc_serialize_response(const rpc_response_t* response, void* buffer, size_t buffer_size) { |
||||
if (!response || !buffer || buffer_size < sizeof(rpc_response_t)) { |
if (!response || !buffer || buffer_size < sizeof(rpc_response_t)) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 复制响应消息到缓冲区
|
// 复制响应消息到缓冲区
|
||||
memcpy(buffer, response, sizeof(rpc_response_t)); |
memcpy(buffer, response, sizeof(rpc_response_t)); |
||||
|
|
||||
// 注意:这里简化了字符串返回值的序列化
|
// 注意:这里简化了字符串返回值的序列化
|
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 反序列化缓冲区到响应消息 |
* 反序列化缓冲区到响应消息 |
||||
*/ |
*/ |
||||
int rpc_deserialize_response(const void* buffer, size_t buffer_size, rpc_response_t* response) { |
int rpc_deserialize_response(const void* buffer, size_t buffer_size, rpc_response_t* response) { |
||||
if (!buffer || !response || buffer_size < sizeof(rpc_response_t)) { |
if (!buffer || !response || buffer_size < sizeof(rpc_response_t)) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 从缓冲区复制响应消息
|
// 从缓冲区复制响应消息
|
||||
memcpy(response, buffer, sizeof(rpc_response_t)); |
memcpy(response, buffer, sizeof(rpc_response_t)); |
||||
|
|
||||
// 注意:这里简化了字符串返回值的反序列化
|
// 注意:这里简化了字符串返回值的反序列化
|
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 发送请求消息 |
* 发送请求消息 |
||||
*/ |
*/ |
||||
int rpc_send_request(rpc_transport_t* transport, const rpc_request_t* request) { |
int rpc_send_request(rpc_transport_t* transport, const rpc_request_t* request) { |
||||
if (!transport || !request) { |
if (!transport || !request) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
uint8_t buffer[MAX_MESSAGE_SIZE]; |
uint8_t buffer[MAX_MESSAGE_SIZE]; |
||||
rpc_message_t message; |
rpc_message_t message; |
||||
|
|
||||
// 设置消息头部
|
// 设置消息头部
|
||||
message.header.type = RPC_MESSAGE_REQUEST; |
message.header.type = RPC_MESSAGE_REQUEST; |
||||
message.header.payload_size = sizeof(rpc_request_t); |
message.header.payload_size = sizeof(rpc_request_t); |
||||
|
|
||||
// 复制请求到消息负载
|
// 复制请求到消息负载
|
||||
message.payload.request = *request; |
message.payload.request = *request; |
||||
|
|
||||
// 序列化整个消息
|
// 序列化整个消息
|
||||
size_t message_size = sizeof(rpc_message_header_t) + message.header.payload_size; |
size_t message_size = sizeof(rpc_message_header_t) + message.header.payload_size; |
||||
if (message_size > MAX_MESSAGE_SIZE) { |
if (message_size > MAX_MESSAGE_SIZE) { |
||||
return RPC_ERROR; |
return RPC_ERROR; |
||||
} |
} |
||||
|
|
||||
memcpy(buffer, &message, message_size); |
memcpy(buffer, &message, message_size); |
||||
|
|
||||
// 发送消息
|
// 发送消息
|
||||
return rpc_transport_send(transport, buffer, message_size); |
return rpc_transport_send(transport, buffer, message_size); |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 接收请求消息 |
* 接收请求消息 |
||||
*/ |
*/ |
||||
int rpc_recv_request(rpc_transport_t* transport, rpc_request_t* request) { |
int rpc_recv_request(rpc_transport_t* transport, rpc_request_t* request) { |
||||
if (!transport || !request) { |
if (!transport || !request) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
uint8_t buffer[MAX_MESSAGE_SIZE]; |
uint8_t buffer[MAX_MESSAGE_SIZE]; |
||||
rpc_message_header_t header; |
rpc_message_header_t header; |
||||
|
|
||||
// 接收消息头部
|
// 接收消息头部
|
||||
if (rpc_transport_recv(transport, &header, sizeof(rpc_message_header_t)) != RPC_SUCCESS) { |
if (rpc_transport_recv(transport, &header, sizeof(rpc_message_header_t)) != RPC_SUCCESS) { |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 检查消息类型和大小
|
// 检查消息类型和大小
|
||||
if (header.type != RPC_MESSAGE_REQUEST || header.payload_size > MAX_MESSAGE_SIZE - sizeof(rpc_message_header_t)) { |
if (header.type != RPC_MESSAGE_REQUEST || header.payload_size > MAX_MESSAGE_SIZE - sizeof(rpc_message_header_t)) { |
||||
return RPC_ERROR; |
return RPC_ERROR; |
||||
} |
} |
||||
|
|
||||
// 接收消息负载
|
// 接收消息负载
|
||||
if (rpc_transport_recv(transport, request, header.payload_size) != RPC_SUCCESS) { |
if (rpc_transport_recv(transport, request, header.payload_size) != RPC_SUCCESS) { |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 发送响应消息 |
* 发送响应消息 |
||||
*/ |
*/ |
||||
int rpc_send_response(rpc_transport_t* transport, const rpc_response_t* response) { |
int rpc_send_response(rpc_transport_t* transport, const rpc_response_t* response) { |
||||
if (!transport || !response) { |
if (!transport || !response) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
uint8_t buffer[MAX_MESSAGE_SIZE]; |
uint8_t buffer[MAX_MESSAGE_SIZE]; |
||||
rpc_message_t message; |
rpc_message_t message; |
||||
|
|
||||
// 设置消息头部
|
// 设置消息头部
|
||||
message.header.type = RPC_MESSAGE_RESPONSE; |
message.header.type = RPC_MESSAGE_RESPONSE; |
||||
message.header.payload_size = sizeof(rpc_response_t); |
message.header.payload_size = sizeof(rpc_response_t); |
||||
|
|
||||
// 复制响应到消息负载
|
// 复制响应到消息负载
|
||||
message.payload.response = *response; |
message.payload.response = *response; |
||||
|
|
||||
// 序列化整个消息
|
// 序列化整个消息
|
||||
size_t message_size = sizeof(rpc_message_header_t) + message.header.payload_size; |
size_t message_size = sizeof(rpc_message_header_t) + message.header.payload_size; |
||||
if (message_size > MAX_MESSAGE_SIZE) { |
if (message_size > MAX_MESSAGE_SIZE) { |
||||
return RPC_ERROR; |
return RPC_ERROR; |
||||
} |
} |
||||
|
|
||||
memcpy(buffer, &message, message_size); |
memcpy(buffer, &message, message_size); |
||||
|
|
||||
// 发送消息
|
// 发送消息
|
||||
return rpc_transport_send(transport, buffer, message_size); |
return rpc_transport_send(transport, buffer, message_size); |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 接收响应消息 |
* 接收响应消息 |
||||
*/ |
*/ |
||||
int rpc_recv_response(rpc_transport_t* transport, rpc_response_t* response) { |
int rpc_recv_response(rpc_transport_t* transport, rpc_response_t* response) { |
||||
if (!transport || !response) { |
if (!transport || !response) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
uint8_t buffer[MAX_MESSAGE_SIZE]; |
uint8_t buffer[MAX_MESSAGE_SIZE]; |
||||
rpc_message_header_t header; |
rpc_message_header_t header; |
||||
|
|
||||
// 接收消息头部
|
// 接收消息头部
|
||||
if (rpc_transport_recv(transport, &header, sizeof(rpc_message_header_t)) != RPC_SUCCESS) { |
if (rpc_transport_recv(transport, &header, sizeof(rpc_message_header_t)) != RPC_SUCCESS) { |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 检查消息类型和大小
|
// 检查消息类型和大小
|
||||
if (header.type != RPC_MESSAGE_RESPONSE || header.payload_size > MAX_MESSAGE_SIZE - sizeof(rpc_message_header_t)) { |
if (header.type != RPC_MESSAGE_RESPONSE || header.payload_size > MAX_MESSAGE_SIZE - sizeof(rpc_message_header_t)) { |
||||
return RPC_ERROR; |
return RPC_ERROR; |
||||
} |
} |
||||
|
|
||||
// 接收消息负载
|
// 接收消息负载
|
||||
if (rpc_transport_recv(transport, response, header.payload_size) != RPC_SUCCESS) { |
if (rpc_transport_recv(transport, response, header.payload_size) != RPC_SUCCESS) { |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
@ -1,296 +1,296 @@ |
|||||
/*
|
/*
|
||||
* rpc_server.c |
* rpc_server.c |
||||
* RPC服务器实现,处理客户端连接和执行远程函数调用 |
* RPC服务器实现,处理客户端连接和执行远程函数调用 |
||||
*/ |
*/ |
||||
|
|
||||
#include "rpc_common.h" |
#include "rpc_common.h"
|
||||
#include "rpc_transport.h" |
#include "rpc_transport.h"
|
||||
#include "rpc_message.h" |
#include "rpc_message.h"
|
||||
|
|
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
#include <windows.h> |
#include <windows.h>
|
||||
#else |
#else
|
||||
#include <pthread.h> |
#include <pthread.h>
|
||||
#endif |
#endif
|
||||
|
|
||||
/* 函数处理函数类型定义 */ |
/* 函数处理函数类型定义 */ |
||||
typedef int (*rpc_handler_func_t)(rpc_param_t* params, int args_count, rpc_param_t* return_value); |
typedef int (*rpc_handler_func_t)(rpc_param_t* params, int args_count, rpc_param_t* return_value); |
||||
|
|
||||
/* 函数处理器结构 */ |
/* 函数处理器结构 */ |
||||
typedef struct { |
typedef struct { |
||||
char func_name[MAX_FUNC_NAME_LEN]; |
char func_name[MAX_FUNC_NAME_LEN]; |
||||
rpc_handler_func_t handler; |
rpc_handler_func_t handler; |
||||
rpc_param_type_t return_type; |
rpc_param_type_t return_type; |
||||
rpc_param_type_t param_types[MAX_ARGS_COUNT]; |
rpc_param_type_t param_types[MAX_ARGS_COUNT]; |
||||
int param_count; |
int param_count; |
||||
} rpc_handler_t; |
} rpc_handler_t; |
||||
|
|
||||
/* 函数处理器表 */ |
/* 函数处理器表 */ |
||||
static rpc_handler_t handlers[MAX_FUNC_NAME_LEN]; |
static rpc_handler_t handlers[MAX_FUNC_NAME_LEN]; |
||||
static int handler_count = 0; |
static int handler_count = 0; |
||||
|
|
||||
/*
|
/*
|
||||
* 注册远程函数 |
* 注册远程函数 |
||||
*/ |
*/ |
||||
int rpc_register_function(const char* func_name, rpc_handler_func_t handler, |
int rpc_register_function(const char* func_name, rpc_handler_func_t handler, |
||||
rpc_param_type_t return_type, |
rpc_param_type_t return_type, |
||||
rpc_param_type_t* param_types, int param_count) { |
rpc_param_type_t* param_types, int param_count) { |
||||
if (!func_name || !handler || param_count < 0 || param_count > MAX_ARGS_COUNT) { |
if (!func_name || !handler || param_count < 0 || param_count > MAX_ARGS_COUNT) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
if (handler_count >= MAX_FUNC_NAME_LEN) { |
if (handler_count >= MAX_FUNC_NAME_LEN) { |
||||
return RPC_ERROR; |
return RPC_ERROR; |
||||
} |
} |
||||
|
|
||||
// 检查函数名是否已存在
|
// 检查函数名是否已存在
|
||||
for (int i = 0; i < handler_count; i++) { |
for (int i = 0; i < handler_count; i++) { |
||||
if (strcmp(handlers[i].func_name, func_name) == 0) { |
if (strcmp(handlers[i].func_name, func_name) == 0) { |
||||
return RPC_ERROR; |
return RPC_ERROR; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
// 添加新的函数处理器
|
// 添加新的函数处理器
|
||||
strncpy(handlers[handler_count].func_name, func_name, MAX_FUNC_NAME_LEN - 1); |
strncpy(handlers[handler_count].func_name, func_name, MAX_FUNC_NAME_LEN - 1); |
||||
handlers[handler_count].func_name[MAX_FUNC_NAME_LEN - 1] = '\0'; |
handlers[handler_count].func_name[MAX_FUNC_NAME_LEN - 1] = '\0'; |
||||
handlers[handler_count].handler = handler; |
handlers[handler_count].handler = handler; |
||||
handlers[handler_count].return_type = return_type; |
handlers[handler_count].return_type = return_type; |
||||
handlers[handler_count].param_count = param_count; |
handlers[handler_count].param_count = param_count; |
||||
|
|
||||
// 复制参数类型
|
// 复制参数类型
|
||||
if (param_count > 0 && param_types) { |
if (param_count > 0 && param_types) { |
||||
memcpy(handlers[handler_count].param_types, param_types, |
memcpy(handlers[handler_count].param_types, param_types, |
||||
sizeof(rpc_param_type_t) * param_count); |
sizeof(rpc_param_type_t) * param_count); |
||||
} |
} |
||||
|
|
||||
handler_count++; |
handler_count++; |
||||
printf("Registered function: %s\n", func_name); |
printf("Registered function: %s\n", func_name); |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 查找函数处理器 |
* 查找函数处理器 |
||||
*/ |
*/ |
||||
rpc_handler_t* rpc_find_handler(const char* func_name) { |
rpc_handler_t* rpc_find_handler(const char* func_name) { |
||||
for (int i = 0; i < handler_count; i++) { |
for (int i = 0; i < handler_count; i++) { |
||||
if (strcmp(handlers[i].func_name, func_name) == 0) { |
if (strcmp(handlers[i].func_name, func_name) == 0) { |
||||
return &handlers[i]; |
return &handlers[i]; |
||||
} |
} |
||||
} |
} |
||||
return NULL; |
return NULL; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 处理客户端请求 |
* 处理客户端请求 |
||||
*/ |
*/ |
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
DWORD WINAPI handle_client(LPVOID arg) { |
DWORD WINAPI handle_client(LPVOID arg) { |
||||
#else |
#else
|
||||
void* handle_client(void* arg) { |
void* handle_client(void* arg) { |
||||
#endif |
#endif
|
||||
rpc_transport_t* transport = (rpc_transport_t*)arg; |
rpc_transport_t* transport = (rpc_transport_t*)arg; |
||||
rpc_request_t request; |
rpc_request_t request; |
||||
rpc_response_t response; |
rpc_response_t response; |
||||
int ret; |
int ret; |
||||
|
|
||||
while (1) { |
while (1) { |
||||
// 接收请求
|
// 接收请求
|
||||
ret = rpc_recv_request(transport, &request); |
ret = rpc_recv_request(transport, &request); |
||||
if (ret != RPC_SUCCESS) { |
if (ret != RPC_SUCCESS) { |
||||
printf("Failed to receive request: %s\n", rpc_error_to_string(ret)); |
printf("Failed to receive request: %s\n", rpc_error_to_string(ret)); |
||||
break; |
break; |
||||
} |
} |
||||
|
|
||||
printf("Received request: %s with %d arguments\n", request.func_name, request.args_count); |
printf("Received request: %s with %d arguments\n", request.func_name, request.args_count); |
||||
|
|
||||
// 查找函数处理器
|
// 查找函数处理器
|
||||
rpc_handler_t* handler = rpc_find_handler(request.func_name); |
rpc_handler_t* handler = rpc_find_handler(request.func_name); |
||||
if (!handler) { |
if (!handler) { |
||||
printf("Function not found: %s\n", request.func_name); |
printf("Function not found: %s\n", request.func_name); |
||||
response.result_code = RPC_FUNC_NOT_FOUND; |
response.result_code = RPC_FUNC_NOT_FOUND; |
||||
response.return_type = RPC_TYPE_VOID; |
response.return_type = RPC_TYPE_VOID; |
||||
rpc_send_response(transport, &response); |
rpc_send_response(transport, &response); |
||||
rpc_free_request(&request); |
rpc_free_request(&request); |
||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
// 检查参数数量
|
// 检查参数数量
|
||||
if (request.args_count != handler->param_count) { |
if (request.args_count != handler->param_count) { |
||||
printf("Invalid argument count for %s\n", request.func_name); |
printf("Invalid argument count for %s\n", request.func_name); |
||||
response.result_code = RPC_INVALID_ARGS; |
response.result_code = RPC_INVALID_ARGS; |
||||
response.return_type = RPC_TYPE_VOID; |
response.return_type = RPC_TYPE_VOID; |
||||
rpc_send_response(transport, &response); |
rpc_send_response(transport, &response); |
||||
rpc_free_request(&request); |
rpc_free_request(&request); |
||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
// 执行函数
|
// 执行函数
|
||||
rpc_param_t return_value; |
rpc_param_t return_value; |
||||
rpc_init_param(&return_value, handler->return_type); |
rpc_init_param(&return_value, handler->return_type); |
||||
|
|
||||
ret = handler->handler(request.args, request.args_count, &return_value); |
ret = handler->handler(request.args, request.args_count, &return_value); |
||||
|
|
||||
// 设置响应
|
// 设置响应
|
||||
response.result_code = ret; |
response.result_code = ret; |
||||
response.return_type = handler->return_type; |
response.return_type = handler->return_type; |
||||
|
|
||||
// 复制返回值
|
// 复制返回值
|
||||
switch (handler->return_type) { |
switch (handler->return_type) { |
||||
case RPC_TYPE_INT: |
case RPC_TYPE_INT: |
||||
response.return_value.int_val = return_value.value.int_val; |
response.return_value.int_val = return_value.value.int_val; |
||||
break; |
break; |
||||
case RPC_TYPE_FLOAT: |
case RPC_TYPE_FLOAT: |
||||
response.return_value.float_val = return_value.value.float_val; |
response.return_value.float_val = return_value.value.float_val; |
||||
break; |
break; |
||||
case RPC_TYPE_DOUBLE: |
case RPC_TYPE_DOUBLE: |
||||
response.return_value.double_val = return_value.value.double_val; |
response.return_value.double_val = return_value.value.double_val; |
||||
break; |
break; |
||||
case RPC_TYPE_STRING: |
case RPC_TYPE_STRING: |
||||
// 注意:这里需要复制字符串,避免内存问题
|
// 注意:这里需要复制字符串,避免内存问题
|
||||
response.return_value.string_val = strdup(return_value.value.string_val); |
response.return_value.string_val = strdup(return_value.value.string_val); |
||||
break; |
break; |
||||
case RPC_TYPE_BOOL: |
case RPC_TYPE_BOOL: |
||||
response.return_value.bool_val = return_value.value.bool_val; |
response.return_value.bool_val = return_value.value.bool_val; |
||||
break; |
break; |
||||
case RPC_TYPE_VOID: |
case RPC_TYPE_VOID: |
||||
default: |
default: |
||||
break; |
break; |
||||
} |
} |
||||
|
|
||||
// 发送响应
|
// 发送响应
|
||||
rpc_send_response(transport, &response); |
rpc_send_response(transport, &response); |
||||
|
|
||||
// 释放资源
|
// 释放资源
|
||||
rpc_free_request(&request); |
rpc_free_request(&request); |
||||
if (handler->return_type == RPC_TYPE_STRING && return_value.value.string_val) { |
if (handler->return_type == RPC_TYPE_STRING && return_value.value.string_val) { |
||||
free((void*)return_value.value.string_val); |
free((void*)return_value.value.string_val); |
||||
} |
} |
||||
if (response.return_type == RPC_TYPE_STRING && response.return_value.string_val) { |
if (response.return_type == RPC_TYPE_STRING && response.return_value.string_val) { |
||||
free((void*)response.return_value.string_val); |
free((void*)response.return_value.string_val); |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
// 关闭连接
|
// 关闭连接
|
||||
rpc_transport_close(transport); |
rpc_transport_close(transport); |
||||
free(transport); |
free(transport); |
||||
|
|
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
return 0; |
return 0; |
||||
#else |
#else
|
||||
return NULL; |
return NULL; |
||||
#endif |
#endif
|
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 示例函数:加法 |
* 示例函数:加法 |
||||
*/ |
*/ |
||||
int add_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
int add_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
||||
if (args_count < 2 || params[0].type != RPC_TYPE_INT || params[1].type != RPC_TYPE_INT) { |
if (args_count < 2 || params[0].type != RPC_TYPE_INT || params[1].type != RPC_TYPE_INT) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
int a = params[0].value.int_val; |
int a = params[0].value.int_val; |
||||
int b = params[1].value.int_val; |
int b = params[1].value.int_val; |
||||
|
|
||||
return_value->value.int_val = a + b; |
return_value->value.int_val = a + b; |
||||
|
|
||||
printf("Executed add(%d, %d) = %d\n", a, b, return_value->value.int_val); |
printf("Executed add(%d, %d) = %d\n", a, b, return_value->value.int_val); |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 示例函数:获取服务器信息 |
* 示例函数:获取服务器信息 |
||||
*/ |
*/ |
||||
int get_server_info_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
int get_server_info_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
||||
const char* info = "RPC Server v1.0"; |
const char* info = "RPC Server v1.0"; |
||||
return_value->value.string_val = strdup(info); |
return_value->value.string_val = strdup(info); |
||||
|
|
||||
printf("Executed get_server_info()\n"); |
printf("Executed get_server_info()\n"); |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 主函数 |
* 主函数 |
||||
*/ |
*/ |
||||
int main(int argc, char* argv[]) { |
int main(int argc, char* argv[]) { |
||||
rpc_server_t server; |
rpc_server_t server; |
||||
int port = 8080; |
int port = 8080; |
||||
|
|
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
// 初始化Windows套接字库
|
// 初始化Windows套接字库
|
||||
if (rpc_winsock_init() != RPC_SUCCESS) { |
if (rpc_winsock_init() != RPC_SUCCESS) { |
||||
printf("Failed to initialize Winsock\n"); |
printf("Failed to initialize Winsock\n"); |
||||
return 1; |
return 1; |
||||
} |
} |
||||
#endif |
#endif
|
||||
|
|
||||
// 注册示例函数
|
// 注册示例函数
|
||||
rpc_param_type_t add_params[] = {RPC_TYPE_INT, RPC_TYPE_INT}; |
rpc_param_type_t add_params[] = {RPC_TYPE_INT, RPC_TYPE_INT}; |
||||
rpc_register_function("add", add_handler, RPC_TYPE_INT, add_params, 2); |
rpc_register_function("add", add_handler, RPC_TYPE_INT, add_params, 2); |
||||
rpc_register_function("get_server_info", get_server_info_handler, RPC_TYPE_STRING, NULL, 0); |
rpc_register_function("get_server_info", get_server_info_handler, RPC_TYPE_STRING, NULL, 0); |
||||
|
|
||||
// 初始化服务器
|
// 初始化服务器
|
||||
if (rpc_server_init(&server, "0.0.0.0", port, 5) != RPC_SUCCESS) { |
if (rpc_server_init(&server, "0.0.0.0", port, 5) != RPC_SUCCESS) { |
||||
printf("Failed to initialize server\n"); |
printf("Failed to initialize server\n"); |
||||
return 1; |
return 1; |
||||
} |
} |
||||
|
|
||||
printf("RPC Server listening on port %d\n", port); |
printf("RPC Server listening on port %d\n", port); |
||||
printf("Waiting for client connections...\n"); |
printf("Waiting for client connections...\n"); |
||||
|
|
||||
while (1) { |
while (1) { |
||||
// 接受客户端连接
|
// 接受客户端连接
|
||||
rpc_transport_t* client_transport = (rpc_transport_t*)malloc(sizeof(rpc_transport_t)); |
rpc_transport_t* client_transport = (rpc_transport_t*)malloc(sizeof(rpc_transport_t)); |
||||
if (!client_transport) { |
if (!client_transport) { |
||||
printf("Failed to allocate memory\n"); |
printf("Failed to allocate memory\n"); |
||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
if (rpc_server_accept(&server, client_transport) != RPC_SUCCESS) { |
if (rpc_server_accept(&server, client_transport) != RPC_SUCCESS) { |
||||
free(client_transport); |
free(client_transport); |
||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
// 创建线程处理客户端请求
|
// 创建线程处理客户端请求
|
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
HANDLE thread_handle = CreateThread( |
HANDLE thread_handle = CreateThread( |
||||
NULL, // 默认安全属性
|
NULL, // 默认安全属性
|
||||
0, // 默认堆栈大小
|
0, // 默认堆栈大小
|
||||
handle_client, // 线程函数
|
handle_client, // 线程函数
|
||||
client_transport, // 线程参数
|
client_transport, // 线程参数
|
||||
0, // 默认创建标志
|
0, // 默认创建标志
|
||||
NULL // 线程ID(不需要)
|
NULL // 线程ID(不需要)
|
||||
); |
); |
||||
if (thread_handle == NULL) { |
if (thread_handle == NULL) { |
||||
fprintf(stderr, "CreateThread failed with error code: %d\n", GetLastError()); |
fprintf(stderr, "CreateThread failed with error code: %d\n", GetLastError()); |
||||
rpc_transport_close(client_transport); |
rpc_transport_close(client_transport); |
||||
free(client_transport); |
free(client_transport); |
||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
// 关闭线程句柄但不终止线程,让线程自动结束
|
// 关闭线程句柄但不终止线程,让线程自动结束
|
||||
CloseHandle(thread_handle); |
CloseHandle(thread_handle); |
||||
#else |
#else
|
||||
pthread_t thread_id; |
pthread_t thread_id; |
||||
if (pthread_create(&thread_id, NULL, handle_client, client_transport) != 0) { |
if (pthread_create(&thread_id, NULL, handle_client, client_transport) != 0) { |
||||
perror("pthread_create failed"); |
perror("pthread_create failed"); |
||||
rpc_transport_close(client_transport); |
rpc_transport_close(client_transport); |
||||
free(client_transport); |
free(client_transport); |
||||
continue; |
continue; |
||||
} |
} |
||||
|
|
||||
// 分离线程,自动回收资源
|
// 分离线程,自动回收资源
|
||||
pthread_detach(thread_id); |
pthread_detach(thread_id); |
||||
#endif |
#endif
|
||||
} |
} |
||||
|
|
||||
// 关闭服务器
|
// 关闭服务器
|
||||
rpc_server_close(&server); |
rpc_server_close(&server); |
||||
|
|
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
// 清理Windows套接字库
|
// 清理Windows套接字库
|
||||
rpc_winsock_cleanup(); |
rpc_winsock_cleanup(); |
||||
#endif |
#endif
|
||||
|
|
||||
return 0; |
return 0; |
||||
} |
} |
||||
@ -1,259 +1,259 @@ |
|||||
/*
|
/*
|
||||
* rpc_transport.c |
* rpc_transport.c |
||||
* 实现RPC传输层的功能,处理网络通信 |
* 实现RPC传输层的功能,处理网络通信 |
||||
*/ |
*/ |
||||
|
|
||||
#include "rpc_transport.h" |
#include "rpc_transport.h"
|
||||
|
|
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
/*
|
/*
|
||||
* 初始化Windows套接字库 |
* 初始化Windows套接字库 |
||||
*/ |
*/ |
||||
int rpc_winsock_init() { |
int rpc_winsock_init() { |
||||
WSADATA wsaData; |
WSADATA wsaData; |
||||
int result = WSAStartup(MAKEWORD(2, 2), &wsaData); |
int result = WSAStartup(MAKEWORD(2, 2), &wsaData); |
||||
if (result != 0) { |
if (result != 0) { |
||||
fprintf(stderr, "WSAStartup failed: %d\n", result); |
fprintf(stderr, "WSAStartup failed: %d\n", result); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 清理Windows套接字库 |
* 清理Windows套接字库 |
||||
*/ |
*/ |
||||
void rpc_winsock_cleanup() { |
void rpc_winsock_cleanup() { |
||||
WSACleanup(); |
WSACleanup(); |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* Windows平台的错误打印函数 |
* Windows平台的错误打印函数 |
||||
*/ |
*/ |
||||
static void print_windows_error(const char* message) { |
static void print_windows_error(const char* message) { |
||||
int error_code = WSAGetLastError(); |
int error_code = WSAGetLastError(); |
||||
char* error_text = NULL; |
char* error_text = NULL; |
||||
FormatMessageA( |
FormatMessageA( |
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
||||
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
||||
(LPSTR)&error_text, 0, NULL); |
(LPSTR)&error_text, 0, NULL); |
||||
if (error_text) { |
if (error_text) { |
||||
fprintf(stderr, "%s: %s\n", message, error_text); |
fprintf(stderr, "%s: %s\n", message, error_text); |
||||
LocalFree(error_text); |
LocalFree(error_text); |
||||
} else { |
} else { |
||||
fprintf(stderr, "%s: Error code %d\n", message, error_code); |
fprintf(stderr, "%s: Error code %d\n", message, error_code); |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
#define PRINT_ERROR(msg) print_windows_error(msg) |
#define PRINT_ERROR(msg) print_windows_error(msg)
|
||||
#else |
#else
|
||||
/*
|
/*
|
||||
* Linux/Unix平台的错误打印函数 |
* Linux/Unix平台的错误打印函数 |
||||
*/ |
*/ |
||||
#define PRINT_ERROR(msg) perror(msg) |
#define PRINT_ERROR(msg) perror(msg)
|
||||
#endif |
#endif
|
||||
|
|
||||
/*
|
/*
|
||||
* 初始化RPC服务器 |
* 初始化RPC服务器 |
||||
*/ |
*/ |
||||
int rpc_server_init(rpc_server_t* server, const char* host, uint16_t port, int backlog) { |
int rpc_server_init(rpc_server_t* server, const char* host, uint16_t port, int backlog) { |
||||
if (!server || !host) { |
if (!server || !host) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 创建套接字
|
// 创建套接字
|
||||
server->server_fd = socket(AF_INET, SOCK_STREAM, 0); |
server->server_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
if (server->server_fd == INVALID_SOCKET_VALUE) { |
if (server->server_fd == INVALID_SOCKET_VALUE) { |
||||
PRINT_ERROR("socket creation failed"); |
PRINT_ERROR("socket creation failed"); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 设置套接字选项,允许地址重用
|
// 设置套接字选项,允许地址重用
|
||||
int opt = 1; |
int opt = 1; |
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
// Windows不支持SO_REUSEPORT
|
// Windows不支持SO_REUSEPORT
|
||||
if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, |
if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, |
||||
&opt, sizeof(opt)) != 0) { |
&opt, sizeof(opt)) != 0) { |
||||
#else |
#else
|
||||
// Linux/Unix支持SO_REUSEPORT
|
// Linux/Unix支持SO_REUSEPORT
|
||||
if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, |
if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, |
||||
&opt, sizeof(opt)) != 0) { |
&opt, sizeof(opt)) != 0) { |
||||
#endif |
#endif
|
||||
PRINT_ERROR("setsockopt failed"); |
PRINT_ERROR("setsockopt failed"); |
||||
CLOSE_SOCKET(server->server_fd); |
CLOSE_SOCKET(server->server_fd); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 设置服务器地址结构
|
// 设置服务器地址结构
|
||||
memset(&server->address, 0, sizeof(server->address)); |
memset(&server->address, 0, sizeof(server->address)); |
||||
server->address.sin_family = AF_INET; |
server->address.sin_family = AF_INET; |
||||
server->address.sin_addr.s_addr = inet_addr(host); |
server->address.sin_addr.s_addr = inet_addr(host); |
||||
server->address.sin_port = htons(port); |
server->address.sin_port = htons(port); |
||||
|
|
||||
// 绑定地址到套接字
|
// 绑定地址到套接字
|
||||
if (bind(server->server_fd, (struct sockaddr*)&server->address, sizeof(server->address)) != 0) { |
if (bind(server->server_fd, (struct sockaddr*)&server->address, sizeof(server->address)) != 0) { |
||||
PRINT_ERROR("bind failed"); |
PRINT_ERROR("bind failed"); |
||||
CLOSE_SOCKET(server->server_fd); |
CLOSE_SOCKET(server->server_fd); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 开始监听连接
|
// 开始监听连接
|
||||
if (listen(server->server_fd, backlog) != 0) { |
if (listen(server->server_fd, backlog) != 0) { |
||||
PRINT_ERROR("listen failed"); |
PRINT_ERROR("listen failed"); |
||||
CLOSE_SOCKET(server->server_fd); |
CLOSE_SOCKET(server->server_fd); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
printf("RPC Server started on %s:%d\n", host, port); |
printf("RPC Server started on %s:%d\n", host, port); |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 服务器接受客户端连接 |
* 服务器接受客户端连接 |
||||
*/ |
*/ |
||||
int rpc_server_accept(rpc_server_t* server, rpc_transport_t* transport) { |
int rpc_server_accept(rpc_server_t* server, rpc_transport_t* transport) { |
||||
if (!server || !transport) { |
if (!server || !transport) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
socklen_t addrlen = sizeof(transport->address); |
socklen_t addrlen = sizeof(transport->address); |
||||
transport->socket_fd = accept(server->server_fd, (struct sockaddr*)&transport->address, &addrlen); |
transport->socket_fd = accept(server->server_fd, (struct sockaddr*)&transport->address, &addrlen); |
||||
if (transport->socket_fd == INVALID_SOCKET_VALUE) { |
if (transport->socket_fd == INVALID_SOCKET_VALUE) { |
||||
PRINT_ERROR("accept failed"); |
PRINT_ERROR("accept failed"); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
printf("Client connected: %s:%d\n", |
printf("Client connected: %s:%d\n", |
||||
inet_ntoa(transport->address.sin_addr), |
inet_ntoa(transport->address.sin_addr), |
||||
ntohs(transport->address.sin_port)); |
ntohs(transport->address.sin_port)); |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 关闭RPC服务器 |
* 关闭RPC服务器 |
||||
*/ |
*/ |
||||
void rpc_server_close(rpc_server_t* server) { |
void rpc_server_close(rpc_server_t* server) { |
||||
if (!server || server->server_fd == INVALID_SOCKET_VALUE) { |
if (!server || server->server_fd == INVALID_SOCKET_VALUE) { |
||||
return; |
return; |
||||
} |
} |
||||
|
|
||||
CLOSE_SOCKET(server->server_fd); |
CLOSE_SOCKET(server->server_fd); |
||||
server->server_fd = INVALID_SOCKET_VALUE; |
server->server_fd = INVALID_SOCKET_VALUE; |
||||
printf("RPC Server closed\n"); |
printf("RPC Server closed\n"); |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 初始化RPC客户端传输 |
* 初始化RPC客户端传输 |
||||
*/ |
*/ |
||||
int rpc_client_init(rpc_transport_t* transport, const char* server_host, uint16_t server_port) { |
int rpc_client_init(rpc_transport_t* transport, const char* server_host, uint16_t server_port) { |
||||
if (!transport || !server_host) { |
if (!transport || !server_host) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 创建套接字
|
// 创建套接字
|
||||
transport->socket_fd = socket(AF_INET, SOCK_STREAM, 0); |
transport->socket_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
if (transport->socket_fd == INVALID_SOCKET_VALUE) { |
if (transport->socket_fd == INVALID_SOCKET_VALUE) { |
||||
PRINT_ERROR("socket creation failed"); |
PRINT_ERROR("socket creation failed"); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 设置服务器地址结构
|
// 设置服务器地址结构
|
||||
memset(&transport->address, 0, sizeof(transport->address)); |
memset(&transport->address, 0, sizeof(transport->address)); |
||||
transport->address.sin_family = AF_INET; |
transport->address.sin_family = AF_INET; |
||||
transport->address.sin_port = htons(server_port); |
transport->address.sin_port = htons(server_port); |
||||
|
|
||||
// 将主机名转换为IP地址
|
// 将主机名转换为IP地址
|
||||
if (inet_pton(AF_INET, server_host, &transport->address.sin_addr) <= 0) { |
if (inet_pton(AF_INET, server_host, &transport->address.sin_addr) <= 0) { |
||||
PRINT_ERROR("invalid address"); |
PRINT_ERROR("invalid address"); |
||||
CLOSE_SOCKET(transport->socket_fd); |
CLOSE_SOCKET(transport->socket_fd); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
// 连接到服务器
|
// 连接到服务器
|
||||
if (connect(transport->socket_fd, (struct sockaddr*)&transport->address, sizeof(transport->address)) != 0) { |
if (connect(transport->socket_fd, (struct sockaddr*)&transport->address, sizeof(transport->address)) != 0) { |
||||
PRINT_ERROR("connection failed"); |
PRINT_ERROR("connection failed"); |
||||
CLOSE_SOCKET(transport->socket_fd); |
CLOSE_SOCKET(transport->socket_fd); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
|
|
||||
printf("Connected to server %s:%d\n", server_host, server_port); |
printf("Connected to server %s:%d\n", server_host, server_port); |
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 通过传输层发送数据 |
* 通过传输层发送数据 |
||||
*/ |
*/ |
||||
int rpc_transport_send(rpc_transport_t* transport, const void* data, size_t data_size) { |
int rpc_transport_send(rpc_transport_t* transport, const void* data, size_t data_size) { |
||||
if (!transport || !data || data_size == 0) { |
if (!transport || !data || data_size == 0) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 发送所有数据
|
// 发送所有数据
|
||||
size_t sent_bytes = 0; |
size_t sent_bytes = 0; |
||||
while (sent_bytes < data_size) { |
while (sent_bytes < data_size) { |
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
int bytes = send(transport->socket_fd, (const char*)data + sent_bytes, ( |
int bytes = send(transport->socket_fd, (const char*)data + sent_bytes, ( |
||||
#ifdef _WIN64 |
#ifdef _WIN64
|
||||
int |
int |
||||
#else |
#else
|
||||
int |
int |
||||
#endif |
#endif
|
||||
)(data_size - sent_bytes), 0); |
)(data_size - sent_bytes), 0); |
||||
#else |
#else
|
||||
ssize_t bytes = send(transport->socket_fd, (const char*)data + sent_bytes, data_size - sent_bytes, 0); |
ssize_t bytes = send(transport->socket_fd, (const char*)data + sent_bytes, data_size - sent_bytes, 0); |
||||
#endif |
#endif
|
||||
if (bytes <= 0) { |
if (bytes <= 0) { |
||||
PRINT_ERROR("send failed"); |
PRINT_ERROR("send failed"); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
sent_bytes += bytes; |
sent_bytes += bytes; |
||||
} |
} |
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 通过传输层接收数据 |
* 通过传输层接收数据 |
||||
*/ |
*/ |
||||
int rpc_transport_recv(rpc_transport_t* transport, void* buffer, size_t buffer_size) { |
int rpc_transport_recv(rpc_transport_t* transport, void* buffer, size_t buffer_size) { |
||||
if (!transport || !buffer || buffer_size == 0) { |
if (!transport || !buffer || buffer_size == 0) { |
||||
return RPC_INVALID_ARGS; |
return RPC_INVALID_ARGS; |
||||
} |
} |
||||
|
|
||||
// 接收所有数据
|
// 接收所有数据
|
||||
size_t recv_bytes = 0; |
size_t recv_bytes = 0; |
||||
while (recv_bytes < buffer_size) { |
while (recv_bytes < buffer_size) { |
||||
#ifdef _WIN32 |
#ifdef _WIN32
|
||||
int bytes = recv(transport->socket_fd, (char*)buffer + recv_bytes, ( |
int bytes = recv(transport->socket_fd, (char*)buffer + recv_bytes, ( |
||||
#ifdef _WIN64 |
#ifdef _WIN64
|
||||
int |
int |
||||
#else |
#else
|
||||
int |
int |
||||
#endif |
#endif
|
||||
)(buffer_size - recv_bytes), 0); |
)(buffer_size - recv_bytes), 0); |
||||
#else |
#else
|
||||
ssize_t bytes = recv(transport->socket_fd, (char*)buffer + recv_bytes, buffer_size - recv_bytes, 0); |
ssize_t bytes = recv(transport->socket_fd, (char*)buffer + recv_bytes, buffer_size - recv_bytes, 0); |
||||
#endif |
#endif
|
||||
if (bytes < 0) { |
if (bytes < 0) { |
||||
PRINT_ERROR("recv failed"); |
PRINT_ERROR("recv failed"); |
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} else if (bytes == 0) { |
} else if (bytes == 0) { |
||||
// 连接关闭
|
// 连接关闭
|
||||
return RPC_NET_ERROR; |
return RPC_NET_ERROR; |
||||
} |
} |
||||
recv_bytes += bytes; |
recv_bytes += bytes; |
||||
} |
} |
||||
|
|
||||
return RPC_SUCCESS; |
return RPC_SUCCESS; |
||||
} |
} |
||||
|
|
||||
/*
|
/*
|
||||
* 关闭传输连接 |
* 关闭传输连接 |
||||
*/ |
*/ |
||||
void rpc_transport_close(rpc_transport_t* transport) { |
void rpc_transport_close(rpc_transport_t* transport) { |
||||
if (!transport || transport->socket_fd == INVALID_SOCKET_VALUE) { |
if (!transport || transport->socket_fd == INVALID_SOCKET_VALUE) { |
||||
return; |
return; |
||||
} |
} |
||||
|
|
||||
CLOSE_SOCKET(transport->socket_fd); |
CLOSE_SOCKET(transport->socket_fd); |
||||
transport->socket_fd = INVALID_SOCKET_VALUE; |
transport->socket_fd = INVALID_SOCKET_VALUE; |
||||
} |
} |
||||
@ -1,33 +1,33 @@ |
|||||
@echo off |
@echo off |
||||
REM 简单的测试编译脚本 |
REM 简单的测试编译脚本 |
||||
|
|
||||
REM 设置Visual Studio环境 |
REM 设置Visual Studio环境 |
||||
REM 尝试检测Visual Studio安装路径 |
REM 尝试检测Visual Studio安装路径 |
||||
set VS170COMNTOOLS= |
set VS170COMNTOOLS= |
||||
for /f "delims=" %%i in ('reg query "HKLM\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v "17.0" 2^>nul') do ( |
for /f "delims=" %%i in ('reg query "HKLM\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v "17.0" 2^>nul') do ( |
||||
for /f "tokens=2*" %%j in ("%%i") do set "VS170COMNTOOLS=%%kCommon7\Tools\" |
for /f "tokens=2*" %%j in ("%%i") do set "VS170COMNTOOLS=%%kCommon7\Tools\" |
||||
) |
) |
||||
|
|
||||
REM 如果找不到Visual Studio 2022,尝试其他版本 |
REM 如果找不到Visual Studio 2022,尝试其他版本 |
||||
if not exist "%VS170COMNTOOLS%vsdevcmd.bat" ( |
if not exist "%VS170COMNTOOLS%vsdevcmd.bat" ( |
||||
echo 无法找到Visual Studio 2022环境 |
echo 无法找到Visual Studio 2022环境 |
||||
pause |
pause |
||||
exit /b 1 |
exit /b 1 |
||||
) |
) |
||||
|
|
||||
REM 设置环境变量 |
REM 设置环境变量 |
||||
call "%VS170COMNTOOLS%vsdevcmd.bat" -arch=x64 |
call "%VS170COMNTOOLS%vsdevcmd.bat" -arch=x64 |
||||
|
|
||||
REM 设置编译选项 |
REM 设置编译选项 |
||||
set INCLUDE_DIR=include |
set INCLUDE_DIR=include |
||||
set SRC_DIR=src |
set SRC_DIR=src |
||||
|
|
||||
REM 编译服务器 |
REM 编译服务器 |
||||
cl.exe /I%INCLUDE_DIR% %SRC_DIR%\rpc_server.c %SRC_DIR%\rpc_common.c %SRC_DIR%\rpc_transport.c %SRC_DIR%\rpc_message.c /link ws2_32.lib /out:rpc_server_test.exe |
cl.exe /I%INCLUDE_DIR% %SRC_DIR%\rpc_server.c %SRC_DIR%\rpc_common.c %SRC_DIR%\rpc_transport.c %SRC_DIR%\rpc_message.c /link ws2_32.lib /out:rpc_server_test.exe |
||||
|
|
||||
REM 检查编译结果 |
REM 检查编译结果 |
||||
if %ERRORLEVEL% EQU 0 ( |
if %ERRORLEVEL% EQU 0 ( |
||||
echo 编译成功!可执行文件: rpc_server_test.exe |
echo 编译成功!可执行文件: rpc_server_test.exe |
||||
) else ( |
) else ( |
||||
echo 编译失败! |
echo 编译失败! |
||||
) |
) |
||||
Loading…
Reference in new issue