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

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
「 前に書いたエコー・サーバーは どこに行ったんだろうな☆?」

<書きかけ>

何度でもクリック!→

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位

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

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

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

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

ボードとは?

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位 の最近の記事