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

# 前に作成したTCPサーバーに改良を加える
[前に作成したTCPサーバー](https://qiita.com/Papiposa/items/37811741c7ef46db2194)は，受け取ったデータを表示してくれないので，少し改良を加えて受け取ったデータを表示できるようにしました。

# コード
### 前に作成したコード

```rust
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()?;
    }
}
```

### 今回改良を加えたコード

```rust
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()?;
    }
}
```

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

```rust
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`までの範囲を指定し，`buffer`の`i番目`の要素を`println!()`で出力します。（`println!()`は改行してしまうので今回は使わないことにしました。）
そして，`buffer`の中身をすべて出力し終えたら，`println!()`で最後に改行をはさみます。
`stream.write()`の部分はエコーサーバーとして機能させるために，ソケットに受け取ったデータをそのまま返しています。なので`stream.flush()`もそのナカマのような感じでついています。

# 実行結果
<img width="1440" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352824/62c9dbae-d904-3995-da4d-6f26d475b70f.png">

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