LoginSignup
3
1

More than 3 years have passed since last update.

TCPサーバーをRustで作成したときの記録②

Posted at

前に作成したTCPサーバーに改良を加える

前に作成したTCPサーバーは,受け取ったデータを表示してくれないので,少し改良を加えて受け取ったデータを表示できるようにしました。

コード

前に作成したコード

mod errors;
mod result;

#[cfg(test)]
mod tests;

use std::io::{Error, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;

pub use self::errors::ServerSessionError;
pub use self::result::ServerSessionResult;

pub struct Server {
    addr: Option<String>,
}

impl Server {
    pub fn new() -> Result<(Server, Vec<ServerSessionResult>), ServerSessionError> {
        let server = Server {
            addr: Some("somewhere".to_string()),
        };

        let mut results = Vec::with_capacity(4);

        Ok((server, results))
    }

    pub fn listen_and_serve(self) {
        // Build a server
        let listener = TcpListener::bind("127.0.0.1:1935").expect("Error: Failed to bind");
        println!("Listening...");
        for streams in listener.incoming() {
            match streams {
                Err(e) => { eprintln!("error: {}", e) },
                Ok(stream) => {
                    thread::spawn(move || {
                        handler(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
                    });
                }
            }
        }
    }
}

fn handler(mut stream: TcpStream) -> Result<(), Error> {
    println!("Connection from {}", stream.peer_addr()?);
    let mut buffer = [0; 1024];
    loop {
        let nbytes = stream.read(&mut buffer)?;
        if nbytes == 0 {
            return Ok(());
        }

        stream.write(&buffer[..nbytes])?;
        stream.flush()?;
    }
}

今回改良を加えたコード

mod errors;
mod result;

#[cfg(test)]
mod tests;

use std::io::{Error, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;

pub use self::errors::ServerSessionError;
pub use self::result::ServerSessionResult;

pub struct Server {
    addr: Option<String>,
    listener: TcpListener,
}

impl Server {
    pub fn new() -> Result<(Server, Vec<ServerSessionResult>), ServerSessionError> {
        let server = Server {
            addr: Some("somewhere".to_string()),
            listener: TcpListener::bind("127.0.0.1:1935").unwrap(),
        };

        let mut results = Vec::with_capacity(4);

        Ok((server, results))
    }

    pub fn listen_and_serve(&self) {
        // Build a server
        println!("Listening...");
        for streams in self.listener.incoming() {
            match streams {
                Err(e) => { eprintln!("error: {}", e) },
                Ok(stream) => {
                    thread::spawn(move || {
                        handler(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
                    });
                }
            }
        }
    }
}

fn handler(mut stream: TcpStream) -> Result<(), Error> {
    println!("Connection from {}", stream.peer_addr()?);
    let mut buffer = [0; 8192];
    loop {
        let nbytes = stream.read(&mut buffer)?;
        if nbytes == 0 {
            return Ok(());
        }

        for i in 0..nbytes {
            print!("{}", buffer[i]);
        }
        println!("");

        // Write buffer to socket
        stream.write(&buffer[..nbytes])?;
        stream.flush()?;
    }
}

改良を加えた点

改良を加えたのはこの部分です。

fn handler(mut stream: TcpStream) -> Result<(), Error> {
    println!("Connection from {}", stream.peer_addr()?);
    let mut buffer = [0; 8192];
    loop {
        let nbytes = stream.read(&mut buffer)?;
        if nbytes == 0 {
            return Ok(());
        }

        for i in 0..nbytes {
            print!("{}", buffer[i]);
        }
        println!("");

        // Write buffer to socket
        stream.write(&buffer[..nbytes])?;
        stream.flush()?;
    }
}

解説

このstreamはソケットのような使い方ができます。
なので,stream.read()で配列bufferにクライアントから送信されたデータを読み取ります。
そのとき,bufferの大きさをstream.read()の戻り値としてnbytesにとっておきます。
読み取ったデータを出力するには,配列から取り出す必要があるのでforループで0からnbytesまでの範囲を指定し,bufferi番目の要素をprintln!()で出力します。(println!()は改行してしまうので今回は使わないことにしました。)
そして,bufferの中身をすべて出力し終えたら,println!()で最後に改行をはさみます。
stream.write()の部分はエコーサーバーとして機能させるために,ソケットに受け取ったデータをそのまま返しています。なのでstream.flush()もそのナカマのような感じでついています。

実行結果

image.png

pythonのスクリプトで送信した数字を表示できています!

3
1
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
3
1