2019-12-08に更新

チャット・サーバーを作ろうぜ☆(^~^)?

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 とりあえず チャット・サーバーを作るのを目指そうぜ☆?」

See also: CPerezz/rust-chat-server

KIFUWARABE_80x100x8_01_Futu.gif
「 他人のソースを参考にしようぜ☆?」

cd C:\Users\むずでょ\source\repos\practice-rust
cargo new chat-server-1

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑プロジェクト作成☆」

config.toml:

[host]
domain = localhost
port = 3000

Cargo.toml ファイルと同じフォルダーに置く。

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こういうアプリを作るときは 外部ファイルで 設定できるようにしておくと楽だぜ☆」

Cargo.toml:

[dependencies]
serde = "1.0.102"
serde_derive = "1.0.102"
toml = "0.5.5"

main.rs:

// cd C:\Users\むずでょ\source\repos\practice-rust
// cargo new chat-server-1
//
// cd C:\Users\むずでょ\source\repos\practice-rust\chat-server-1
// cargo check
// cargo build
// cargo run
//
// See also:
// https://crates.io/
// #[macro_use]
extern crate serde_derive;
extern crate toml;

mod config;
use config::*;

fn main() {
    println!("Hello, world!");
    match read_toml("./config.toml".to_string()) {
        Ok(config) => {
            let host = config.host.unwrap();
            println!("Connect | {}:{}", host.domain.unwrap(), host.port.unwrap());
        }
        Err(err) => panic!(err),
    }
}

config.rs:

use serde_derive::*;
use std::fs;
use std::io::{BufReader, Read};
// use toml::*;

#[derive(Debug, Deserialize)]
pub struct Config {
    pub host: Option<Host>,
}

#[derive(Debug, Deserialize)]
pub struct Host {
    pub domain: Option<String>,
    pub port: Option<u16>,
}

pub fn read_toml(path: String) -> Result<Config, toml::de::Error> {
    let contents = match read_file(path.to_owned()) {
        Ok(s) => s,
        Err(e) => panic!("fail to read file: {}", e),
    };

    println!("contents:\n----\n{}\n----", contents);

    toml::from_str(&contents)
}

fn read_file(path: String) -> Result<String, String> {
    let mut file_content = String::new();

    let mut file_read = fs::File::open(path)
        .map(|f| BufReader::new(f))
        .map_err(|e| e.to_string())?;

    file_read
        .read_to_string(&mut file_content)
        .map_err(|e| e.to_string())?;

    Ok(file_content)
}

Output:

Hello, world!
contents:
----
[host]
domain = "localhost"
port = 3000

----
Connect | localhost:3000

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 デシリアライズするコードを書かないといけないのは イマイチだよな☆」

サーバー待ち受け

See also: CPerezz/rust-chat-server

main.rs:

// cd C:\Users\むずでょ\source\repos\practice-rust
// cargo new chat-server-1
//
// cd C:\Users\むずでょ\source\repos\practice-rust\chat-server-1
// cargo check
// cargo build
// cargo run
//
// See also:
// https://crates.io/
// [CPerezz/rust-chat-server](https://github.com/CPerezz/rust-chat-server/blob/master/src/main.rs )

// #[macro_use]
extern crate serde_derive;
extern crate toml;

use std::net::TcpListener;
use std::sync::mpsc;

mod config;
use config::*;

