Browse Source

增加windows下的适配

master
xyiege 2 months ago
parent
commit
3de62f0d82
  1. 47
      scalib/README.md
  2. 61
      scalib/build_windows.bat
  3. 43
      scalib/include/rpc_transport.h
  4. 32
      scalib/src/CMakeLists.txt
  5. 17
      scalib/src/rpc_client.c
  6. 49
      scalib/src/rpc_server.c
  7. 125
      scalib/src/rpc_transport.c

47
scalib/README.md

@ -31,6 +31,8 @@
## 编译和构建
### Linux 平台
在Linux环境下,使用以下命令编译项目:
```bash
@ -47,6 +49,51 @@ 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. 查看终端输出以确认操作是否成功完成
## 使用示例
### 启动服务器

61
scalib/build_windows.bat

@ -0,0 +1,61 @@
@echo off
REM Windows平台构建脚本
REM 配置参数
set BUILD_DIR=build_windows
set CMAKE_GENERATOR="Visual Studio 17 2022"
set INSTALL_PREFIX=install
REM 检查命令行参数
:parse_args
if "%1"=="--clean" (
echo Cleaning build directory...
if exist %BUILD_DIR% rmdir /s /q %BUILD_DIR%
if exist %INSTALL_PREFIX% rmdir /s /q %INSTALL_PREFIX%
shift
)
REM 创建构建目录
if not exist %BUILD_DIR% mkdir %BUILD_DIR%
REM 运行CMake配置
pushd %BUILD_DIR%
echo Running CMake configuration...
cmake .. -G %CMAKE_GENERATOR% -DCMAKE_INSTALL_PREFIX=../%INSTALL_PREFIX%
if %ERRORLEVEL% neq 0 (
echo CMake configuration failed!
popd
exit /b 1
)
REM 构建项目
echo Building project...
cmake --build . --config Release
if %ERRORLEVEL% neq 0 (
echo Build failed!
popd
exit /b 1
)
REM 安装项目
echo Installing project...
cmake --build . --config Release --target install
if %ERRORLEVEL% neq 0 (
echo Installation failed!
popd
exit /b 1
)
popd
echo Build completed successfully!
echo Server executable: %INSTALL_PREFIX%\bin\rpc_server.exeecho Client executable: %INSTALL_PREFIX%\bin\rpc_client.exe
echo
echo To run the server:
cd %INSTALL_PREFIX%\bin
echo rpc_server.exe
echo
echo Then in another terminal:
echo rpc_client.exe

43
scalib/include/rpc_transport.h

@ -7,21 +7,48 @@
#define RPC_TRANSPORT_H
#include "rpc_common.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.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 {
int socket_fd; // 套接字文件描述符
struct sockaddr_in address; // 地址信息
socket_t socket_fd; // 套接字文件描述符
struct sockaddr_in address; // 地址信息
} rpc_transport_t;
/* 服务器上下文 */
typedef struct {
int server_fd; // 服务器套接字文件描述符
struct sockaddr_in address; // 服务器地址信息
socket_t server_fd; // 服务器套接字文件描述符
struct sockaddr_in address; // 服务器地址信息
} rpc_server_t;
/* 传输层函数声明 */

32
scalib/src/CMakeLists.txt

@ -15,20 +15,36 @@ add_executable(rpc_server
rpc_server.c
)
target_link_libraries(rpc_server
rpc_common
pthread
)
#
if(WIN32)
target_link_libraries(rpc_server
rpc_common
ws2_32 # Windows
)
else()
target_link_libraries(rpc_server
rpc_common
pthread
)
endif()
# RPC
add_executable(rpc_client
rpc_client.c
)
target_link_libraries(rpc_client
rpc_common
pthread
)
#
if(WIN32)
target_link_libraries(rpc_client
rpc_common
ws2_32 # Windows
)
else()
target_link_libraries(rpc_client
rpc_common
pthread
)
endif()
#
install(TARGETS rpc_common rpc_server rpc_client

17
scalib/src/rpc_client.c

@ -7,6 +7,10 @@
#include "rpc_transport.h"
#include "rpc_message.h"
#ifdef _WIN32
#include <windows.h>
#endif
/*
* RPC客户端结构
*/
@ -192,6 +196,14 @@ int main(int argc, char* argv[]) {
rpc_client_t client;
const char* server_host = "127.0.0.1";
uint16_t server_port = 8080;
#ifdef _WIN32
// 初始化Windows套接字库
if (rpc_winsock_init() != RPC_SUCCESS) {
printf("Failed to initialize Winsock\n");
return 1;
}
#endif
// 初始化客户端
printf("Connecting to RPC server at %s:%d...\n", server_host, server_port);
@ -225,6 +237,11 @@ int main(int argc, char* argv[]) {
// 清理资源
rpc_client_destroy(&client);
printf("Client disconnected\n");
#ifdef _WIN32
// 清理Windows套接字库
rpc_winsock_cleanup();
#endif
return 0;
}

49
scalib/src/rpc_server.c

@ -6,7 +6,23 @@
#include "rpc_common.h"
#include "rpc_transport.h"
#include "rpc_message.h"
#ifdef _WIN32
#include <windows.h>
typedef DWORD WINAPI (*ThreadFunction)(LPVOID lpParam);
#else
#include <pthread.h>
#endif
/*
* Windows平台的线程函数包装器
*/
#ifdef _WIN32
DWORD WINAPI thread_wrapper(LPVOID lpParam) {
handle_client(lpParam);
return 0;
}
#endif
/* 函数处理函数类型定义 */
typedef int (*rpc_handler_func_t)(rpc_param_t* params, int args_count, rpc_param_t* return_value);
@ -202,6 +218,14 @@ int get_server_info_handler(rpc_param_t* params, int args_count, rpc_param_t* re
int main(int argc, char* argv[]) {
rpc_server_t server;
int port = 8080;
#ifdef _WIN32
// 初始化Windows套接字库
if (rpc_winsock_init() != RPC_SUCCESS) {
printf("Failed to initialize Winsock\n");
return 1;
}
#endif
// 注册示例函数
rpc_param_type_t add_params[] = {RPC_TYPE_INT, RPC_TYPE_INT};
@ -231,6 +255,25 @@ int main(int argc, char* argv[]) {
}
// 创建线程处理客户端请求
#ifdef _WIN32
HANDLE thread_handle = CreateThread(
NULL, // 默认安全属性
0, // 默认堆栈大小
thread_wrapper, // 线程函数
client_transport, // 线程参数
0, // 默认创建标志
NULL // 线程ID(不需要)
);
if (thread_handle == NULL) {
fprintf(stderr, "CreateThread failed with error code: %d\n", GetLastError());
rpc_transport_close(client_transport);
free(client_transport);
continue;
}
// 关闭线程句柄但不终止线程,让线程自动结束
CloseHandle(thread_handle);
#else
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, handle_client, client_transport) != 0) {
perror("pthread_create failed");
@ -241,10 +284,16 @@ int main(int argc, char* argv[]) {
// 分离线程,自动回收资源
pthread_detach(thread_id);
#endif
}
// 关闭服务器
rpc_server_close(&server);
#ifdef _WIN32
// 清理Windows套接字库
rpc_winsock_cleanup();
#endif
return 0;
}

125
scalib/src/rpc_transport.c

@ -5,6 +5,53 @@
#include "rpc_transport.h"
#ifdef _WIN32
/*
* Windows套接字库
*/
int rpc_winsock_init() {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
fprintf(stderr, "WSAStartup failed: %d\n", result);
return RPC_NET_ERROR;
}
return RPC_SUCCESS;
}
/*
* Windows套接字库
*/
void rpc_winsock_cleanup() {
WSACleanup();
}
/*
* Windows平台的错误打印函数
*/
static void print_windows_error(const char* message) {
int error_code = WSAGetLastError();
char* error_text = NULL;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&error_text, 0, NULL);
if (error_text) {
fprintf(stderr, "%s: %s\n", message, error_text);
LocalFree(error_text);
} else {
fprintf(stderr, "%s: Error code %d\n", message, error_code);
}
}
#define PRINT_ERROR(msg) print_windows_error(msg)
#else
/*
* Linux/Unix平台的错误打印函数
*/
#define PRINT_ERROR(msg) perror(msg)
#endif
/*
* RPC服务器
*/
@ -15,17 +62,17 @@ int rpc_server_init(rpc_server_t* server, const char* host, uint16_t port, int b
// 创建套接字
server->server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server->server_fd < 0) {
perror("socket creation failed");
if (server->server_fd == INVALID_SOCKET_VALUE) {
PRINT_ERROR("socket creation failed");
return RPC_NET_ERROR;
}
// 设置套接字选项,允许地址重用
int opt = 1;
if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt))) {
perror("setsockopt failed");
close(server->server_fd);
&opt, sizeof(opt)) != 0) {
PRINT_ERROR("setsockopt failed");
CLOSE_SOCKET(server->server_fd);
return RPC_NET_ERROR;
}
@ -36,16 +83,16 @@ int rpc_server_init(rpc_server_t* server, const char* host, uint16_t port, int b
server->address.sin_port = htons(port);
// 绑定地址到套接字
if (bind(server->server_fd, (struct sockaddr*)&server->address, sizeof(server->address)) < 0) {
perror("bind failed");
close(server->server_fd);
if (bind(server->server_fd, (struct sockaddr*)&server->address, sizeof(server->address)) != 0) {
PRINT_ERROR("bind failed");
CLOSE_SOCKET(server->server_fd);
return RPC_NET_ERROR;
}
// 开始监听连接
if (listen(server->server_fd, backlog) < 0) {
perror("listen failed");
close(server->server_fd);
if (listen(server->server_fd, backlog) != 0) {
PRINT_ERROR("listen failed");
CLOSE_SOCKET(server->server_fd);
return RPC_NET_ERROR;
}
@ -63,8 +110,8 @@ int rpc_server_accept(rpc_server_t* server, rpc_transport_t* transport) {
socklen_t addrlen = sizeof(transport->address);
transport->socket_fd = accept(server->server_fd, (struct sockaddr*)&transport->address, &addrlen);
if (transport->socket_fd < 0) {
perror("accept failed");
if (transport->socket_fd == INVALID_SOCKET_VALUE) {
PRINT_ERROR("accept failed");
return RPC_NET_ERROR;
}
@ -78,12 +125,12 @@ int rpc_server_accept(rpc_server_t* server, rpc_transport_t* transport) {
* RPC服务器
*/
void rpc_server_close(rpc_server_t* server) {
if (!server || server->server_fd < 0) {
if (!server || server->server_fd == INVALID_SOCKET_VALUE) {
return;
}
close(server->server_fd);
server->server_fd = -1;
CLOSE_SOCKET(server->server_fd);
server->server_fd = INVALID_SOCKET_VALUE;
printf("RPC Server closed\n");
}
@ -97,8 +144,8 @@ int rpc_client_init(rpc_transport_t* transport, const char* server_host, uint16_
// 创建套接字
transport->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (transport->socket_fd < 0) {
perror("socket creation failed");
if (transport->socket_fd == INVALID_SOCKET_VALUE) {
PRINT_ERROR("socket creation failed");
return RPC_NET_ERROR;
}
@ -109,15 +156,15 @@ int rpc_client_init(rpc_transport_t* transport, const char* server_host, uint16_
// 将主机名转换为IP地址
if (inet_pton(AF_INET, server_host, &transport->address.sin_addr) <= 0) {
perror("invalid address");
close(transport->socket_fd);
PRINT_ERROR("invalid address");
CLOSE_SOCKET(transport->socket_fd);
return RPC_NET_ERROR;
}
// 连接到服务器
if (connect(transport->socket_fd, (struct sockaddr*)&transport->address, sizeof(transport->address)) < 0) {
perror("connection failed");
close(transport->socket_fd);
if (connect(transport->socket_fd, (struct sockaddr*)&transport->address, sizeof(transport->address)) != 0) {
PRINT_ERROR("connection failed");
CLOSE_SOCKET(transport->socket_fd);
return RPC_NET_ERROR;
}
@ -136,9 +183,19 @@ int rpc_transport_send(rpc_transport_t* transport, const void* data, size_t data
// 发送所有数据
size_t sent_bytes = 0;
while (sent_bytes < data_size) {
#ifdef _WIN32
int bytes = send(transport->socket_fd, (const char*)data + sent_bytes, (
#ifdef _WIN64
int
#else
int
#endif
)(data_size - sent_bytes), 0);
#else
ssize_t bytes = send(transport->socket_fd, (const char*)data + sent_bytes, data_size - sent_bytes, 0);
if (bytes < 0) {
perror("send failed");
#endif
if (bytes <= 0) {
PRINT_ERROR("send failed");
return RPC_NET_ERROR;
}
sent_bytes += bytes;
@ -158,9 +215,19 @@ int rpc_transport_recv(rpc_transport_t* transport, void* buffer, size_t buffer_s
// 接收所有数据
size_t recv_bytes = 0;
while (recv_bytes < buffer_size) {
#ifdef _WIN32
int bytes = recv(transport->socket_fd, (char*)buffer + recv_bytes, (
#ifdef _WIN64
int
#else
int
#endif
)(buffer_size - recv_bytes), 0);
#else
ssize_t bytes = recv(transport->socket_fd, (char*)buffer + recv_bytes, buffer_size - recv_bytes, 0);
#endif
if (bytes < 0) {
perror("recv failed");
PRINT_ERROR("recv failed");
return RPC_NET_ERROR;
} else if (bytes == 0) {
// 连接关闭
@ -176,10 +243,10 @@ int rpc_transport_recv(rpc_transport_t* transport, void* buffer, size_t buffer_s
*
*/
void rpc_transport_close(rpc_transport_t* transport) {
if (!transport || transport->socket_fd < 0) {
if (!transport || transport->socket_fd == INVALID_SOCKET_VALUE) {
return;
}
close(transport->socket_fd);
transport->socket_fd = -1;
CLOSE_SOCKET(transport->socket_fd);
transport->socket_fd = INVALID_SOCKET_VALUE;
}
Loading…
Cancel
Save