Browse Source

更改文件编码为linux

master
xyiege 4 months ago
parent
commit
820805dd10
  1. 1
      scalib/.gitignore
  2. 330
      scalib/README.md
  3. 120
      scalib/build_windows.bat
  4. 108
      scalib/convert_encoding.py
  5. 116
      scalib/include/rpc_message.h
  6. 152
      scalib/include/rpc_transport.h
  7. 108
      scalib/src/CMakeLists.txt
  8. 192
      scalib/src/rpc_common.c
  9. 380
      scalib/src/rpc_message.c
  10. 590
      scalib/src/rpc_server.c
  11. 516
      scalib/src/rpc_transport.c
  12. 64
      scalib/test_compile.cmd

1
scalib/.gitignore

@ -14,6 +14,7 @@ install/
*.o *.o
*.obj *.obj
# 临时文件 # 临时文件
*.tmp *.tmp
*.temp *.temp

330
scalib/README.md

@ -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(&params[0], RPC_TYPE_INT); rpc_init_param(&params[0], RPC_TYPE_INT);
params[0].value.int_val = 123; params[0].value.int_val = 123;
rpc_init_param(&params[1], RPC_TYPE_STRING); rpc_init_param(&params[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);
``` ```
## 注意事项 ## 注意事项
- 本项目是一个教学示例,可能不适合在生产环境中使用 - 本项目是一个教学示例,可能不适合在生产环境中使用
- 当前实现中,字符串参数和返回值的处理使用了简单的内存管理策略,在实际应用中可能需要更复杂的处理 - 当前实现中,字符串参数和返回值的处理使用了简单的内存管理策略,在实际应用中可能需要更复杂的处理
- 错误处理机制相对简单,实际应用中可能需要更完善的错误处理 - 错误处理机制相对简单,实际应用中可能需要更完善的错误处理

120
scalib/build_windows.bat

@ -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

108
scalib/convert_encoding.py

@ -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()

116
scalib/include/rpc_message.h

@ -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 */

152
scalib/include/rpc_transport.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 */

108
scalib/src/CMakeLists.txt

@ -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
) )

192
scalib/src/rpc_common.c

@ -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";
} }
} }

380
scalib/src/rpc_message.c

@ -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;
} }

590
scalib/src/rpc_server.c

@ -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;
} }

516
scalib/src/rpc_transport.c

@ -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;
} }

64
scalib/test_compile.cmd

@ -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…
Cancel
Save