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