Rust Unix域套接字通信库unix-named-pipe的使用,实现高效进程间通信(IPC)与本地数据传输
unix-named-pipe
unix-named-pipe
是一个用于简化 Unix 平台上命名管道创建和使用的库
用法
extern crate unix_named_pipe;
...
let filename = "/var/run/application.pipe";
let mode: u32 = 0o644
// 创建一个新的命名管道
unix_named_pipe::create(filename, mode)?;
// 打开一个命名管道用于读取
let read_file = unix_named_pipe::open_read(filename)?;
// 打开一个命名管道用于写入(追加)
let write_file = unix_named_pipe::open_write(filename)?;
贡献
欢迎并鼓励拉取请求。可以通过问题跟踪器或电子邮件提问。
任何贡献都将不胜感激 <3。
许可证
根据 MIT 许可证授权。有关详细信息,请参阅 LICENSE。
完整示例代码
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;
extern crate unix_named_pipe;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 定义命名管道文件路径
let filename = "/tmp/my_named_pipe.pipe";
// 设置文件权限模式
let mode: u32 = 0o644;
// 创建命名管道
unix_named_pipe::create(filename, mode)?;
// 启动写入线程
let writer_thread = thread::spawn({
let filename = filename.to_string();
move || {
// 打开管道用于写入
let mut write_file = unix_named_pipe::open_write(&filename).unwrap();
// 写入一些数据
let message = "Hello from writer process!";
write_file.write_all(message.as_bytes()).unwrap();
println!("Writer: Sent message: {}", message);
// 短暂延迟
thread::sleep(Duration::from_millis(100));
}
});
// 启动读取线程
let reader_thread = thread::spawn({
let filename = filename.to_string();
move || {
// 打开管道用于读取
let mut read_file = unix_named_pipe::open_read(&filename).unwrap();
// 读取数据
let mut buffer = [0; 1024];
let bytes_read = read_file.read(&mut buffer).unwrap();
let message = String::from_utf8_lossy(&buffer[..bytes_read]);
println!("Reader: Received message: {}", message);
}
});
// 等待线程完成
writer_thread.join().unwrap();
reader_thread.join().unwrap();
// 清理:删除管道文件
std::fs::remove_file(filename)?;
Ok(())
}
# Cargo.toml 依赖配置
[dependencies]
unix-named-pipe = "0.2.0"
这个示例展示了如何使用 unix-named-pipe
库创建、写入和读取 Unix 命名管道。示例中:
- 首先创建命名管道文件
- 启动写入线程向管道写入数据
- 启动读取线程从管道读取数据
- 最后清理删除管道文件
注意:在实际使用中,通常会在不同的进程中运行读写操作,这里使用线程是为了演示方便。
完整示例代码
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;
extern crate unix_named_pipe;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 定义命名管道文件路径
let filename = "/tmp/my_named_pipe.pipe";
// 设置文件权限模式
let mode: u32 = 0o644;
// 创建命名管道
unix_named_pipe::create(filename, mode)?;
// 启动写入线程
let writer_thread = thread::spawn({
let filename = filename.to_string();
move || {
// 打开管道用于写入
let mut write_file = unix_named_pipe::open_write(&filename).unwrap();
// 写入一些数据
let message = "Hello from writer process!";
write_file.write_all(message.as_bytes()).unwrap();
println!("Writer: Sent message: {}", message);
// 短暂延迟
thread::sleep(Duration::from_millis(100));
}
});
// 启动读取线程
let reader_thread = thread::spawn({
let filename = filename.to_string();
move || {
// 打开管道用于读取
let mut read_file = unix_named_pipe::open_read(&filename).unwrap();
// 读取数据
let mut buffer = [0; 1024];
let bytes_read = read_file.read(&mut buffer).unwrap();
let message = String::from_utf8_lossy(&buffer[..bytes_read]);
println!("Reader: Received message: {}", message);
}
});
// 等待线程完成
writer_thread.join().unwrap();
reader_thread.join().unwrap();
// 清理:删除管道文件
std::fs::remove_file(filename)?;
Ok(())
}
# Cargo.toml 依赖配置
[dependencies]
unix-named-pipe = "0.2.0"
1 回复
Rust Unix域套接字通信库unix-named-pipe使用指南
概述
unix-named-pipe是一个专门用于Unix域套接字通信的Rust库,提供高效的进程间通信(IPC)和本地数据传输解决方案。该库封装了Unix命名管道(FIFO)的底层操作,为Rust开发者提供了简单易用的API接口。
主要特性
- 类型安全的API设计
- 同步和异步通信支持
- 跨平台兼容性(Unix-like系统)
- 高性能的零拷贝数据传输
- 完善的错误处理机制
安装方法
在Cargo.toml中添加依赖:
[dependencies]
unix-named-pipe = "0.3"
基本使用方法
1. 创建命名管道
use unix_named_pipe::Pipe;
fn main() -> std::io::Result<()> {
// 创建命名管道
let pipe_path = "/tmp/my_pipe";
Pipe::create(pipe_path)?;
println!("命名管道已创建: {}", pipe_path);
Ok(())
}
2. 写入数据到管道
use unix_named_pipe::{Pipe, PipeOptions};
use std::io::Write;
fn writer() -> std::io::Result<()> {
let pipe_path = "/tmp/my_pipe";
let mut pipe = PipeOptions::new(pipe_path).open_write()?;
// 写入数据
pipe.write_all(b"Hello from writer process!")?;
println!("数据已写入管道");
Ok(())
}
3. 从管道读取数据
use unix_named_pipe::{Pipe, PipeOptions};
use std::io::Read;
fn reader() -> std::io::Result<()> {
let pipe_path = "/tmp/my_pipe";
let mut pipe = PipeOptions::new(pipe_path).open_read()?;
// 读取数据
let mut buffer = [0; 1024];
let bytes_read = pipe.read(&mut buffer)?;
println!("收到数据: {}",
String::from_utf8_lossy(&buffer[..bytes_read]));
Ok(())
}
4. 双向通信示例
use unix_named_pipe::{Pipe, PipeOptions};
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;
fn bidirectional_communication() -> std::io::Result<()> {
let pipe_path = "/tmp/bidirectional_pipe";
// 创建管道
Pipe::create(pipe_path)?;
// 启动读取线程
let reader_thread = thread::spawn(move || {
let mut pipe = PipeOptions::new(pipe_path).open_read().unwrap();
let mut buffer = [0; 256];
loop {
match pipe.read(&mut buffer) {
Ok(0) => break, // 连接关闭
Ok(n) => {
println!("收到: {}", String::from_utf8_lossy(&buffer[..n]));
}
Err(e) => {
eprintln!("读取错误: {}", e);
break;
}
}
}
});
// 主线程作为写入者
let mut pipe = PipeOptions::new(pipe_path).open_write()?;
for i in 0..5 {
let message = format!("消息 {}", i);
pipe.write_all(message.as_bytes())?;
println!("已发送: {}", message);
thread::sleep(Duration::from_secs(1));
}
// 等待读取线程结束
reader_thread.join().unwrap();
// 清理管道
std::fs::remove_file(pipe_path)?;
Ok(())
}
高级用法
异步通信
use unix_named_pipe::{Pipe, PipeOptions};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::fs;
async fn async_example() -> std::io::Result<()> {
let pipe_path = "/tmp/async_pipe";
// 创建异步管道
Pipe::create(pipe_path)?;
// 异步写入
let write_task = tokio::spawn(async move {
let mut pipe = PipeOptions::new(pipe_path).open_async_write().await?;
pipe.write_all(b"异步消息").await?;
Ok::<_, std::io::Error>(())
});
// 异步读取
let read_task = tokio::spawn(async move {
let mut pipe = PipeOptions::new(pipe_path).open_async_read().await?;
let mut buffer = [0; 128];
let n = pipe.read(&mut buffer).await?;
println!("异步收到: {}", String::from_utf8_lossy(&buffer[..n]));
Ok::<_, std::io::Error>(())
});
write_task.await??;
read_task.await??;
fs::remove_file(pipe_path).await?;
Ok(())
}
错误处理最佳实践
use unix_named_pipe::{Pipe, PipeOptions, Error};
use std::io;
fn robust_example() -> Result<(), Error> {
let pipe_path = "/tmp/robust_pipe";
// 尝试创建管道,处理可能存在的错误
match Pipe::create(pipe_path) {
Ok(_) => println!("管道创建成功"),
Err(Error::Io(io_err)) if io_err.kind() == io::ErrorKind::AlreadyExists => {
println!("管道已存在,继续使用");
}
Err(e) => return Err(e),
}
Ok(())
}
完整示例demo
以下是一个完整的客户端-服务器通信示例:
use unix_named_pipe::{Pipe, PipeOptions};
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;
use std::process;
// 服务器端函数
fn server() -> std::io::Result<()> {
let pipe_path = "/tmp/example_pipe";
// 创建命名管道
println!("服务器: 创建管道...");
Pipe::create(pipe_path)?;
// 打开管道进行读取
println!("服务器: 等待客户端连接...");
let mut pipe = PipeOptions::new(pipe_path).open_read()?;
let mut buffer = [0; 1024];
// 持续读取数据
loop {
match pipe.read(&mut buffer) {
Ok(0) => {
println!("服务器: 客户端断开连接");
break;
}
Ok(n) => {
let message = String::from_utf8_lossy(&buffer[..n]);
println!("服务器收到: {}", message);
// 如果是退出命令,则退出循环
if message.trim() == "exit" {
println!("服务器: 收到退出命令");
break;
}
}
Err(e) => {
eprintln!("服务器读取错误: {}", e);
break;
}
}
}
// 清理管道文件
println!("服务器: 清理管道文件...");
std::fs::remove_file(pipe_path)?;
Ok(())
}
// 客户端函数
fn client() -> std::io::Result<()> {
let pipe_path = "/tmp/example_pipe";
// 等待服务器创建管道
thread::sleep(Duration::from_secs(1));
// 打开管道进行写入
println!("客户端: 连接到服务器...");
let mut pipe = PipeOptions::new(pipe_path).open_write()?;
// 发送几条测试消息
let messages = [
"Hello, Server!",
"This is a test message",
"How are you?",
"exit" // 退出命令
];
for message in messages.iter() {
println!("客户端发送: {}", message);
pipe.write_all(message.as_bytes())?;
thread::sleep(Duration::from_secs(1));
}
Ok(())
}
fn main() -> std::io::Result<()> {
// 使用fork创建子进程
match unsafe { libc::fork() } {
-1 => panic!("fork失败"),
0 => {
// 子进程作为客户端
client()?;
process::exit(0);
}
_ => {
// 父进程作为服务器
server()?;
}
}
Ok(())
}
注意事项
- 确保有足够的权限创建和访问管道文件
- 管道文件需要在使用完毕后进行清理
- 考虑使用绝对路径来避免路径解析问题
- 在多进程环境中注意同步访问
性能优化建议
- 使用适当大小的缓冲区(通常4KB-64KB)
- 考虑使用零拷贝技术处理大数据传输
- 在需要高吞吐量的场景中使用异步IO
这个库为Rust开发者提供了简单而强大的Unix域套接字通信能力,适用于各种本地进程间通信场景。