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 命名管道。示例中:

  1. 首先创建命名管道文件
  2. 启动写入线程向管道写入数据
  3. 启动读取线程从管道读取数据
  4. 最后清理删除管道文件

注意:在实际使用中,通常会在不同的进程中运行读写操作,这里使用线程是为了演示方便。

完整示例代码

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

注意事项

  1. 确保有足够的权限创建和访问管道文件
  2. 管道文件需要在使用完毕后进行清理
  3. 考虑使用绝对路径来避免路径解析问题
  4. 在多进程环境中注意同步访问

性能优化建议

  • 使用适当大小的缓冲区(通常4KB-64KB)
  • 考虑使用零拷贝技术处理大数据传输
  • 在需要高吞吐量的场景中使用异步IO

这个库为Rust开发者提供了简单而强大的Unix域套接字通信能力,适用于各种本地进程间通信场景。

回到顶部