RustでUnix Domain Socketを扱う方法
"rust domain socket"とかで検索するといろいろ引っかかるけどいかんせんライブラリの更新が早くて情報が古かったりするのでここに現状を書きます(この文章もすぐに古くなるかもしれないので後から読む人は注意してください..)
基本
std::os::unix::net
- 元は rust-lang-nursery/unix-socketだったものが,stdに取り込まれたもの(rfc)
std::net::TcpListener
等と同様の使い勝手
- nix
- setsockoptしたいときやancillary dataをsendmsgで送りたいときに有用(例)
- libc
- 硬派な人向け
async/await
- mio-uds
- mioをdomain socketに対応させたもの
- 後述のtokio, async-stdもこれを利用
tokio::net::unix
async_std::os::unix::net
- async-std版
- 現在バグってて動きません
- 1.0が出るころにはきっと修正されているはず
HTTPサーバ
- actix-web
- udsのサポートがある(例)
- hyper
- hyperlocalを使う
例
std::os::unix::net::{UnixListner, UnixStream}
use std::fs; use std::io::prelude::*; use std::os::unix::net::{UnixListener, UnixStream}; use std::path::Path; use std::thread; fn handle_client(mut stream: UnixStream) -> std::io::Result<()> { let mut buf = [0; 1024]; let n = stream.read(&mut buf)?; let s = String::from_utf8_lossy(&buf[..n]); println!("{}", s); Ok(()) } fn main() -> Result<(), Box<dyn std::error::Error>> { let sockfile = Path::new("/tmp/uds.sock"); if sockfile.exists() { fs::remove_file(&sockfile)?; } let listner = UnixListener::bind(sockfile)?; for stream in listner.incoming() { let stream = stream?; thread::spawn(move || handle_client(stream).unwrap()); } Ok(()) }
// cargo-deps: tokio="0.2.0-alpha.6", tokio-net="0.2.0-alpha.6", futures-preview="0.3.0-alpha.19" use std::fs; use std::path::Path; use futures::StreamExt; use tokio; use tokio::io::AsyncReadExt; use tokio::net::unix::{UnixListener, UnixStream}; async fn handle_client(mut stream: UnixStream) -> Result<(), Box<dyn std::error::Error>> { let mut buf = [0; 1024]; let n = stream.read(&mut buf).await?; let s = String::from_utf8_lossy(&buf[..n]); println!("{}", s); Ok(()) } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let sockfile = Path::new("/tmp/uds.sock"); if sockfile.exists() { fs::remove_file(&sockfile)?; } let listner = UnixListener::bind(sockfile)?; let mut incoming = listner.incoming(); while let Some(stream) = incoming.next().await { let stream = stream?; tokio::spawn(async move { handle_client(stream).await.unwrap(); }); } Ok(()) }