ゲスト 31人 と メンバー0人 がオンラインです

概要

 試しにTCP通信を使ったチャットサーバを作成してみた。

・ライフタイム、所有権、借用回りはあやふやな状態で作成しているため、

 恐らく余り参考にならないコードになっていると思う

 

参考にしたサイト様

http://agtn.hatenablog.com/entry/2017/01/07/151455

 

GitHub

https://github.com/dctk/chatserver_rust_sample

 

依存関係

mio = "0.6.19"
byteorder = "1"

 

サンプル

///
/// 簡易チャットサーバー
/// プロトコル:
///   リトルエンディアン
///  Header(1byte) : 0xFF
///   Length(4byte) : (i32)
///   Message(byte) : (text)
/// 

extern crate mio;
extern crate byteorder;

use std::collections::{HashMap};
use std::io::prelude::*;
use std::io::{Cursor};
use mio::{Poll,Events,Token,PollOpt,Ready};
use mio::tcp::{TcpListener,TcpStream,Shutdown};
use std::net::{SocketAddr,IpAddr,Ipv4Addr};
use byteorder::{ReadBytesExt, LittleEndian};

struct Client{
    addr : SocketAddr,
    stream: TcpStream,
    receive_buff: Vec<u8>
}

impl Client{
    fn new(stream: TcpStream,addr: SocketAddr)->Self{
        Client{ addr,stream,receive_buff:Vec::new() }
    }
}

struct ClientManager{
    clients : HashMap<Token,Client>,
    free_tokens:Vec<Token>,
    next_token : Token
}

impl ClientManager{
    fn new(init_token : Token)->Self{
        ClientManager{
            clients: HashMap::new(),
            free_tokens : Vec::new(),
            next_token : init_token,
        }
    }

    fn next_token(&mut self)->Token{
        if let Some(token) = self.free_tokens.pop(){
            return token;
        }
        let next_token = self.next_token;
        self.next_token = Token(self.next_token.0+1);
        return next_token;
    }

    fn add_client(&mut self,token :Token,client : Client){
        self.clients.insert(token, client);
    }

    fn remove_client(&mut self,token:Token){
        let r = self.clients.remove(&token);
        if r.is_some(){
            self.free_tokens.push(token);
        }
    }

    fn get_mut(&mut self,token: &Token)->Option<&mut Client>{
        self.clients.get_mut(token)
    }

    fn transfer_all(&mut self,buff:&[u8]){
        for client in self.clients.values_mut(){
            match client.stream.write(buff){
                Ok(_)=>{},
                Err(_)=>{ }
            }
        }
    }
}

fn main(){
   let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),1024);
   server(&addr);
}

fn server(addr: &SocketAddr){
    println!("start server : {}",addr);

    // preparation
    const SERVER_TOKEN: Token = Token(0);
    let mut client_mng = ClientManager::new(Token(1));

    // bind
    let listener = TcpListener::bind(&addr).unwrap();

    // start listener
    let poll = Poll::new().unwrap(); 
    poll.register(
        &listener, 
        SERVER_TOKEN, 
        Ready::readable(), 
        PollOpt::edge()).unwrap();
    let mut events = Events::with_capacity(1024);

    // server loop
    let mut messages:Vec<u8> = Vec::new();
    loop{
        poll.poll(&mut events, None).unwrap();
        for event in events.iter(){
            match event.token(){
                // accept
                SERVER_TOKEN=>{
                    let (stream,client_addr)=listener.accept().unwrap();
                    println!("connection client : {}",client_addr);

                    let token = client_mng.next_token();                    
                    poll.register(&stream, token, Ready::readable(), PollOpt::edge()).unwrap();
                    client_mng.add_client(token, Client::new(stream,client_addr));
                }
                // receive from client
                token=>{
                    let mut closed = false;
                    if let Some(client) = client_mng.get_mut(&token){
                        let mut buff = [0;1024];
                        match client.stream.read(&mut buff){
                            Ok(n)=>{
                                if n == 0 {
                                    println!("disconnection client : {}",client.addr);
                                    poll.deregister(&client.stream).unwrap();
                                    client.stream.shutdown(Shutdown::Both).unwrap();    
                                    closed = true;                   
                                }
                                else{
                                    client.receive_buff.extend_from_slice(&buff[0..n]);

                                    // analyze data
                                    let mut message_len: usize = 0;
                                    loop{
                                        if let Some(n) = client.receive_buff.iter().position(|&r|r==0xFF){
                                            if n > 0{
                                                client.receive_buff.resize(client.receive_buff.len()-n,0);
                                            }
                                        }
                                        else{
                                            client.receive_buff.clear();
                                            break;
                                        } 

                                        if client.receive_buff.len() >= 5{
                                            let mut rdr = Cursor::new(vec![
                                                client.receive_buff[1],
                                                client.receive_buff[2],
                                                client.receive_buff[3],
                                                client.receive_buff[4],
                                            ]);
                                            message_len = rdr.read_i32::<LittleEndian>().unwrap() as usize;
                                        }
                                        else{
                                            break;
                                        }
                                        
                                        if message_len+5 <= client.receive_buff.len(){
                                            messages.extend_from_slice(&client.receive_buff[..message_len+5]); 
                                            client.receive_buff.resize(client.receive_buff.len()-(message_len+5), 0);                          
                                        }     
                                        else{
                                            break;
                                        }
                                    }
                                }
                            },
                            Err(_)=>{}
                        }
                        
                    }
                    if closed{
                        client_mng.remove_client(token);
                    }
                }
            }
        }

        // クライアント全員にメッセージを配送する
        if messages.len()>0{
            let array = &messages[..];
            client_mng.transfer_all(&array);
            messages.clear();
        }        
    }
}