Browse Source

提交变更

master
xyiege 4 months ago
parent
commit
2464c20d45
  1. 34
      scalib/.gitignore
  2. 40
      scalib/CMakeLists.txt
  3. 166
      scalib/README.md
  4. 120
      scalib/build.sh
  5. 159
      scalib/build_windows.bat
  6. 108
      scalib/convert_encoding.py
  7. 3
      scalib/go.mod
  8. 81
      scalib/include/rpc_common.h
  9. 58
      scalib/include/rpc_message.h
  10. 75
      scalib/include/rpc_transport.h
  11. 21
      scalib/src/CMakeLists.txt
  12. 159
      scalib/src/minimal_client.c
  13. 137
      scalib/src/rpc_file_client.c

34
scalib/.gitignore

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

40
scalib/CMakeLists.txt

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

166
scalib/README.md

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

120
scalib/build.sh

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

159
scalib/build_windows.bat

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

108
scalib/convert_encoding.py

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

3
scalib/go.mod

@ -0,0 +1,3 @@
module scalib
go 1.24.6

81
scalib/include/rpc_common.h

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

58
scalib/include/rpc_message.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 */

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

21
scalib/src/CMakeLists.txt

@ -1,21 +0,0 @@
# C
add_executable(minimal_client
minimal_client.c
)
# RPCUpFileService.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
)

159
scalib/src/minimal_client.c

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

137
scalib/src/rpc_file_client.c

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