我想从 C++ 控制台应用程序启动简单的 actix-web 服务器作为概念证明。 这是我在 Rust 代码中的尝试:
use std::{io};
use actix_web::{get, middleware::Logger, App, HttpServer, Responder};
use actix_web_lab::{respond::Html};
#[no_mangle]
pub extern "C" fn API_Start_Server() {
println!("Rust about to launch server.");
actix_web::rt::spawn(async move {
// Thread will be consumed until server is closed.
let _ = start_server();
});
println!("Server has been launched, returning.");
}
#[actix_web::main]
async fn start_server() -> io::Result<()> {
HttpServer::new(move || {
App::new()
.service(index)
.wrap(Logger::default())
})
.bind(("127.0.0.1", 8080))?
.workers(2)
.run()
.await
}
#[get("/")]
async fn index() -> impl Responder {
Html(include_str!("../../Client-Side/index.html").to_string())
}
但显然我做错了什么,因为当我从我的 C++ 代码中调用
API_Start_Server
时:
#include <iostream>
#include <windows.h> // Windows API header
// Function signature for initializing and starting the Actix server
typedef void (*StartServerFn)();
int main()
{
std::wstring wsRelativePath = L"..\\..\\..\\..\\..\..\\..\\target\\release\\actix_server_library.dll";
// Load the Rust shared library
HINSTANCE handle = LoadLibrary(wsRelativePath.c_str());
if (!handle) {
std::cerr << "Error loading shared library: " << GetLastError() << std::endl;
return 1;
}
// Get a function pointer to the Actix server's entry point
StartServerFn startServer = (StartServerFn)GetProcAddress(handle, "API_Start_Server");
if (!startServer) {
std::cerr << "Error finding function symbol: " << GetLastError() << std::endl;
FreeLibrary(handle);
return 1;
}
try
{
// Call the Rust function to start the Actix server on a new thread
startServer();
}
catch (std::exception ex)
{
std::cerr << ex.what();
}
// Continue with other tasks in the main thread
// ...
// Wait for the Actix server to finish (in a real application, you may use proper synchronization)
std::cout << "Press Enter to exit..." << std::endl;
std::cin.get();
// Clean up and close the shared library
FreeLibrary(handle);
return 0;
}
抛出异常,在控制台日志中我可以看到以下消息:
Rust about to launch server.
thread '<unnamed>' panicked at '`spawn_local` called from outside of a `task::LocalSet`', src/Server-Side/Rust/lib.rs:10:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
我知道我可能没有通过生成另一个线程来正确调用服务器创建,并且我可能需要一些状态来存储服务器,但我对 Rust 和 actix 很陌生,找不到任何如何执行此操作的示例。如何从外部线程创建服务器,并在从 C++ 端加载 dll 的情况下使其保持活动状态?
使用
actix_web::rt::spawn
生成一个 task(您不需要),并且它还需要在现有运行时(您没有)中运行。 #[actix_web::main]
属性已经通过创建自己的运行时将 async
函数转换为非异步函数。因此,要在后台运行它,您只需要 std::thread::spawn
:
#[no_mangle]
pub extern "C" fn API_Start_Server() {
println!("Rust about to launch server.");
std::thread::spawn(|| {
// Thread will be consumed until server is closed.
let _ = start_server();
});
println!("Server has been launched, returning.");
}