LoginSignup
11
8

More than 5 years have passed since last update.

pipeをweb socketにつなぐコマンドをRustで書いてみた

Last updated at Posted at 2018-10-09

wspipe

Linuxのプロセス間通信であるpipeをweb socketにつないで、インターネットをまたいで使えるようなコマンドをRustで書いてみました。

ソースコードはgithub に上げました。
https://github.com/tetsu-koba/wspipe-rs

使用方法

stdin2wsws2stdout という2つのコマンドがあります。
ws2stdout が受信側でありweb socketを開いてlistenします。
そこにstdin2wsで送信することができます。

例として、受信側(ipアドレスは192.168.10.120)では以下のようにしてポート8001にweb socketを作って待ち受けます。

./ws2stdout 0.0.0.0:8001 |tee kern.log

それに対して、以下のように/var/log/kern.log をwebsocket経由で流すことができます。

sudo tail -f /var/log/kern.log | ./stdin2ws ws://192.168.10.120:8001

これはある実験のために作ったのですが、それに関しては次の記事で。
(2018.10.10 書きました。Websocketで簡単に音声のストリーミングをしてみる)

つまずいたところ

websocketにはws-rs のクレートを使用しています。
https://crates.io/crates/ws

pub fn stdin2websocket(url: &str) {
    let (sender, receiver) = channel::<u32>();
    if let Err(error) = connect(url, |out| {
        let s2 = sender.clone();
        thread::spawn(move || {
            send_binary(&out);
            thread::sleep(time::Duration::from_millis(100));
            out.close(CloseCode::Normal).unwrap();
            s2.send(1).unwrap();
        });

        msg_handler
    })
    {
        println!("Failed to create WebSocket due to: {:?}", error);
    }
    receiver.recv().unwrap();
}

ws::connect() の引数で渡すクロージャの中でスレッドを起こしてstdinからwebsocketに転送をするのですが、このスレッドの終了を待つ方法で苦労しました。
このクロージャが FnMut であり、複数回実行される可能性のあるものであるため、単純に所有権をmove させることができないのです。コンパイルエラーになります。
channelのsenderをcloneして渡せばよいということに気がつくまでかなりかかりました。
channelはreceiverはcloneできませんが、senderはclone可能です。
(パッケージ名のmpscはMulti-producer, single-consumer の意味)

また、転送終了後にcloseする前に100msのwaitを入れましたが、これが無いとcloseがエラーになります。まだwebsocketの処理が完了していないためと思われるのですが、ちょっと解せません。バグを踏んでいるのか、やり方が間違っているのか。

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8