13 changed files with 3 additions and 1158 deletions
@ -1,34 +0,0 @@ |
|||
# 编译目录 |
|||
build/ |
|||
build_windows/ |
|||
bin/ |
|||
|
|||
# 安装目录 |
|||
install/ |
|||
|
|||
# 生成的可执行文件 |
|||
*.exe |
|||
*.out |
|||
|
|||
# 目标文件 |
|||
*.o |
|||
*.obj |
|||
|
|||
|
|||
# 临时文件 |
|||
*.tmp |
|||
*.temp |
|||
|
|||
# 日志文件 |
|||
*.log |
|||
|
|||
# IDE配置文件 |
|||
.vscode/ |
|||
.idea/ |
|||
*.swp |
|||
*.swo |
|||
*~ |
|||
|
|||
# 操作系统文件 |
|||
.DS_Store |
|||
Thumbs.db |
|||
@ -1,40 +0,0 @@ |
|||
# CMake最低版本要求 |
|||
cmake_minimum_required(VERSION 3.10) |
|||
|
|||
# 项目名称和版本 |
|||
project(rpc_client VERSION 1.0 LANGUAGES C) |
|||
|
|||
# 设置C标准 |
|||
set(CMAKE_C_STANDARD 11) |
|||
set(CMAKE_C_STANDARD_REQUIRED ON) |
|||
|
|||
# 设置生成文件输出目录 |
|||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) |
|||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) |
|||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) |
|||
|
|||
# 输出编译信息 |
|||
message(STATUS "Project: ${PROJECT_NAME}") |
|||
message(STATUS "Version: ${PROJECT_VERSION}") |
|||
message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") |
|||
message(STATUS "C Standard: ${CMAKE_C_STANDARD}") |
|||
|
|||
# 添加头文件搜索路径 |
|||
include_directories(${CMAKE_SOURCE_DIR}/include) |
|||
|
|||
# 添加子目录 |
|||
add_subdirectory(src) |
|||
|
|||
# 添加cmake模块路径 |
|||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) |
|||
|
|||
# 安装目标 |
|||
install(TARGETS minimal_client rpc_file_client |
|||
RUNTIME DESTINATION bin |
|||
) |
|||
|
|||
# 安装头文件 |
|||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ |
|||
DESTINATION include/rpc_demo |
|||
FILES_MATCHING PATTERN "*.h" |
|||
) |
|||
@ -1,166 +0,0 @@ |
|||
# RPC Demo Project
|
|||
|
|||
这是一个用C语言实现的简单RPC(Remote Procedure Call)框架,可以在Linux环境下运行。这个框架允许客户端程序远程调用服务器上的函数,就像调用本地函数一样。 |
|||
|
|||
## 项目结构
|
|||
|
|||
``` |
|||
├── include/ # 头文件目录 |
|||
│ ├── rpc_common.h # 公共定义和工具函数 |
|||
│ ├── rpc_transport.h # 网络传输层接口 |
|||
│ └── rpc_message.h # 消息序列化和反序列化 |
|||
├── src/ # 源代码目录 |
|||
│ ├── rpc_common.c # 公共函数实现 |
|||
│ ├── rpc_transport.c # 传输层实现 |
|||
│ ├── rpc_message.c # 消息处理实现 |
|||
│ ├── rpc_server.c # RPC服务器实现 |
|||
│ ├── rpc_client.c # RPC客户端实现 |
|||
│ └── CMakeLists.txt # 源代码CMake配置 |
|||
├── cmake/ # CMake模块目录 |
|||
├── CMakeLists.txt # 主CMake配置文件 |
|||
└── README.md # 项目说明文档 |
|||
``` |
|||
|
|||
## 功能特性
|
|||
|
|||
- 支持基本数据类型的远程函数调用(int、float、double、string、bool、void) |
|||
- 支持多参数和返回值 |
|||
- 基于TCP/IP协议的网络通信 |
|||
- 多线程服务器设计,支持并发请求 |
|||
- 使用CMake构建系统 |
|||
|
|||
## 编译和构建
|
|||
|
|||
### Linux 平台
|
|||
|
|||
在Linux环境下,使用以下命令编译项目: |
|||
|
|||
```bash |
|||
# 创建构建目录
|
|||
mkdir build && cd build |
|||
|
|||
# 运行CMake配置
|
|||
cmake .. |
|||
|
|||
# 编译项目
|
|||
make |
|||
|
|||
# 安装(可选)
|
|||
make install |
|||
``` |
|||
|
|||
### Windows 平台
|
|||
|
|||
1. 确保已安装 CMake(3.10 或更高版本)和 Visual Studio 2017 或更高版本 |
|||
2. 使用提供的构建脚本(以管理员身份运行命令提示符): |
|||
|
|||
```batch |
|||
build_windows.bat |
|||
``` |
|||
|
|||
3. 构建完成后,可执行文件将位于 `install\bin\` 目录下 |
|||
|
|||
或者手动构建: |
|||
|
|||
```batch |
|||
mkdir build_windows |
|||
cd build_windows |
|||
cmake .. -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=..\install |
|||
cmake --build . --config Release |
|||
cmake --build . --config Release --target install |
|||
``` |
|||
|
|||
### 运行示例
|
|||
|
|||
无论是在Linux还是Windows平台上,运行示例的方式相同: |
|||
|
|||
1. 首先启动服务器: |
|||
```bash |
|||
cd install/bin |
|||
./rpc_server # Linux |
|||
rpc_server.exe # Windows |
|||
``` |
|||
|
|||
2. 在另一个终端启动客户端: |
|||
```bash |
|||
cd install/bin |
|||
./rpc_client # Linux |
|||
rpc_client.exe # Windows |
|||
``` |
|||
|
|||
3. 客户端将连接到服务器并执行两个示例操作: |
|||
- 调用远程加法函数 `add(10, 20)` |
|||
- 调用远程函数获取服务器信息 `get_server_info()` |
|||
|
|||
4. 查看终端输出以确认操作是否成功完成 |
|||
|
|||
## 使用示例
|
|||
|
|||
### 启动服务器
|
|||
|
|||
```bash |
|||
./bin/rpc_server |
|||
``` |
|||
|
|||
服务器将在8080端口上监听客户端连接。 |
|||
|
|||
### 运行客户端
|
|||
|
|||
```bash |
|||
./bin/rpc_client |
|||
``` |
|||
|
|||
客户端将连接到服务器并调用两个示例函数: |
|||
- `add(10, 20)` - 远程加法运算 |
|||
- `get_server_info()` - 获取服务器信息 |
|||
|
|||
## 自定义扩展
|
|||
|
|||
### 注册新的远程函数
|
|||
|
|||
要在服务器端添加新的远程函数,您需要: |
|||
|
|||
1. 实现函数处理器 |
|||
2. 使用`rpc_register_function`注册函数 |
|||
|
|||
示例: |
|||
|
|||
```c |
|||
// 函数实现 |
|||
example_handler(rpc_param_t* params, int args_count, rpc_param_t* return_value) { |
|||
// 函数逻辑 |
|||
return RPC_SUCCESS; |
|||
} |
|||
|
|||
// 注册函数 |
|||
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); |
|||
``` |
|||
|
|||
### 客户端调用新函数
|
|||
|
|||
在客户端调用新注册的函数: |
|||
|
|||
```c |
|||
rpc_param_t params[2]; |
|||
rpc_param_t return_value; |
|||
|
|||
// 设置参数 |
|||
rpc_init_param(¶ms[0], RPC_TYPE_INT); |
|||
params[0].value.int_val = 123; |
|||
|
|||
rpc_init_param(¶ms[1], RPC_TYPE_STRING); |
|||
params[1].value.string_val = "example string"; |
|||
|
|||
// 设置返回值 |
|||
rpc_init_param(&return_value, RPC_TYPE_STRING); |
|||
|
|||
// 调用远程函数 |
|||
int ret = rpc_call(client, "example_func", params, 2, &return_value); |
|||
``` |
|||
|
|||
## 注意事项
|
|||
|
|||
- 本项目是一个教学示例,可能不适合在生产环境中使用 |
|||
- 当前实现中,字符串参数和返回值的处理使用了简单的内存管理策略,在实际应用中可能需要更复杂的处理 |
|||
- 错误处理机制相对简单,实际应用中可能需要更完善的错误处理 |
|||
@ -1,120 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
# RPC项目构建脚本 |
|||
|
|||
# 设置默认构建目录 |
|||
build_dir="build" |
|||
install_prefix="/usr/local" |
|||
|
|||
# 显示帮助信息 |
|||
show_help() { |
|||
echo "用法: $0 [选项]" |
|||
echo "选项:" |
|||
echo " --help 显示帮助信息" |
|||
echo " --clean 清理构建目录" |
|||
echo " --install 安装到系统目录" |
|||
echo " --prefix=DIR 设置安装前缀 (默认: /usr/local)" |
|||
echo " --build-dir=DIR 设置构建目录 (默认: build)" |
|||
} |
|||
|
|||
# 处理命令行参数 |
|||
for arg in "$@"; |
|||
do |
|||
case $arg in |
|||
--help) |
|||
show_help |
|||
exit 0 |
|||
;; |
|||
--clean) |
|||
echo "清理构建目录 $build_dir..." |
|||
rm -rf "$build_dir" |
|||
exit 0 |
|||
;; |
|||
--install) |
|||
install=true |
|||
shift |
|||
;; |
|||
--prefix=*) |
|||
install_prefix="${arg#*=}" |
|||
shift |
|||
;; |
|||
--build-dir=*) |
|||
build_dir="${arg#*=}" |
|||
shift |
|||
;; |
|||
*) |
|||
echo "未知选项: $arg" |
|||
show_help |
|||
exit 1 |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
# 检查是否在Linux环境下运行 |
|||
if [[ "$(uname)" != "Linux" ]]; then |
|||
echo "警告: 这个脚本设计用于Linux环境,您的操作系统可能不兼容" |
|||
echo "如果您在Windows上,可以尝试使用WSL或其他Linux子系统" |
|||
fi |
|||
|
|||
# 检查是否安装了CMake |
|||
if ! command -v cmake &> /dev/null; |
|||
then |
|||
echo "错误: CMake未安装,请先安装CMake" |
|||
echo "Ubuntu/Debian: sudo apt-get install cmake" |
|||
echo "CentOS/RHEL: sudo yum install cmake" |
|||
exit 1 |
|||
fi |
|||
|
|||
# 检查是否安装了GCC |
|||
if ! command -v gcc &> /dev/null; |
|||
then |
|||
echo "错误: GCC编译器未安装,请先安装GCC" |
|||
echo "Ubuntu/Debian: sudo apt-get install gcc" |
|||
echo "CentOS/RHEL: sudo yum install gcc" |
|||
exit 1 |
|||
fi |
|||
|
|||
# 创建构建目录 |
|||
mkdir -p "$build_dir" |
|||
cd "$build_dir" |
|||
|
|||
# 运行CMake配置 |
|||
echo "运行CMake配置..." |
|||
echo "安装前缀: $install_prefix" |
|||
cmake .. -DCMAKE_INSTALL_PREFIX="$install_prefix" |
|||
|
|||
if [ $? -ne 0 ]; |
|||
then |
|||
echo "CMake配置失败,请检查错误信息" |
|||
exit 1 |
|||
fi |
|||
|
|||
# 编译项目 |
|||
echo "编译项目..." |
|||
make -j$(nproc) |
|||
|
|||
if [ $? -ne 0 ]; |
|||
then |
|||
echo "编译失败,请检查错误信息" |
|||
exit 1 |
|||
fi |
|||
|
|||
# 安装(如果请求) |
|||
if [ "$install" = true ]; |
|||
then |
|||
echo "安装项目到 $install_prefix..." |
|||
sudo make install |
|||
|
|||
if [ $? -ne 0 ]; |
|||
then |
|||
echo "安装失败,请检查错误信息" |
|||
exit 1 |
|||
fi |
|||
|
|||
echo "安装成功!" |
|||
fi |
|||
|
|||
# 显示成功信息 |
|||
echo "构建成功! 可执行文件位于 $build_dir/bin/" |
|||
echo "运行服务器: ./$build_dir/bin/rpc_server" |
|||
echo "运行客户端: ./$build_dir/bin/rpc_client" |
|||
@ -1,159 +0,0 @@ |
|||
REM 输出utf8编码 |
|||
chcp 65001 |
|||
|
|||
@echo off |
|||
REM Windows平台构建脚本 - 优化版 |
|||
setlocal enabledelayedexpansion |
|||
|
|||
REM 配置参数 |
|||
set BUILD_DIR=build_windows |
|||
set CMAKE_GENERATOR="Visual Studio 17 2022" |
|||
set INSTALL_PREFIX=install |
|||
set BUILD_TYPE=Release |
|||
set NUM_JOBS=%NUMBER_OF_PROCESSORS% |
|||
set CLEAN_BUILD=0 |
|||
set ONLY_CONFIG=0 |
|||
set ONLY_BUILD=0 |
|||
set SKIP_INSTALL=0 |
|||
|
|||
REM 检查命令行参数 |
|||
:parse_args |
|||
if "%~1"=="" goto end_parse_args |
|||
|
|||
if "%~1"=="--clean" ( |
|||
set CLEAN_BUILD=1 |
|||
shift |
|||
goto parse_args |
|||
) |
|||
|
|||
if "%~1"=="--config-only" ( |
|||
set ONLY_CONFIG=1 |
|||
shift |
|||
goto parse_args |
|||
) |
|||
|
|||
if "%~1"=="--build-only" ( |
|||
set ONLY_BUILD=1 |
|||
shift |
|||
goto parse_args |
|||
) |
|||
|
|||
if "%~1"=="--skip-install" ( |
|||
set SKIP_INSTALL=1 |
|||
shift |
|||
goto parse_args |
|||
) |
|||
|
|||
if "%~1"=="--debug" ( |
|||
set BUILD_TYPE=Debug |
|||
shift |
|||
goto parse_args |
|||
) |
|||
|
|||
if "%~1"=="--jobs" ( |
|||
if not "%~2"=="" ( |
|||
set NUM_JOBS=%~2 |
|||
shift |
|||
shift |
|||
goto parse_args |
|||
) |
|||
) |
|||
|
|||
echo 未知参数: %~1 |
|||
:end_parse_args |
|||
|
|||
REM 显示配置信息 |
|||
cls |
|||
echo ==================================================== |
|||
echo Windows平台构建脚本 - RPC项目 |
|||
echo ==================================================== |
|||
echo 构建目录: %BUILD_DIR% |
|||
echo 生成器: %CMAKE_GENERATOR% |
|||
echo 安装前缀: %INSTALL_PREFIX% |
|||
echo 构建类型: %BUILD_TYPE% |
|||
echo 并行任务数: %NUM_JOBS% |
|||
echo 清理构建: %CLEAN_BUILD% |
|||
echo ==================================================== |
|||
|
|||
REM 清理构建目录(如果需要) |
|||
if %CLEAN_BUILD% equ 1 ( |
|||
echo 正在清理构建目录... |
|||
if exist %BUILD_DIR% ( |
|||
rmdir /s /q %BUILD_DIR% >nul 2>&1 |
|||
if errorlevel 1 ( |
|||
echo 清理构建目录失败,请确保没有进程正在使用该目录。 |
|||
exit /b 1 |
|||
) |
|||
) |
|||
if exist %INSTALL_PREFIX% ( |
|||
rmdir /s /q %INSTALL_PREFIX% >nul 2>&1 |
|||
if errorlevel 1 ( |
|||
echo 清理安装目录失败,请确保没有进程正在使用该目录。 |
|||
exit /b 1 |
|||
) |
|||
) |
|||
) |
|||
|
|||
REM 创建构建目录 |
|||
if not exist %BUILD_DIR% ( |
|||
mkdir %BUILD_DIR% >nul 2>&1 |
|||
if errorlevel 1 ( |
|||
echo 创建构建目录失败。 |
|||
exit /b 1 |
|||
) |
|||
) |
|||
|
|||
REM 运行CMake配置 |
|||
pushd %BUILD_DIR% >nul 2>&1 |
|||
|
|||
if %ONLY_BUILD% equ 0 ( |
|||
echo 正在运行CMake配置... |
|||
cmake .. -G %CMAKE_GENERATOR% -DCMAKE_INSTALL_PREFIX=../%INSTALL_PREFIX% |
|||
if errorlevel 1 ( |
|||
echo CMake配置失败! |
|||
popd >nul 2>&1 |
|||
exit /b 1 |
|||
) |
|||
echo CMake配置成功。 |
|||
|
|||
if %ONLY_CONFIG% equ 1 ( |
|||
echo 已完成配置,跳过构建和安装步骤。 |
|||
popd >nul 2>&1 |
|||
exit /b 0 |
|||
) |
|||
) |
|||
|
|||
REM 构建项目 |
|||
if %SKIP_INSTALL% equ 0 ( |
|||
echo 正在构建项目... [%BUILD_TYPE%] |
|||
cmake --build . --config %BUILD_TYPE% --parallel %NUM_JOBS% |
|||
if errorlevel 1 ( |
|||
echo 构建失败! |
|||
popd >nul 2>&1 |
|||
exit /b 1 |
|||
) |
|||
echo 项目构建成功。 |
|||
|
|||
REM 安装项目 |
|||
echo 正在安装项目... |
|||
cmake --build . --config %BUILD_TYPE% --target install |
|||
if errorlevel 1 ( |
|||
echo 安装失败! |
|||
popd >nul 2>&1 |
|||
exit /b 1 |
|||
) |
|||
echo 项目安装成功。 |
|||
) else ( |
|||
echo 已跳过安装步骤。 |
|||
) |
|||
|
|||
popd >nul 2>&1 |
|||
|
|||
REM 显示构建结果 |
|||
echo ==================================================== |
|||
echo 构建完成! |
|||
echo 服务器可执行文件: %INSTALL_PREFIX%\bin\rpc_server.exe |
|||
echo 客户端可执行文件: %INSTALL_PREFIX%\bin\rpc_client.exe |
|||
echo ==================================================== |
|||
|
|||
exit /b 0 |
|||
@ -1,108 +0,0 @@ |
|||
#!/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() |
|||
@ -0,0 +1,3 @@ |
|||
module scalib |
|||
|
|||
go 1.24.6 |
|||
@ -1,81 +0,0 @@ |
|||
/*
|
|||
* rpc_common.h |
|||
* 定义RPC框架的公共数据结构、常量和工具函数 |
|||
*/ |
|||
|
|||
#ifndef RPC_COMMON_H |
|||
#define RPC_COMMON_H |
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <stdint.h> |
|||
#include <stdbool.h> |
|||
|
|||
/* 错误码定义 */ |
|||
#define RPC_SUCCESS 0 // 成功
|
|||
#define RPC_ERROR -1 // 一般错误
|
|||
#define RPC_NET_ERROR -2 // 网络错误
|
|||
#define RPC_TIMEOUT -3 // 超时错误
|
|||
#define RPC_INVALID_ARGS -4 // 参数无效
|
|||
#define RPC_FUNC_NOT_FOUND -5 // 函数未找到
|
|||
|
|||
/* 最大消息大小 */ |
|||
#define MAX_MESSAGE_SIZE 4096 |
|||
|
|||
/* 最大函数名长度 */ |
|||
#define MAX_FUNC_NAME_LEN 64 |
|||
|
|||
/* 最大参数数量 */ |
|||
#define MAX_ARGS_COUNT 16 |
|||
|
|||
/* 参数类型枚举 */ |
|||
typedef enum { |
|||
RPC_TYPE_INT, |
|||
RPC_TYPE_FLOAT, |
|||
RPC_TYPE_DOUBLE, |
|||
RPC_TYPE_STRING, |
|||
RPC_TYPE_BOOL, |
|||
RPC_TYPE_VOID |
|||
} rpc_param_type_t; |
|||
|
|||
/* 参数数据结构 */ |
|||
typedef struct { |
|||
rpc_param_type_t type; // 参数类型
|
|||
union { |
|||
int32_t int_val; // 整数值
|
|||
float float_val; // 浮点值
|
|||
double double_val; // 双精度值
|
|||
const char* string_val; // 字符串值
|
|||
bool bool_val; // 布尔值
|
|||
} value; // 参数值
|
|||
} rpc_param_t; |
|||
|
|||
/* RPC请求数据结构 */ |
|||
typedef struct { |
|||
char func_name[MAX_FUNC_NAME_LEN]; // 函数名
|
|||
int args_count; // 参数数量
|
|||
rpc_param_t args[MAX_ARGS_COUNT]; // 参数数组
|
|||
} rpc_request_t; |
|||
|
|||
/* RPC响应数据结构 */ |
|||
typedef struct { |
|||
int result_code; // 结果代码
|
|||
rpc_param_type_t return_type; // 返回值类型
|
|||
union { |
|||
int32_t int_val; // 整数值
|
|||
float float_val; // 浮点值
|
|||
double double_val; // 双精度值
|
|||
const char* string_val; // 字符串值
|
|||
bool bool_val; // 布尔值
|
|||
} return_value; // 返回值
|
|||
} rpc_response_t; |
|||
|
|||
/* 工具函数声明 */ |
|||
void rpc_init_param(rpc_param_t* param, rpc_param_type_t type); |
|||
void rpc_free_params(rpc_param_t* params, int count); |
|||
void rpc_free_request(rpc_request_t* request); |
|||
void rpc_free_response(rpc_response_t* response); |
|||
const char* rpc_error_to_string(int error_code); |
|||
|
|||
#endif /* RPC_COMMON_H */ |
|||
@ -1,58 +0,0 @@ |
|||
/*
|
|||
* rpc_message.h |
|||
* 定义RPC消息的序列化和反序列化接口 |
|||
*/ |
|||
#ifndef RPC_MESSAGE_H |
|||
#define RPC_MESSAGE_H |
|||
|
|||
#include "rpc_common.h" |
|||
#include "rpc_transport.h" |
|||
|
|||
/* 消息类型枚举 */ |
|||
typedef enum { |
|||
RPC_MESSAGE_REQUEST, // 请求消息
|
|||
RPC_MESSAGE_RESPONSE // 响应消息
|
|||
} rpc_message_type_t; |
|||
|
|||
/* RPC消息头部 */ |
|||
typedef struct { |
|||
rpc_message_type_t type; // 消息类型
|
|||
uint32_t payload_size; // 负载大小
|
|||
} rpc_message_header_t; |
|||
|
|||
/* RPC消息结构 */ |
|||
typedef struct { |
|||
rpc_message_header_t header; // 消息头部
|
|||
union { |
|||
rpc_request_t request; // 请求消息
|
|||
rpc_response_t response; // 响应消息
|
|||
} payload; // 消息负载
|
|||
} rpc_message_t; |
|||
|
|||
/* 消息处理函数声明 */ |
|||
|
|||
// 序列化请求消息到缓冲区
|
|||
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_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_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_send_response(rpc_transport_t* transport, const rpc_response_t* response); |
|||
|
|||
// 接收响应消息
|
|||
int rpc_recv_response(rpc_transport_t* transport, rpc_response_t* response); |
|||
|
|||
#endif /* RPC_MESSAGE_H */ |
|||
@ -1,75 +0,0 @@ |
|||
/*
|
|||
* rpc_transport.h |
|||
* 定义RPC传输层的接口,负责处理网络通信 |
|||
*/ |
|||
|
|||
#ifndef RPC_TRANSPORT_H |
|||
#define RPC_TRANSPORT_H |
|||
#include "rpc_common.h" |
|||
/* 根据不同平台包含不同的头文件 */ |
|||
|
|||
#ifdef _WIN32 |
|||
#include <winsock2.h> |
|||
#include <ws2tcpip.h> |
|||
#pragma comment(lib, "ws2_32.lib") |
|||
/* Windows平台的类型定义 */ |
|||
typedef SOCKET socket_t; |
|||
#define INVALID_SOCKET_VALUE INVALID_SOCKET |
|||
#define CLOSE_SOCKET(s) closesocket(s) |
|||
|
|||
/* Windows平台初始化和清理函数 */ |
|||
int rpc_winsock_init(); |
|||
void rpc_winsock_cleanup(); |
|||
#else |
|||
|
|||
/* Linux/Unix平台的头文件 */ |
|||
#include <sys/socket.h> |
|||
#include <netinet/in.h> |
|||
#include <arpa/inet.h> |
|||
#include <unistd.h> |
|||
|
|||
/* Linux/Unix平台的类型定义 */ |
|||
typedef int socket_t; |
|||
#define INVALID_SOCKET_VALUE (-1) |
|||
#define CLOSE_SOCKET(s) close(s) |
|||
|
|||
/* Linux/Unix平台不需要特殊的初始化和清理 */ |
|||
#define rpc_winsock_init() 0 |
|||
#define rpc_winsock_cleanup() |
|||
#endif |
|||
/* 传输上下文 */ |
|||
|
|||
typedef struct { |
|||
socket_t socket_fd; // 套接字文件描述符
|
|||
struct sockaddr_in address; // 地址信息
|
|||
} rpc_transport_t; |
|||
|
|||
/* 服务器上下文 */ |
|||
typedef struct { |
|||
socket_t server_fd; // 服务器套接字文件描述符
|
|||
struct sockaddr_in address; // 服务器地址信息
|
|||
} rpc_server_t; |
|||
|
|||
/* 传输层函数声明 */ |
|||
// 初始化服务器
|
|||
|
|||
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); |
|||
// 关闭服务器
|
|||
|
|||
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_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); |
|||
// 关闭传输连接
|
|||
|
|||
void rpc_transport_close(rpc_transport_t* transport); |
|||
#endif /* RPC_TRANSPORT_H */ |
|||
@ -1,21 +0,0 @@ |
|||
# 最小化客户端(仅标准C库) |
|||
add_executable(minimal_client |
|||
minimal_client.c |
|||
) |
|||
|
|||
# RPC文件客户端(支持UpFileService.SendFileInfo调用) |
|||
add_executable(rpc_file_client |
|||
rpc_file_client.c |
|||
) |
|||
|
|||
# RPC文件客户端链接 |
|||
if(WIN32) |
|||
target_link_libraries(rpc_file_client |
|||
ws2_32 # Windows套接字库 |
|||
) |
|||
endif() |
|||
|
|||
# 安装目标 |
|||
install(TARGETS minimal_client rpc_file_client |
|||
RUNTIME DESTINATION bin |
|||
) |
|||
@ -1,159 +0,0 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#ifdef _WIN32 |
|||
#include <winsock2.h> |
|||
#include <ws2tcpip.h> |
|||
#pragma comment(lib, "ws2_32.lib") |
|||
#define close closesocket |
|||
#else |
|||
#include <unistd.h> |
|||
#include <sys/socket.h> |
|||
#include <netinet/in.h> |
|||
#include <arpa/inet.h> |
|||
#endif |
|||
|
|||
// 文件信息结构体
|
|||
typedef struct { |
|||
char filepath[256]; |
|||
long long file_size; |
|||
time_t modify_time; |
|||
} FileInfo; |
|||
|
|||
// 初始化Winsock库(Windows平台)
|
|||
#ifdef _WIN32 |
|||
int init_winsock() { |
|||
WSADATA wsaData; |
|||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { |
|||
printf("Winsock initialization failed\n"); |
|||
return -1; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
// 清理Winsock库(Windows平台)
|
|||
void cleanup_winsock() { |
|||
WSACleanup(); |
|||
} |
|||
#else |
|||
#define init_winsock() 0 |
|||
#define cleanup_winsock() |
|||
#endif |
|||
|
|||
// UpFileService.SendFileInfo RPC调用函数
|
|||
int send_file_info(const char* server, int port, const char* filepath) { |
|||
// 创建套接字
|
|||
int sockfd = socket(AF_INET, SOCK_STREAM, 0); |
|||
if (sockfd < 0) { |
|||
printf("Failed to create socket\n"); |
|||
return -1; |
|||
} |
|||
|
|||
// 设置服务器地址
|
|||
struct sockaddr_in server_addr; |
|||
memset(&server_addr, 0, sizeof(server_addr)); |
|||
server_addr.sin_family = AF_INET; |
|||
server_addr.sin_port = htons(port); |
|||
|
|||
// 将服务器地址字符串转换为网络地址
|
|||
#ifdef _WIN32 |
|||
if (inet_pton(AF_INET, server, &(server_addr.sin_addr)) <= 0) { |
|||
#else |
|||
if (inet_aton(server, &(server_addr.sin_addr)) == 0) { |
|||
#endif |
|||
printf("Invalid server address\n"); |
|||
close(sockfd); |
|||
return -1; |
|||
} |
|||
|
|||
// 连接到服务器
|
|||
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { |
|||
printf("Failed to connect to server\n"); |
|||
close(sockfd); |
|||
return -1; |
|||
} |
|||
|
|||
printf("Connected to UpFileService at %s:%d\n", server, port); |
|||
|
|||
// 准备文件信息
|
|||
FileInfo file_info; |
|||
strncpy(file_info.filepath, filepath, sizeof(file_info.filepath) - 1); |
|||
file_info.filepath[sizeof(file_info.filepath) - 1] = '\0'; |
|||
|
|||
// 这里简化处理,实际应用中应该从文件系统获取真实的文件大小和修改时间
|
|||
file_info.file_size = 0; |
|||
file_info.modify_time = time(NULL); |
|||
|
|||
// 构造RPC请求:调用UpFileService.SendFileInfo方法
|
|||
char rpc_request[1024]; |
|||
sprintf(rpc_request, "RPC CALL: UpFileService.SendFileInfo\n" \ |
|||
"Filepath: %s\n" \ |
|||
"FileSize: %lld\n" \ |
|||
"ModifyTime: %lld\n", |
|||
file_info.filepath, file_info.file_size, file_info.modify_time); |
|||
|
|||
// 发送RPC请求
|
|||
if (send(sockfd, rpc_request, strlen(rpc_request), 0) < 0) { |
|||
printf("Failed to send RPC request\n"); |
|||
close(sockfd); |
|||
return -1; |
|||
} |
|||
|
|||
printf("Sent file info to server: %s\n", filepath); |
|||
|
|||
// 接收服务器响应
|
|||
char buffer[1024] = {0}; |
|||
int bytes_read = recv(sockfd, buffer, sizeof(buffer) - 1, 0); |
|||
if (bytes_read < 0) { |
|||
printf("Failed to receive response\n"); |
|||
close(sockfd); |
|||
return -1; |
|||
} else if (bytes_read == 0) { |
|||
printf("Server closed connection\n"); |
|||
close(sockfd); |
|||
return -1; |
|||
} |
|||
|
|||
// 输出服务器响应
|
|||
printf("Server response: %s\n", buffer); |
|||
|
|||
// 关闭套接字
|
|||
close(sockfd); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// 最小化的RPC客户端示例
|
|||
int main(int argc, char* argv[]) { |
|||
const char* server = "127.0.0.1"; |
|||
int port = 8080; |
|||
char filepath[256] = {0}; |
|||
|
|||
if (argc >= 3) { |
|||
server = argv[1]; |
|||
port = atoi(argv[2]); |
|||
} |
|||
|
|||
// 初始化网络库
|
|||
if (init_winsock() != 0) { |
|||
return 1; |
|||
} |
|||
|
|||
printf("Client connecting to %s:%d\n", server, port); |
|||
printf("Enter file path: "); |
|||
fgets(filepath, sizeof(filepath), stdin); |
|||
filepath[strcspn(filepath, "\n")] = '\0'; |
|||
|
|||
// 调用UpFileService.SendFileInfo方法
|
|||
if (send_file_info(server, port, filepath) != 0) { |
|||
printf("Failed to call UpFileService.SendFileInfo\n"); |
|||
cleanup_winsock(); |
|||
return 1; |
|||
} |
|||
|
|||
// 清理网络库
|
|||
cleanup_winsock(); |
|||
|
|||
return 0; |
|||
} |
|||
@ -1,137 +0,0 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <time.h> |
|||
|
|||
#ifdef _WIN32 |
|||
#include <winsock2.h> |
|||
#include <ws2tcpip.h> |
|||
#pragma comment(lib, "ws2_32.lib") |
|||
#define CLOSE_SOCKET(s) closesocket(s) |
|||
#else |
|||
#include <unistd.h> |
|||
#include <sys/socket.h> |
|||
#include <netinet/in.h> |
|||
#include <arpa/inet.h> |
|||
#define CLOSE_SOCKET(s) close(s) |
|||
#define SOCKET int |
|||
#define INVALID_SOCKET -1 |
|||
#define SOCKET_ERROR -1 |
|||
#endif |
|||
|
|||
// RPC client for UpFileService
|
|||
int send_file_info_rpc(const char* server_ip, int server_port, const char* file_path) { |
|||
#ifdef _WIN32 |
|||
WSADATA wsaData; |
|||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { |
|||
printf("WSAStartup failed\n"); |
|||
return -1; |
|||
} |
|||
#endif |
|||
|
|||
// Create socket
|
|||
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); |
|||
if (sock == INVALID_SOCKET) { |
|||
printf("Socket creation failed\n"); |
|||
#ifdef _WIN32 |
|||
WSACleanup(); |
|||
#endif |
|||
return -1; |
|||
} |
|||
|
|||
// Server address structure
|
|||
struct sockaddr_in server_addr; |
|||
memset(&server_addr, 0, sizeof(server_addr)); |
|||
server_addr.sin_family = AF_INET; |
|||
server_addr.sin_port = htons(server_port); |
|||
|
|||
// Convert IP address
|
|||
#ifdef _WIN32 |
|||
if (inet_pton(AF_INET, server_ip, &(server_addr.sin_addr)) <= 0) { |
|||
#else |
|||
if (inet_aton(server_ip, &(server_addr.sin_addr)) == 0) { |
|||
#endif |
|||
printf("Invalid server IP address\n"); |
|||
CLOSE_SOCKET(sock); |
|||
#ifdef _WIN32 |
|||
WSACleanup(); |
|||
#endif |
|||
return -1; |
|||
} |
|||
|
|||
// Connect to server
|
|||
if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) { |
|||
printf("Connection to server failed\n"); |
|||
CLOSE_SOCKET(sock); |
|||
#ifdef _WIN32 |
|||
WSACleanup(); |
|||
#endif |
|||
return -1; |
|||
} |
|||
|
|||
printf("Connected to UpFileService at %s:%d\n", server_ip, server_port); |
|||
|
|||
// Prepare RPC request for UpFileService.SendFileInfo
|
|||
char request[1024]; |
|||
time_t now = time(NULL); |
|||
|
|||
sprintf(request, "{\"service\":\"UpFileService\",\"method\":\"SendFileInfo\",\"params\":{\"filepath\":\"%s\",\"timestamp\":%lld}}", |
|||
file_path, (long long)now); |
|||
|
|||
printf("Sending request: %s\n", request); |
|||
|
|||
// Send RPC request
|
|||
if (send(sock, request, strlen(request), 0) == SOCKET_ERROR) { |
|||
printf("Failed to send RPC request\n"); |
|||
CLOSE_SOCKET(sock); |
|||
#ifdef _WIN32 |
|||
WSACleanup(); |
|||
#endif |
|||
return -1; |
|||
} |
|||
|
|||
printf("Sent file info: %s\n", file_path); |
|||
|
|||
// Receive response (simple implementation)
|
|||
char buffer[1024] = {0}; |
|||
int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); |
|||
if (bytes_received > 0) { |
|||
printf("Server response: %s\n", buffer); |
|||
} else { |
|||
printf("No response from server\n"); |
|||
} |
|||
|
|||
// Cleanup
|
|||
CLOSE_SOCKET(sock); |
|||
#ifdef _WIN32 |
|||
WSACleanup(); |
|||
#endif |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
// 函数主要入口
|
|||
int main(int argc, char* argv[]) { |
|||
const char* server_ip = "127.0.0.1"; |
|||
int server_port = 8080; |
|||
char file_path[256] = {0}; |
|||
|
|||
// Parse command line arguments
|
|||
if (argc >= 3) { |
|||
server_ip = argv[1]; |
|||
server_port = atoi(argv[2]); |
|||
} |
|||
|
|||
// Get file path from user
|
|||
printf("Enter file path: "); |
|||
fgets(file_path, sizeof(file_path), stdin); |
|||
file_path[strcspn(file_path, "\n")] = '\0'; |
|||
|
|||
// Call UpFileService.SendFileInfo
|
|||
if (send_file_info_rpc(server_ip, server_port, file_path) != 0) { |
|||
printf("RPC call failed\n"); |
|||
return 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
Loading…
Reference in new issue