fn main() {
    println!("Hello, world!");
    match read_toml("./config.toml".to_string()) {
        Ok(config) => {
            let host = config.host.unwrap();
            let host_text = format!("{}:{}", host.domain.unwrap(), host.port.unwrap());
            println!("Host            | {}", host_text);

            //Instanciate the server
            let server = TcpListener::bind(&host_text).expect("Listener failet to bind.");

            //Set server in Non-blocking state to force it to hear for changes all the time.
            server
                .set_nonblocking(true)
                .expect("Failed to set Non-Blocking state.");

            //Generating a clients Storage Vector.
            let mut clients: Vec<std::net::TcpStream> = vec![];

            //An asynchronous, infinitely buffered channel. The channel function will return a (Sender, Receiver) tuple where all sends will be asynchronous.
            //Note that we've specified that Strings will be the types that travel through the channel.
            let (sender, reciever) = mpsc::channel::<String>();
        }
        Err(err) => panic!(err),
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 localhost:3000 で サーバーが待ってるところまでは こうだが、
次は クライアントが2つ以上接続してくる部分だぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 片方は nngsサーバー、片方は わらちゃん でいいんじゃないの?」

クライアント待ち受け

See also: CPerezz/rust-chat-server

main.rs:

// cd C:\Users\むずでょ\source\repos\practice-rust
// cargo new chat-server-1
//
// cd C:\Users\むずでょ\source\repos\practice-rust\chat-server-1
// cargo check
// cargo build
// cargo run
//
// See also:
// https://crates.io/
// [CPerezz/rust-chat-server](https://github.com/CPerezz/rust-chat-server/blob/master/src/main.rs )

// #[macro_use]
extern crate serde_derive;
extern crate toml;

use std::io::{ErrorKind, Read, Write};
use std::net::TcpListener;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

const MSG_SIZE: usize = 32;

mod config;
use config::*;

fn main() {
    println!("Hello, world!");
    match read_toml("./config.toml".to_string()) {
        Ok(config) => {
            let host = config.host.unwrap();
            let hostText = format!("{}:{}", host.domain.unwrap(), host.port.unwrap());
            println!("Host            | {}", hostText);

            //Instanciate the server
            let server = TcpListener::bind(&hostText).expect("Listener failet to bind.");

            //Set server in Non-blocking state to force it to hear for changes all the time.
            server
                .set_nonblocking(true)
                .expect("Failed to set Non-Blocking state.");

            //Generating a clients Storage Vector.
            let mut clients: Vec<std::net::TcpStream> = vec![];

            //An asynchronous, infinitely buffered channel. The channel function will return a (Sender, Receiver) tuple where all sends will be asynchronous.
            //Note that we've specified that Strings will be the types that travel through the channel.
            let (sender, reciever) = mpsc::channel::<String>();

            // クライアント待ち受け☆(^~^)
            loop {
                //If the recieved connection from the listener contains a correct value, is accepted.
                if let Ok((mut socket, addr)) = server.accept() {
                    println!("Client {:?} connected to the chhanel!", addr);

                    let sender = sender.clone();
                    //Clone the socket to push it into a thread.
                    clients.push(socket.try_clone().expect("Failed to clone the client."));

                    thread::spawn(move || loop {
                        //Create a buffer to store the msges.
                        let mut buff = vec![0; MSG_SIZE];

                        //Hear socket entries from sender an match it with a Result.
                        match socket.read(&mut buff) {
                            //a read() syscall on a socket that has been closed on the other end will return 0 bytes read,
                            //but no error, which should translate to Ok(0) in Rust.
                            //But this may only apply when the other end closed the connection cleanly.
                            Ok(0) => {
                                println!("\nClient: {} left the channel.", addr);
                                break;
                            }

                            //Handle when we do not read an empty socket
                            Ok(_) => {
                                //Set the buffer as an Iretartor and take it's elements while the condition retunrs true. Finally returns a Vec of type T
                                let msg = buff
                                    .clone()
                                    .into_iter()
                                    .take_while(|&x| x != 0)
                                    .collect::<Vec<_>>();

                                println!("\nMSG as Bytes:   {:?}", msg.clone());
                                let msg = String::from_utf8(msg).expect("Invalid utf8 message");

                                println!("\n{}: {:?}", addr, msg);
                                sender.send(msg).expect("failed to send msg to reciever");
                            }
                            //Handle reading errors!
                            Err(ref err) if err.kind() == ErrorKind::WouldBlock => (),
                            Err(_) => {
                                println!("\nClient: {} left the channel.", addr);
                                break;
                            }
                        }

                        thread::sleep(Duration::from_millis(200));
                    });
                }
                //A bit of functionall programming to send the message to all the other chat members.
                if let Ok(msg) = reciever.try_recv() {
                    clients = clients
                        .into_iter()
                        .filter_map(|mut client| {
                            let buff = msg.clone().into_bytes();
                            buff.clone().resize(buff.len(), 0);

                            client.write_all(&buff).map(|_| client).ok()
                        })
                        .collect::<Vec<_>>();
                }

                thread::sleep(Duration::from_millis(200));
            }
        }
        Err(err) => panic!(err),
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これで サーバー・プログラムは終わり☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 クライアント2つは どうやって作るんだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 前に作ったと思うが、TCPで文字列検索するか……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 見つからないな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 30分で自作しましょう!」

See also: mas-yo/rustgs-testcl

main.rs:

// cd C:\Users\むずでょ\source\repos\practice-rust
// cargo new chat-client-1
//
// cd C:\Users\むずでょ\source\repos\practice-rust\chat-client-1
// cargo check
// cargo build
// cargo run
//
// See also:
// https://crates.io/

// #[macro_use]
extern crate serde_derive;
extern crate toml;

// TcpListener は、標準のと Tokio のとがあって、どちらか選べだぜ☆(^~^)
use std::net::TcpStream;

mod config;
use config::*;

fn main() {
    println!("I am a client!");
    match read_toml("./config.toml".to_string()) {
        Ok(config) => {
            let host = config.host.unwrap();
            let host_text = format!("{}:{}", host.domain.unwrap(), host.port.unwrap());
            println!("Host            | {}", host_text);

            let client = TcpStream::connect(&host_text)
                .and_then(move |stream| Ok(()))
                .map_err(|err| {
                    println!("connection error = {:?}", err);
                });
        }
        Err(err) => panic!(err),
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 クライアント側は、ストリームを確立するだけでいい☆」

main.rs

// cd C:\Users\むずでょ\source\repos\practice-rust
// cargo new chat-client-1
//
// cd C:\Users\むずでょ\source\repos\practice-rust\chat-client-1
// cargo check
// cargo build
// cargo run
//
// See also:
// https://crates.io/

// #[macro_use]
extern crate serde_derive;
extern crate toml;

// TcpListener は、標準のと Tokio のとがあって、どちらか選べだぜ☆(^~^)
use std::net::TcpStream;

mod config;
use config::*;

fn main() {
    println!("I am a client!");
    match read_toml("./config.toml".to_string()) {
        Ok(config) => {
            let host = config.host.unwrap();
            let host_text = format!("{}:{}", host.domain.unwrap(), host.port.unwrap());
            println!("Host            | {}", host_text);

            let client = TcpStream::connect(&host_text)
                .and_then(move |stream| {
                    stream.set_nodelay(true);
                    println!("connected");

                    let mut s = String::new();
                    std::io::stdin().read_line(&mut s).ok();

                    println!("Input           | [{}]", s);

                    Ok(())
                })
                .map_err(|err| {
                    println!("connection error = {:?}", err);
                });
        }
        Err(err) => panic!(err),
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これで テキストを一方的に送り付けて終了することができるぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 前に書いたエコー・サーバーは どこに行ったんだろうな☆?」

2019-12-07 08:45頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 というかこれ、チャット・クライアント だよな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 まず チャット・クライアント を作ろうぜ☆?」

                    let mut s = String::new();
                    std::io::stdin().read_line(&mut s).ok();

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 リード・ラインで 標準入力へのコマンド入力を待機していたら、サーバーからのメッセージを受け取れないだろ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 サーバーからのメッセージは バックグラウンドに流しておけないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ サーバーからのメッセージは 標準エラー出力にでも流せばいいのかだぜ☆?!」

KIFUWARABE_80x100x8_01_Futu.gif
「 いったん それで☆」

            let client = TcpStream::connect(&host_text)
                .and_then(move |stream| {

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 この stream は 読み書きできるのかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 読み書きできるからストリームなのだろう☆」

// use std::io::{BufRead, BufReader, BufWriter, Error, Write};

    // Buffering.
    let mut reader = BufReader::new(&stream);
    let mut writer = BufWriter::new(&stream);

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑読む方向と、書く方向があるだろ☆ 確かRust言語では分けるんだぜ☆」

        if let Err(err) = reader.read_line(&mut line) {
            // panic!("error during receive a line: {}", err);
            println!("Error           | {}", err);
        }
        println!("Read            | {}", line);

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑読み取りの雰囲気は こんな感じ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 非同期で読み取って、標準エラー出力に流せばいいのよ!」

        writer.write(format!("{}\n", msg).as_bytes())?;
        writer.flush()?;

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑書込みは これだけだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 Rustの非同期処理は今でも tokio を使うのかだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Rust 1.39 は async/await が言語の構文に採用されただけだろ☆
引き続き ライブラリは使うんじゃないか……☆?」

                                if let Err(err) = reader.read_line(&mut line) {
                                    // panic!("error during receive a line: {}", err);
                                    println!("Error           | {}", err);
                                }
                                println!("Read            | {}", line);

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ read_line は一見良さそうだが、メッセージが送られてくるまでずっと待ち続けてしまう☆
タイムアウトしない☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ いつ読取終わるんだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ miotokio を使わないと まともな処理も行えなさそうだな☆」

Cargo.toml:

[dependencies]
tokio = { version = "0.2.3", features = ["full"] }

tokio

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 新しい方法が さっぱり分からん☆ 新しいドキュメントを読もうぜ☆」

//! Hello world server.
//!
//! A simple client that opens a TCP stream, writes "hello world\n", and closes
//! the connection.
//!
//! You can test this out by running:
//!
//!     ncat -l 6142
//!     nc.exe -l -p 6142 -t -e cmd.exe
//!
//! And then in another terminal run:
//!
//!     cargo run --example hello_world

/*
 * cd C:\Users\むずでょ\source\repos\practice-rust\tokio
 * cargo check --example ep2-created-stream
 * cargo build --example ep2-created-stream
 * cargo run --example ep2-created-stream
 *
 * [Hello World!](https://tokio.rs/docs/getting-started/hello-world/)
 * [tokio 0.2.3](https://docs.rs/crate/tokio/0.2.3)
 */
use futures::executor::block_on;
use std::net::SocketAddr;
use tokio::net::TcpStream;

async fn connect() {
    let addr: SocketAddr = "127.0.0.1:6142".parse().unwrap();

    // Connect to port 6142 on localhost
    let stream = TcpStream::connect(&addr).await.unwrap();

    // Following snippets come here...
    println!("Info            | Connect end.");
}

fn main() {
    block_on(connect());
    println!("Info            | Finished.");
}

Output:

Info            | Finished.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 非同期処理の中の println! って どこに書き出されてんの?」

KIFUWARABE_80x100x8_01_Futu.gif
「 どこにも書き出されてないのでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「  非同期関数は戻り値を返せるのかだぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 返せなかったら 関数じゃないわよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 どうも block_on を さっと抜けて終了してるみたいだぜ☆
スリープ入れて確かめよう……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 それじゃ ブロック・オン じゃ ないんじゃないの?」

/*
 * cd C:\Users\むずでょ\source\repos\practice-rust\tokio
 * cargo check --example ep2-created-stream
 * cargo build --example ep2-created-stream
 * cargo run --example ep2-created-stream
 *
 * [Hello World!](https://tokio.rs/docs/getting-started/hello-world/)
 * [tokio 0.2.3](https://docs.rs/crate/tokio/0.2.3)
 */
use futures::executor::block_on;
use std::net::SocketAddr;
use tokio::net::TcpStream;

async fn connect() {
    // Sleep 3 seconds.
    println!("Info            | Please wait 3 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(3));

    println!("Info            | Connect end.");
}

fn main() {
    println!("Info            | Please wait 2 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(2));

    block_on(connect());

    // Sleep 9 seconds.
    println!("Info            | Please wait 9 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(9));
    println!("Info            | Finished.");
}

Output:

Info            | Please wait 2 seconds.
Info            | Please wait 3 seconds.
Info            | Connect end.
Info            | Please wait 9 seconds.
Info            | Finished.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 サンプルは シンプルに作るしかないか……☆」

    match TcpStream::connect(&addr).await {
        Ok(_x) => {}
        Err(e) => println!("{:?}", e),
    };

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑接続しようと思ったんだが……☆」

thread 'main' panicked at 'no current reactor', C:\Users\むずでょ\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.4\src\io\driver\mod.rs:243:21
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
             at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.37\src\backtrace\mod.rs:66

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑エラーになってしまうな☆ カレント・リアクター って何だぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 block_on( ) で呼び出したのが 相性合ってないんじゃないか☆?」

connect

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ドキュメントのサンプルを読んでいくかだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 非同期処理で println! とか使ってはいけなかったりするのだろうか☆?」

#[tokio::main]
async fn main() {

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ main の書き方が変わってるのかだぜ☆」

    block_on(connect()); // syncronized.
    // tokio::spawn(connect()); // asyncronized.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 同期と、非同期で分けれるかも☆」

2019-12-07 19:20頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 よく寝た……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 せっかく朝型だったのに……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 部屋が寒すぎる☆ エアコンを28度にしよ☆」

//! Hello world server.
//!
//! A simple client that opens a TCP stream, writes "hello world\n", and closes
//! the connection.
//!
//! You can test this out by running:
//!
//!     ncat -l 6142
//!     nc.exe -l -p 6142 -t -e cmd.exe
//!
//! And then in another terminal run:
//!
//!     cargo run --example hello_world

/*
 * cd C:\Users\むずでょ\source\repos\practice-rust\tokio
 * cargo check --example ep2-created-stream
 * cargo build --example ep2-created-stream
 * cargo run --example ep2-created-stream
 *
 * [Hello World!](https://tokio.rs/docs/getting-started/hello-world/)
 * [tokio 0.2.3](https://docs.rs/crate/tokio/0.2.3)
 */
use futures::executor::block_on;
use std::net::SocketAddr;
// use tokio::net::TcpStream;

async fn connect() {
    // Sleep 3 seconds.
    println!("Info            | Please wait 1 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(1));

    let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap();

    // https://docs.rs/tokio-tcp/0.1.2/src/tokio_tcp/stream.rs.html#49-58
    match tokio::net::TcpStream::connect(&addr).await {
        Ok(_stream) => {
            // Following snippets come here...
            println!("Info            | Connect end.");
        }
        Err(e) => println!("{:?}", e),
    };
}

#[tokio::main]
async fn main() {
    println!("Info            | Please wait 1 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(1));

    // syncronized.
    block_on(connect());
    // asyncronized.
    // tokio::spawn(connect());

    // Sleep 9 seconds.
    println!("Info            | Please wait 3 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(3));
    println!("Info            | Finished.");
}

Output:

Info            | Please wait 1 seconds.
Info            | Please wait 1 seconds.
Os { code: 10061, kind: ConnectionRefused, message: "対象のコンピューターによって拒否されたため、接続できませんでした。" }
Info            | Please wait 3 seconds.
Info            | Finished.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 接続に失敗するところまで 行ったのだった☆
テスト用のエコー・サーバーを用意しよう☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 エコー・サーバーは立てているんだがなあ☆」

    // https://docs.rs/tokio-tcp/0.1.2/src/tokio_tcp/stream.rs.html#49-58
    match tokio::net::TcpStream::connect(&addr).await {
        Ok(_stream) => {
            // Following snippets come here...
            println!("Info            | Connect end.");
        }
        Err(e) => println!("{:?}", e),
    };

Output:

Info            | Please wait 1 seconds.
Info            | Please wait 1 seconds.
Host            | 127.0.0.1:3000
Os { code: 10061, kind: ConnectionRefused, message: "対象のコンピューターによって拒否されたため、接続できませんでした。" }
Info            | Please wait 3 seconds.
Info            | Finished.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こんな短いコードでエラーになってるからな☆ どこが問題なんだろな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 PCを再起動してみましょう!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 v4 と v6 が混在してるのかも知らん☆ localhost:3000 を止めて 127.0.0.1:3000 にしよう☆
よし、いけた☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 サンプル・コードが見つからんなあ☆」

use tokio::net::tcp::TcpStream;
use tokio::net::TcpStream;

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑なんだこの 違いの分からんクラスは☆?」

async fn connect() {
    // v4 か v6 かはサーバー側と合わせること。
    let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap();
    println!("Host            | {}", &addr);

    // クライアント側は リスナーではなく、ストリームを取得する。
    // https://docs.rs/tokio-tcp/0.1.2/src/tokio_tcp/stream.rs.html#49-58
    match TcpStream::connect(&addr).await {
        Ok(mut stream) => {
            match stream.set_nodelay(true) {
                Ok(_x) => {}
                Err(e) => panic!("{}", e),
            }

            println!("Connected from  | {:?}", stream.peer_addr().unwrap());

            // Write some data.
            match stream.write_all(b"hot dog!").await {
                Ok(_x) => {}
                Err(e) => panic!("{}", e),
            }
            stream.flush();

            // Sleep 3 seconds.
            println!("Info            | Please wait 3 seconds.");
            std::thread::sleep(std::time::Duration::from_secs(1));

            // Read.
            let mut buffer = String::new();
            stream.read_to_string(&mut buffer);
            println!("Read            | {:?}", &buffer);
        }
        Err(e) => println!("{:?}", e),
    };
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こう書いても 実行はできるがサーバーからのメッセージは取れないぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 サーバー側にメッセージを出してみようぜ☆?」

Output:

contents:
----     
[host]
# domain = &quot;localhost&quot;
domain = "127.0.0.1"
port = 3000

----
Host            | 127.0.0.1:3000
Server standup  | 127.0.0.1:3000
Connection from | 127.0.0.1:51973
Info            | Waiting...
Read            | hot dog!
Write           | poppo
Info            | Waiting...
Error           | 確立された接続がホスト コンピューターのソウトウェアによって中止されました。 (os error 10053)
Read            | 
Write           | poppo
Os { code: 10053, kind: ConnectionAborted, message: "確立された接続がホスト コンピューターのソウトウェアによって中止されました。" }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もしかして☆」

            match stream.write_all(b"hot dog!").await {

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑これは☆」

            match stream.write_all(b"hot dog!\n").await {

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こうか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 関係なかったぜ☆」

warning: unused `tokio::io::util::read_to_string::ReadToString` that must be used
  --> examples\ep4-read.rs:47:13
   |
47 |             stream.read_to_string(&mut buffer);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_must_use)]` on by default
   = note: futures do nothing unless you `.await` or poll them

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑なんかワーニングが出てるな☆?」

                // Read.
                let mut buffer = String::new();
                match stream.read_to_string(&mut buffer).await {
                    Ok(x) => {
                        stream.flush();
                        println!("Read x          | {:?}", x);
                    }
                    Err(e) => panic!("{}", e),
                }
                println!("Read            | {:?}", &buffer);

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ .await したら 待機待ちしてしまうが☆」

2019-12-08 01:00頃

/*
 * cd C:\Users\むずでょ\source\repos\practice-rust\tokio
 * cargo check --example ep4-read
 * cargo build --example ep4-read
 * cargo run --example ep4-read
 *
 * [Reading and Writing Data](https://tokio.rs/docs/io/reading_writing_data/)
 */
use futures::executor::block_on;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::net::SocketAddr;
use std::str;
use tokio::net::TcpStream;
use tokio::prelude::*;

async fn connect() {
    // v4 か v6 かはサーバー側と合わせること。
    let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap();
    println!("Host            | {}", &addr);

    // クライアント側は リスナーではなく、ストリームを取得する。
    // https://docs.rs/tokio-tcp/0.1.2/src/tokio_tcp/stream.rs.html#49-58
    match TcpStream::connect(&addr).await {
        Ok(mut stream) => {
            match stream.set_nodelay(true) {
                Ok(_x) => {}
                Err(e) => panic!("{}", e),
            }

            println!("Connected from  | {:?}", stream.peer_addr().unwrap());

            loop {
                // Write some data.
                match stream.write_all("hot dog!\n".as_bytes()).await {
                    Ok(_x) => {
                        stream.flush();
                        println!("Info            | Writed.");
                    }
                    Err(e) => panic!("{}", e),
                }

                /*
                // Sleep 3 seconds.
                println!("Info            | Please wait 3 seconds.");
                std::thread::sleep(std::time::Duration::from_secs(3));
                */

                println!("Info            | Waiting for read.");
                // Read.
                // https://docs.rs/tokio/0.1.12/tokio/prelude/trait.Read.html#tymethod.read
                let mut buffer = [0; 10];

                // read up to 10 bytes
                match stream.read(&mut buffer[..]).await {
                    Ok(size) => {
                        println!(
                            "Read            | {} | {:?}",
                            size,
                            str::from_utf8(&buffer[..size]).unwrap()
                        );
                    }
                    Err(e) => panic!(e),
                }
                /*
                // Sleep 3 seconds.
                println!("Info            | Please wait 3 seconds.");
                std::thread::sleep(std::time::Duration::from_secs(3));

                // Write some data.
                match stream.write_all("Jump kick!".as_bytes()).await {
                    Ok(_x) => {
                        // stream.flush();
                        println!("Info            | Writed.");
                    }
                    Err(e) => panic!("{}", e),
                }
                */
            }
        }
        Err(e) => println!("{:?}", e),
    };
}

#[tokio::main]
async fn main() {
    println!("Info            | Please wait 1 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(1));

    // syncronized.
    block_on(connect());
    // asyncronized.
    // tokio::spawn(connect());

    // Sleep 9 seconds.
    println!("Info            | Please wait 10 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(10));
    println!("Info            | Finished.");
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 改行コードの送受信は分からんなあ☆ 1行ずつかも知らん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 \n が送られてくるまで、受信側が待機してしまうのかだぜ☆」

2019-12-08 14:20頃

/*
 * cd C:\Users\むずでょ\source\repos\practice-rust\tokio
 * cargo check --example ep5-input-read
 * cargo build --example ep5-input-read
 * cargo run --example ep5-input-read
 *
 * [Reading and Writing Data](https://tokio.rs/docs/io/reading_writing_data/)
 */
use futures::executor::block_on;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::net::SocketAddr;
use std::str;
use tokio::net::TcpStream;
use tokio::prelude::*;

async fn connect() {
    // v4 か v6 かはサーバー側と合わせること。
    let addr: SocketAddr = "127.0.0.1:3000".parse().unwrap();
    println!("Host            | {}", &addr);

    // クライアント側は リスナーではなく、ストリームを取得する。
    // https://docs.rs/tokio-tcp/0.1.2/src/tokio_tcp/stream.rs.html#49-58
    match TcpStream::connect(&addr).await {
        Ok(mut stream) => {
            match stream.set_nodelay(true) {
                Ok(_x) => {}
                Err(e) => panic!("{}", e),
            }

            println!("Connected from  | {:?}", stream.peer_addr().unwrap());

            loop {
                // 標準入力。
                println!("Info            | Please key typing.");
                let mut line = String::new();
                std::io::stdin().read_line(&mut line).ok();
                // 改行を削る。
                line = line.replace("\r", "\n").replace("\n", "");
                println!("Input           | [{}]", line);

                match line.as_str() {
                    "exit" => {
                        // ループから抜けます。このコマンドはサーバー側には送れません。
                        break;
                    }
                    "" => {
                        // 空打ちで、サーバーのメッセージ読取。
                        // この状態からは途中で抜けれません。
                        println!("Info            | Waiting for read.");
                        // Read.
                        // https://docs.rs/tokio/0.1.12/tokio/prelude/trait.Read.html#tymethod.read
                        let mut buffer = [0; 2048];
                        // 末尾の改行をもって受信完了。
                        match stream.read(&mut buffer[..]).await {
                            Ok(size) => {
                                println!(
                                    "Read            | {} | {:?}",
                                    size,
                                    str::from_utf8(&buffer[..size]).unwrap()
                                );
                            }
                            Err(e) => panic!(e),
                        }
                    }
                    _ => {
                        // その他は、サーバーへのメッセージ送信。
                        println!("Write           | {}", line);
                        // 改行を付けてください。受信側が 受信完了するために必要です。
                        match stream.write_all(format!("{}\n", line).as_bytes()).await {
                            Ok(_x) => {
                                stream.flush();
                                println!("Info            | Writed.");
                            }
                            Err(e) => panic!("{}", e),
                        }
                    }
                }
            }
        }
        Err(e) => println!("{:?}", e),
    };
}

#[tokio::main]
async fn main() {
    println!("Info            | Please wait 1 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(1));

    // syncronized.
    block_on(connect());
    // asyncronized.
    // tokio::spawn(connect());

    // Sleep 9 seconds.
    println!("Info            | Please wait 10 seconds.");
    std::thread::sleep(std::time::Duration::from_secs(10));
    println!("Info            | Finished.");
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ .await したら ブロッキングしてしまうじゃないか☆
どうやって ノン・ブロッキングで読み取るんだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 Tokio は Non-blocking I/O なはずなんだがなあ☆?」

2019-12-08 15:30頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 IPアドレスの数を Who is で調べて 入れると接続できたんだが、
Rust言語って名前解決してくれないの☆?」

通信対局規約

adminmatch alpha beta b 19 30 0

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑adminmatch コマンドって自分で打つのかだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 送信はしたが、受信もしてみるか……☆?」

thread 'main' panicked at 'Box<Any>', examples\ep5-input-read.rs:75:47
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
             at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.37\src\backtrace\mod.rs:66
   1: std::sys_common::backtrace::_print_fmt
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\sys_common\backtrace.rs:76
   2: std::sys_common::backtrace::_print::{{impl}}::fmt
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\sys_common\backtrace.rs:60
   3: core::fmt::write
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libcore\fmt\mod.rs:1030
   4: std::io::Write::write_fmt<std::sys::windows::stdio::Stderr>
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\io\mod.rs:1412
   5: std::sys_common::backtrace::_print
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\sys_common\backtrace.rs:64
   6: std::sys_common::backtrace::print
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\sys_common\backtrace.rs:49
   7: std::panicking::default_hook::{{closure}}
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\panicking.rs:196
   8: std::panicking::default_hook
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\panicking.rs:210
   9: std::panicking::rust_panic_with_hook
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\/src\libstd\panicking.rs:473
  10: std::panicking::begin_panic<std::io::error::Error>
             at /rustc/4560ea788cb760f0a34127156c78e2552949f734\src\libstd\panicking.rs:407
...

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑うーむ☆ 受信できないな☆」

<書きかけ>

何度でもクリック!→

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

むずでょ の最近の記事