60269


私はソケットを用いてシンプルなサーバーとクライアントを作成しました。

[code]

    use std::env;
    #[macro_use]
    extern crate log;
    
    mod client;
    mod server;
    
    fn main() {
        env::set_var("RUST_LOG", "debug");
        env_logger::init();
        let args: Vec<String> = env::args().collect();
        if args.len() != 3 {
            error!("Please specify [server|client] [addr:port].");
            std::process::exit(1);
        }
        let role: &str = &args[1];
        let address = &args[2];
    
        match role {
            "server" => {
                server::serve(address).unwrap_or_else(|e| error!("{}", e));
            }
            "client" => {
                client::connect(address).unwrap_or_else(|e| error!("{}", e));
            }
            _ => {
                missing_role();
            }
        }
    }
    
    fn missing_role() {
        error!("Please specify server or client on the 1st argument.");
        std::process::exit(1);
    }
    
[/code]

[code]

    use std::io::{Read, Write};
    use std::net::{TcpListener, TcpStream};
    use std::{str, thread};
    
    pub fn serve(address: &str) -> Result<(), failure::Error> {
        let listener = TcpListener::bind(address)?;
        loop {
            let (stream, _) = listener.accept()?;
            thread::spawn(move || {
                handler(stream).unwrap_or_else(|error| error!("{:?}", error));
            });
        }
    }
    
    fn handler(mut stream: TcpStream) -> Result<(), failure::Error> {
        debug!("Handling data from {}", stream.peer_addr()?);
        let mut buffer = [0u8; 1024];
        loop {
            let nbytes = stream.read(&mut buffer)?;
            if nbytes == 0 {
                debug!("Connection closed.");
                return Ok(());
            }
            print!("{}", str::from_utf8(&buffer[..nbytes])?);
            stream.write_all(&buffer[..nbytes])?;
        }
    }
    
[/code]

[code]

    use std::io::{self, Write};
    use std::net::TcpStream;
    use std::str;
    
    pub fn connect(address: &str) -> Result<(), failure::Error> {
        let mut stream = TcpStream::connect(address)?;
    
        loop {
            let mut input = String::new();
            io::stdin().read_line(&mut input)?;
            stream.write_all(input.as_bytes())?;
        }
    }
    
[/code]

私は`main.rs`でserverのソケット待ち受け時に別の処理を実行したいと考えています。

しかし、以下のように書いても`server::serve(address).unwrap_or_else(|e| error!("{}",
e));`以降は実行されません。

[code]

    use std::env;
    #[macro_use]
    extern crate log;
    
    mod client;
    mod server;
    
    fn main() {
        env::set_var("RUST_LOG", "debug");
        env_logger::init();
        let args: Vec<String> = env::args().collect();
        if args.len() != 3 {
            error!("Please specify [server|client] [addr:port].");
            std::process::exit(1);
        }
        let role: &str = &args[1];
        let address = &args[2];
    
        match role {
            "server" => {
                server::serve(address).unwrap_or_else(|e| error!("{}", e));
                println!("hogehoge");
            }
            "client" => {
                client::connect(address).unwrap_or_else(|e| error!("{}", e));
            }
            _ => {
                missing_role();
            }
        }
    }
    
    fn missing_role() {
        error!("Please specify server or client on the 1st argument.");
        std::process::exit(1);
    }
    
[/code]

これは、ソケットの待ち受け状態に入っていて、関数が終了していないためだと考えています。

どうすれば、ソケットの待ち受け時に別の処理を実行できるでしょうか？


CC BY-SA 4.0
2019-11-05T01:30:48.963
60256
2019-11-05T05:26:30.890
36479
question
socket rust
ソケットの待ち受け時に別の処理を実行する


`serve`関数と同じく、スレッドを使って並列処理を実現してみます。`"server"`の分岐を次のように書き換えてみてください。

[code]

            "server" => {
                let address = address.to_owned();
    
                let handle = thread::spawn(move || {
                    server::serve(&address).unwrap_or_else(|e| error!("{}", e));
                });
    
                println!("hogehoge");
    
                handle.join().unwrap();
            }
    
[/code]

メインスレッドが終了するとプログラム自体が終了してしまうので、分岐したスレッドの終了を待つために`join`しています。


CC BY-SA 4.0
2019-11-05T03:28:59.630
60261
2019-11-05T03:28:59.630
13199
60256
answer


スレッドを使う方法のほかにノンブロックIOを使う方法もあります。

[code]

    pub fn serve(address: &str) -> Result<(), failure::Error> {
        let listener = TcpListener::bind(address)?;
        listener.set_nonblocking(true)?;
        loop {
            match listener.accept() {
                Ok((stream, _)) => {
                    println!("accept");
                    stream.set_nonblocking(false)?;
                    thread::spawn(move || {
                        handler(stream).unwrap_or_else(|error| error!("{:?}", error));
                    });
                }
                Err(e) => {
                    //error!("{:?}", e);
                    println!("hogehoge");
                }
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2019-11-05T05:26:30.890
60269
2019-11-05T05:26:30.890
241
60256
answer