#io-uring #async-io #linux-networking #high #performance #zero-copy #future

libuio

基于io_uring的异步框架,旨在Linux上进行高性能网络

5个不稳定版本

0.3.0 2024年7月28日
0.2.1 2024年7月28日
0.2.0 2024年7月28日
0.1.1 2024年7月14日
0.1.0 2024年7月14日

#554 in 异步

Download history 183/week @ 2024-07-12 11/week @ 2024-07-19 282/week @ 2024-07-26 39/week @ 2024-08-02

每月515次下载

Apache-2.0

105KB
2K SLoC

libuio

Crates.io Version docs.rs GitHub branch check runs

一个高性能的Linux特定异步框架,基于io_uring,支持零拷贝网络。


lib.rs:

libuio

这是一个功能齐全的异步框架,旨在在Linux上运行,针对高性能网络解决方案进行了优化。其设计上本质上是多线程的,并在底层使用io_uring作为I/O驱动程序。这使得相对于epollpollselect等技术,实现了前所未有的效率提升。该包被拆分为几个模块,每个模块处理所需功能的一个特定子集。

有关详细示例,请参阅此存储库根目录下的examples目录。

从高层次来看,一个简单的TCP回声服务器按预期工作

use std::io;

use futures::StreamExt;

use libuio::net::TcpListener;

#[libuio::main]
async fn main() -> io::Result<()> {
    // Since we are demonstrating a TCP server, lets start by creating a new TcpListener that
    // is set to listen on [::]:9091 and have a connection backlog of 1024.
    let mut listener = TcpListener::with_outstanding("[::]", 9091, 1024)?;

    let mut buf = vec![0u8; 1024];

    println!("Listening on: {}", listener.local_addr());

    // Or we can grab a async stream of incoming connections, this is using the
    // opcode::AcceptMulti, which is a highly efficient implementation of the standard accept
    // loop. This will loop endlessly until dropped or there is an unrecoverable error.
    //
    // Note that you want to call incoming OUTSIDE of a loop like bellow, otherwise you will
    // be implicitly droping/recrating the incoming future which results in performance worse
    // than that of a a `listener.accept().await` loop would provide.
    let mut incoming = listener.incoming();
    while let Some(conn) = incoming.next().await {
        let mut conn = match conn {
            Ok(conn) => conn,
            Err(e) => {
                println!("Oh no we had an error: {}", e);
                continue;
            }
        };

        println!("Got connection from: {}", conn.peer_addr());

        let read = match conn.recv(buf.as_mut_slice()).await {
            Ok(ret) => ret,
            Err(e) => {
                println!("Failed to receive from client: {}", e);
                continue;
            }
        };

        let s = String::from_utf8_lossy(&buf[..read]);

        println!("Client request: {}", s);

        conn.send(&buf[..read])
            .await
            .expect("Failed to respond to client.");
    }
    Ok(())
}

同样,这里有一个与上述服务器交互的TCP客户端示例

use std::{io, net::SocketAddr};

use libuio::net::TcpStream;

#[libuio::main]
async fn main() -> io::Result<()> {
    println!("Connecting to remote server.");

    let remote_addr: SocketAddr = "[::1]:9091".parse().unwrap();
    let mut client = TcpStream::new(false)?;

    // Connect to the defined remote host.
    client.connect(&remote_addr).await?;

    println!(
        "Connected to remote peer {}, local address: {}",
        client.peer_addr(),
        client.local_addr(),
    );

    // Send some data to the remote host.
    client.send("Hello from client!".as_bytes()).await?;

    // Now read back anything the server sent and then exit.
    let mut buf = vec![0u8; 1024];
    let read = client.recv(buf.as_mut_slice()).await?;

    let str = String::from_utf8_lossy(&buf[..read]);
    println!("Server response: {}", str);
    Ok(())
}

如上述示例所示,这几乎可以直接替换std::net::TcpListenerstd::net::TcpStream

依赖项

~3.5MB
~67K SLoC