Rust异步信号处理库signal-hook-async-std的使用:结合async-std实现高效跨平台信号监听与事件驱动
Rust异步信号处理库signal-hook-async-std的使用:结合async-std实现高效跨平台信号监听与事件驱动
signal-hook-async-std是一个async-std适配器库,用于signal-hook crate。它提供了异步信号处理能力,可以与async-std运行时无缝集成。
安装
在项目目录中运行以下Cargo命令:
cargo add signal-hook-async-std
或者在Cargo.toml中添加:
signal-hook-async-std = "0.3.0"
示例代码
以下是使用signal-hook-async-std监听SIGINT信号(CTRL+C)的完整示例:
use async_std::task;
use signal_hook::consts::signal::SIGINT;
use signal_hook_async_std::Signals;
#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建信号监听器,监听SIGINT信号
let mut signals = Signals::new(&[SIGINT])?;
// 启动异步任务处理信号
task::spawn(async move {
while let Some(signal) = signals.next().await {
match signal {
SIGINT => {
println!("Received SIGINT (Ctrl+C), exiting...");
break;
},
_ => unreachable!(),
}
}
}).await;
Ok(())
}
详细说明
- 首先我们创建了一个
Signals
实例,监听SIGINT信号 - 然后我们启动一个异步任务来等待信号
- 当收到SIGINT信号时,打印消息并退出
多信号监听示例
以下是一个监听多个信号的示例:
use async_std::task;
use signal_hook::consts::signal::{SIGINT, SIGTERM, SIGUSR1};
use signal_hook_async_std::Signals;
#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 监听多个信号
let mut signals = Signals::new(&[SIGINT, SIGTERM, SIGUSR1])?;
task::spawn(async move {
while let Some(signal) = signals.next().await {
match signal {
SIGINT => println!("Received SIGINT (Ctrl+C)"),
SIGTERM => println!("Received SIGTERM"),
SIGUSR1 => println!("Received SIGUSR1"),
_ => unreachable!(),
}
}
}).await;
Ok(())
}
完整示例demo
下面是一个更完整的示例,展示如何优雅地处理信号并清理资源:
use async_std::task;
use signal_hook::consts::signal::{SIGINT, SIGTERM};
use signal_hook_async_std::Signals;
use std::time::Duration;
#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建信号监听器,监听SIGINT和SIGTERM信号
let mut signals = Signals::new(&[SIGINT, SIGTERM])?;
// 主应用程序逻辑
let main_task = task::spawn(async {
println!("Application started. Press Ctrl+C to exit.");
loop {
// 模拟应用程序工作
task::sleep(Duration::from_secs(1)).await;
println!("Working...");
}
});
// 信号处理任务
let signal_task = task::spawn(async move {
while let Some(signal) = signals.next().await {
match signal {
SIGINT => {
println!("\nReceived SIGINT (Ctrl+C), shutting down...");
break;
},
SIGTERM => {
println!("\nReceived SIGTERM, shutting down...");
break;
},
_ => unreachable!(),
}
}
});
// 等待任一任务完成
futures::future::select(main_task, signal_task).await;
println!("Cleaning up resources...");
// 这里可以添加资源清理代码
println!("Application exited gracefully.");
Ok(())
}
许可证
signal-hook-async-std采用以下许可证之一:
- Apache License, Version 2.0
- MIT license
贡献
除非您明确声明,否则任何贡献都将按照上述双重许可证提交,不附加任何额外条款或条件。
1 回复
Rust异步信号处理库signal-hook-async-std的使用指南
介绍
signal-hook-async-std
是一个Rust库,它为async-std
运行时提供了异步信号处理能力。这个库建立在signal-hook
之上,专门为async-std
生态系统设计,允许开发者在异步上下文中优雅地处理Unix信号。
主要特点:
- 跨平台支持(主要针对Unix-like系统)
- 与
async-std
运行时无缝集成 - 提供类似事件驱动的信号处理方式
- 线程安全且高效
安装
在Cargo.toml中添加依赖:
[dependencies]
signal-hook-async-std = "0.2"
async-std = "1.12"
基本使用方法
监听单个信号
use async_std::task;
use signal_hook_async_std::Signals;
async fn handle_signals() {
let signals = Signals::new(&[signal_hook::consts::SIGINT]).unwrap();
while let Some(signal) = signals.next().await {
match signal {
signal_hook::consts::SIGINT => {
println!("Received SIGINT (Ctrl+C), shutting down...");
break;
}
_ => unreachable!(),
}
}
}
fn main() {
task::block_on(handle_signals());
}
监听多个信号
use async_std::task;
use signal_hock_async_std::Signals;
use signal_hook::consts::{SIGINT, SIGTERM, SIGQUIT};
async fn handle_multiple_signals() {
let signals = Signals::new(&[SIGINT, SIGTERM, SIGQUIT]).unwrap();
while let Some(signal) = signals.next().await {
match signal {
SIGINT => println!("Received SIGINT (Ctrl+C)"),
SIGTERM => println!("Received SIGTERM (termination request)"),
SIGQUIT => println!("Received SIGQUIT (Ctrl+\\)"),
_ => unreachable!(),
}
}
}
fn main() {
task::block_on(handle_multiple_signals());
}
高级用法
结合async-std任务使用
use async_std::{task, prelude::*};
use signal_hook_async_std::Signals;
use signal_hook::consts::SIGINT;
async fn worker_task() {
for i in 1..=10 {
task::sleep(std::time::Duration::from_secs(1)).await;
println!("Working... {}", i);
}
}
async fn signal_handler() {
let signals = Signals::new(&[SIGINT]).unwrap();
signals.forever().next().await;
println!("Signal received, stopping gracefully...");
}
#[async_std::main]
async fn main() {
let worker = task::spawn(worker_task());
let signal = task::spawn(signal_handler());
worker.race(signal).await;
}
自定义信号处理逻辑
use async_std::{task, sync::Arc};
use signal_hook_async_std::Signals;
use signal_hook::consts::SIGUSR1;
use std::sync::atomic::{AtomicUsize, Ordering};
async fn handle_custom_signal(counter: Arc<AtomicUsize>) {
let signals = Signals::new(&[SIGUSR1]).unwrap();
while let Some(_) = signals.next().await {
let current = counter.fetch_add(1, Ordering::SeqCst);
println!("Received SIGUSR1 signal (count: {})", current + 1);
}
}
#[async_std::main]
async fn main() {
let counter = Arc::new(AtomicUsize::new(0));
let handler = handle_custom_signal(counter.clone());
println!("Send SIGUSR1 to process {} to increment counter", std::process::id());
handler.await;
}
注意事项
- 这个库主要适用于Unix-like系统,Windows支持有限
- 某些信号(如SIGKILL)不能被捕获或处理
- 在异步上下文中处理信号时,应尽量保持处理逻辑简短
- 多个任务监听相同信号时,只有一个会收到通知
实际应用示例:优雅关闭服务
use async_std::{task, net::{TcpListener, TcpStream}, prelude::*};
use signal_hook_async_std::Signals;
use signal_hook::consts::{SIGINT, SIGTERM};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
async fn handle_connection(mut stream: TcpStream, running: Arc<AtomicBool>) {
let mut buf = vec![0u8; 1024];
while running.load(Ordering::Relaxed) {
match stream.read(&mut buf).await {
Ok(n) if n == 0 => break,
Ok(n) => {
println!("Received {} bytes", n);
if let Err(e) = stream.write_all(&buf[..n].await {
eprintln!("Write error: {}", e);
break;
}
}
Err(e) => {
eprintln!("Read error: {}", e);
break;
}
}
}
}
async fn run_server(running: Arc<AtomicBool>) -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
println!("Server listening on port 8080");
while running.load(Ordering::Relaxed) {
match listener.accept().await {
Ok((stream, _)) => {
let running_clone = running.clone();
task::spawn(handle_connection(stream, running_clone));
}
Err(e) => eprintln!("Connection failed: {}", e),
}
}
println!("Server shutting down gracefully...");
Ok(())
}
#[async_std::main]
async fn main() -> std::io::Result<()> {
let running = Arc::new(AtomicBool::new(true));
let running_clone = running.clone();
let signals = Signals::new(&[SIGINT, SIGTERM]).unwrap();
let signal_handler = async move {
signals.forever().next().await;
running_clone.store(false, Ordering::Relaxed);
};
let server = run_server(running);
server.race(signal_handler).await?;
Ok(())
}
这个示例展示了如何结合signal-hook-async-std
和async-std
创建一个可以优雅关闭的TCP服务器,在收到终止信号时能够干净地关闭所有连接。