1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Organization

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

前に作成した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のスクリプトで送信した数字を表示できています!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?