rust学习基于tokio_actor聊天服务器实战(二 )

前言:
上章以前实现了一个基本的服务器,这章主要是完善功能
1: 介绍
在这里插入图片描述
useractor worldactor 等分开

use crate::gobal::*;
use crate::pb::chatproto;
use crate::pb::chatproto::*;
use prost::Message as ProstMssage;
use std::error::Error;
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use tokio::sync::{mpsc, oneshot};

pub struct MyUserActor {
    pub(crate) connid: ConnectID,
    pub(crate) userid: UserID,
    pub(crate) username: String,
    pub(crate) guildid: GuildID,
    pub(crate) userstate: Arc<AtomicU8>,
    pub(crate) receiver: mpsc::UnboundedReceiver<ActorMessage>,
    pub(crate) sendclient: mpsc::UnboundedSender<SendClientMsg>,
    pub(crate) worldsender: mpsc::UnboundedSender<ActorMessage>,
    pub(crate) msgmask: u32,
    pub(crate) lasttime: [u32; ChatChannel_Num],
}

impl MyUserActor {
    //,worldsender:mpsc::UnboundedSender<ActorMessage>
    pub(crate) fn new(
        connid: ConnectID,
        receiver: mpsc::UnboundedReceiver<ActorMessage>,
        sendclient: mpsc::UnboundedSender<SendClientMsg>,
        worldsender: mpsc::UnboundedSender<ActorMessage>,
    ) -> Self {
        Self {
            connid,
            userid: 0,
            username: "".to_string(),
            guildid: 0,
            userstate: Arc::new(AtomicU8::new(0)),
            receiver,
            sendclient,
            worldsender,
            msgmask: MASK_START,
            lasttime: [0; ChatChannel_Num],
            //    worldsender,
        }
    }
    pub(crate) fn setuserinfo(
        &mut self,
        userid: UserID,
        username: String,
        guildid: GuildID,
        state: u8,
    ) {
        self.userid = userid;
        self.userstate.store(state, Ordering::Relaxed);
        self.username = username;
        self.guildid = guildid;
    }
    pub(crate) fn setguildid(&mut self, guildid: GuildID) {
        self.guildid = guildid;
    }
    pub(crate) fn getguildid(&mut self) -> GuildID {
        self.guildid
    }
    pub(crate) fn getuserstateclone(&mut self) -> Arc<AtomicU8> {
        self.userstate.clone()
    }

    pub(crate) fn setuserstate(&mut self, state: u8) {
        self.userstate.store(state, Ordering::Relaxed);
    }
    pub(crate) fn getuserstate(&mut self) -> u8 {
        self.userstate.load(Ordering::Relaxed)
    }

    pub(crate)  fn doLogicMsg(&mut self, datatype: u32, msgdata: VU8) {
        if datatype == MyMsgType::Binary as u32 {
            let (msgid, mask) = getProtoMsgIdAndMask(&msgdata);
            const chat_req: u32 = chatproto::Chatmsg::CchChatReq as u32;
            match msgid {
                chat_req => {
                    if let Ok(req) = chatproto::ChatMessageChatReq::decode(&msgdata[..]) {
                        // println!(
                        //     "user={} msgid={} chatchannel={}",
                        //     self.userid.clone(),
                        //     msgid.clone(),
                        //     req.chattype.clone()
                        // );
                        if req.chattype == ChatChannel::ChatChannel_GUILD as u32 && self.guildid > 0 {
                            let head = chatproto::ChatMessageHeadNoMask {
                                msgid: Chatmsg::ChcNotifyChat as u32,
                            };
                            let mut chatreq = chatproto::ChatMessageNotifyChat {
                                msghead: Some(head),
                                chattype: req.chattype,
                                senderid: self.userid.clone(),
                                sendername: self.username.clone(),
                                strcontext: req.context,
                            };
                            let mut buf = Vec::new();
                            chatreq.encode(&mut buf).unwrap();
                           // buf.insert(0, MyMsgType::Binary as u8);

                            let msg = sendMsgAndType {
                                fromid: self.guildid.clone(),
                                datatype: req.chattype.clone(),
                                data: buf,
                            };
                            self.worldsender.send(ActorMessage::ctw_msg(msg)).unwrap();
                          //  println!("guild msg to world ");
                        } else if req.chattype == ChatChannel::ChatChannel_WORLD as u32 {
                            let head = chatproto::ChatMessageHeadNoMask {
                                msgid: Chatmsg::ChcNotifyChat as u32,
                            };
                            let mut chatreq = chatproto::ChatMessageNotifyChat {
                                msghead: Some(head),
                                chattype: req.chattype,
                                senderid: self.userid.clone(),
                                sendername: self.username.clone(),
                                strcontext: req.context,
                            };
                            let mut buf = Vec::new();
                            chatreq.encode(&mut buf).unwrap();
                         //   buf.insert(0, MyMsgType::Binary as u8);

                            let msg = sendMsgAndType {
                                fromid: 0,
                                datatype: req.chattype.clone(),
                                data: buf,
                            };
                            self.worldsender.send(ActorMessage::ctw_msg(msg)).unwrap();
                        } else if req.chattype == ChatChannel::ChatChannel_NORMAL as u32 {
                            //对个人或朋友
                            let head = chatproto::ChatMessageHeadNoMask {
                                msgid: Chatmsg::CchChatRep as u32,
                            };
                            let mut chatreq = chatproto::ChatMessageChatRep {
                                msghead: Some(head),
                                res: 0,
                            };
                            let mut buf = Vec::new();
                            chatreq.encode(&mut buf).unwrap();
                            // buf.insert(0, MyMsgType::Binary as u8);

                            self.sendclient
                                .send(SendClientMsg {
                                    msgypte: MyMsgType::Binary as u8,
                                    msgdata: buf,
                                })
                                .unwrap();
                        }
                    }
                }
                _ => {}
            }
        }
    }

    pub(crate) async fn handle_message(&mut self, msg: ActorMessage) -> Result<Vec<u8>, Box<dyn Error>> {
      //  println!("handle_message ActorMessage ");
        match msg {
            ActorMessage::synmsgwaitrep { respond_to } => {
                // self.next_id += 1;
                // The `let _ =` ignores any errors when sending.
                // `let _ =` 忽略了发送的任何 error
                // This can happen if the `select!` macro is used
                // to cancel waiting for the response.
                // 当 `select!` 宏被用到时将会停止接受响应
                // let _ = respond_to.send(vec![self.next_id as u8]);
            }
            ActorMessage::ctc_signal_event(signalmsg) => {
                //通知world actor 客户端可以清理了
                let _ = self
                    .worldsender
                    .send(ActorMessage::ctw_signal_event(signalType {
                        signaltype: signalTypeId::Signal_Kick_User as u32,
                        signalparam: self.userid.clone(),
                    }));
                self.userstate.store(UserState_NONE,Ordering::Relaxed);
            }
            ActorMessage::wtc_forwardmsg(mut msg) => {
                // msg.data.insert(0, MyMsgType::Binary as u8);
                //let _ = self.sendclient.send(msg.data);
             //   println!("wtc_forwardmsg  to client {} {} {} {} {}",msg.data[0],msg.data[1],msg.data[2],msg.data[3],msg.data[4]);
                let _ = self.sendclient.send(SendClientMsg {
                    msgypte: msg.datatype as u8,
                    msgdata: msg.data,
                });
            }
            ActorMessage::ctc_nettologic_msg(msg) =>{
                self.doLogicMsg(msg.datatype, msg.data);
            }
            ActorMessage::wtc_signal_event(msg) => {
                match msg.signaltype {
                    signalTypeId_Kick_User => {
                        //let _ =self.sendclient.send(SendClientMsg{msgypte:0,msgdata:vec![]});
                        self.notify_network_disconnect().await;
                        self.userstate.store(UserState_NONE, Ordering::Relaxed);
                        //修改为0
                    }
                    _ => {}
                }
            }
            ActorMessage::wtc_getChan_msg(msg) => {
                //更新连接ID 及 网络发送通道
                //有些数据需要重置
                //原来的网络连接需要断开  //可以提示    你的账号在别的设备上登录
                self.notify_client_msg(1,"你的账号在别的设备上登录".to_string()).await;
                self.notify_network_disconnect().await;

                self.connid = msg.connid;
                self.sendclient = msg.chan;
            }
            _ => {
                return Err("".into());
            }
        }
        Ok(vec![])
    }

    async fn notify_network_disconnect(&mut self) {
        let _ = self.sendclient.send(SendClientMsg {
            msgypte: 0,
            msgdata: vec![],
        });
    }

   async  fn notify_client_msg(&mut self,msgtype:u32,context:String ) {
        let head = chatproto::ChatMessageHeadNoMask {
            msgid: Chatmsg::ChcNotifyMsg as u32,
        };
        let mut chatnotifymsg = chatproto::ChatMessageNotifyMsg {
            msghead: Some(head),
            msgtype,
            strcontext:context,
        };
        let mut buf = Vec::new();
        chatnotifymsg.encode(&mut buf).unwrap();

        let _ = self.sendclient.send(SendClientMsg {
            msgypte: MyMsgType::Binary as u8,
            msgdata: buf,
        });
    }
}

worldActor

use crate::gobal::*;
use crate::pb::chatproto::*;
use prost::Message as ProstMssage;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{mpsc, oneshot};
use tokio::{select, signal, time};

pub struct worldActor {
    pub(crate) sharestate: Arc<AtomicU8>,
    pub(crate) mpscrecv: mpsc::UnboundedReceiver<ActorMessage>,
    pub(crate) chanchan: mpsc::UnboundedReceiver<ActorMessage2>,
    pub(crate) usermap: HashMap<UserID, userChan_world>,
    pub(crate) namemap: HashMap<String, UserID>,
    pub(crate) guildmap: HashMap<GuildID, HashSet<UserID>>, //Rc<RefCell<userChan_world>>>>
    pub(crate) maxonlinerole: u32,
}

impl worldActor {
    pub(crate) fn new(
        sharestate: Arc<AtomicU8>,
        receiver: mpsc::UnboundedReceiver<ActorMessage>,
        chanchan: mpsc::UnboundedReceiver<ActorMessage2>,
    ) -> Self {
        Self {
            sharestate,
            mpscrecv: receiver,
            chanchan,
            usermap: HashMap::new(),
            namemap: HashMap::new(),
            guildmap: HashMap::new(),
            maxonlinerole: MAX_ONLINE_ROLE, //最大人数
        }
    }

    pub(crate) fn kickalluser(&mut self) {
        for (k, v) in &self.usermap {
            if v.chanState.load(Ordering::Relaxed) == UserState::UserState_NORMAL as u8 {
                let _ = v.chanchan.send(ActorMessage::wtc_signal_event(signalType {
                    signaltype: signalTypeId_Kick_User,
                    signalparam: 0,
                }));
            }
        }
        self.sharestate.store(0, Ordering::Relaxed);
        self.usermap.clear();
        self.namemap.clear();
        self.guildmap.clear();
    }
    pub(crate) fn removeuser(&mut self, userid: UserID) {
        if let Some(v) = self.usermap.remove(&userid) {
            self.namemap.remove(&v.username);
            let guildid = v.userguildid.clone();
            if guildid > 0 {
                if let Some(v1) = self.guildmap.get_mut(&guildid) {
                    v1.remove(&userid);
                }
            }
        }
    }

    pub(crate) async fn guildboradcast(
        &mut self,
        formuserid: UserID,
        toguildid: GuildID,
        msg: VU8,
    ) {
        if let Some(v1) = self.guildmap.get_mut(&toguildid) {
            let sendmsg = crate::gobal::sendMsgAndType {
                fromid: formuserid,
                datatype: MyMsgType::Binary as u32,
                data: msg,
            };
            let mut sendcount = 0;
            let userstate = UserState::UserState_NORMAL as u8;
            for key in v1.iter() {
                if let Some(v2) = self.usermap.get(&key) {
                    if v2.chanState.load(Ordering::Relaxed) == userstate {
                        sendcount += 1;
                        v2.chanchan
                            .send(ActorMessage::wtc_forwardmsg(sendmsg.clone()))
                            .unwrap();
                    }
                }
            }
          //  println!(" world  guild msg to role {}", sendcount);
        } else {
            println!("no guild {} \n", toguildid);
        }
    }

    pub(crate) async fn worldboradcast(&mut self, formuserid: UserID, msg: VU8) {
        let userstate = UserState::UserState_NORMAL as u8;
        let sendmsg = crate::gobal::sendMsgAndType {
            fromid: formuserid,
            datatype: MyMsgType::Binary as u32,
            data: msg,
        };
        for (_, v) in &self.usermap {
            if let Some(v2) = self.usermap.get(&v.userid) {
                if v2.chanState.load(Ordering::Relaxed) == userstate {
                    let _ = v2
                        .chanchan
                        .send(ActorMessage::wtc_forwardmsg(sendmsg.clone()));
                }
            }
        }
    }

    pub(crate) async fn handle_logic(&mut self, msg: ActorMessage) {
        match msg {
            ActorMessage::ctw_signal_event(signalmsg) => match signalmsg.signaltype {
                signalTypeId_Server_Close => {}
                signalTypeId_Kick_User => {
                    //self.usermap.remove(&(signalmsg.signalparam as UserID));
                    self.removeuser(signalmsg.signalparam as UserID);
                }
                _ => {}
            },
            ActorMessage::ctw_msg(mut msg) => {
                if msg.datatype == ChatChannel::ChatChannel_GUILD as u32 {
                  //  println!("world recv guild msg");
                    self.guildboradcast(0, msg.fromid, msg.data).await;
                } else if msg.datatype == ChatChannel::ChatChannel_WORLD as u32 {
                    self.worldboradcast(0, msg.data).await;
                }
            }
            _ => {}
        }
    }

    pub(crate) async fn handle_logic2(&mut self, msg: ActorMessage2) {
        match msg {
            ActorMessage2::synmsgwaitrep { respond_to } => {
                if let Some(t) = self.usermap.get(&respond_to.id) {
                    let userchanworld = &t;
                    let userstate = userchanworld.chanState.load(Ordering::Relaxed);
                    if userstate == UserState::UserState_NORMAL as u8 {
                        //
                        let _ = respond_to.msgChann.send(synWaitRep2 {
                            state: 0,
                            op: Some(repChannAndState2 {
                                actorState: userchanworld.chanState.clone(),
                                sendchann: userchanworld.chanchan.clone(),
                            }),
                        });
                        // t.logicchann.send();
                        //t.logicChannChann.send(userChannChann{connid:respond_to.id2 ,chan:respond_to.tonetChann});
                        //chanchan.send(userChannChann{connid:respond_to.id2 ,chan:respond_to.tonetChann});
                        let _ = userchanworld.chanchan.send(ActorMessage::wtc_getChan_msg(
                            userChannChann {
                                connid: respond_to.id2,
                                chan: respond_to.tonetChann,
                            },
                        ));
                    } else if userstate == UserState::UserState_INIT as u8 {
                        // msg.MsgChan <- &shr.UpdateUserWebQue{nil, true, 0}
                        let _ = respond_to.msgChann.send(synWaitRep2 { state: 1, op: None });
                    } else {
                        let _ = respond_to.msgChann.send(synWaitRep2 { state: 0, op: None });
                    }
                } else {
                    let usercount = self.usermap.len();
                    if usercount >= self.maxonlinerole as usize {
                        //是否超过最大人数了
                        let _ = respond_to.msgChann.send(synWaitRep2 { state: 2, op: None });
                    } else {
                        let _ = respond_to.msgChann.send(synWaitRep2 { state: 0, op: None });
                    }
                }
            }
            ActorMessage2::ctw_userhann { respond_to } => {
                let userid = respond_to.userid;
                let mut userid_2 = userid.clone();
                if let Some(t) = self.usermap.remove(&userid_2) {
                    let _ = t.chanchan.send(ActorMessage::wtc_signal_event(signalType {
                        signaltype: signalTypeId::Signal_Kick_User as u32,
                        signalparam: respond_to.userid.clone(),
                    }));
                }
                {
                    // if let Some(t) = self.usermap.get(& userid) {
                    //     self.usermap.remove(&userid_2);
                    //     t.chanchan.send(ActorMessage::wtc_signal_event(signalType{signaltype:signalTypeId::Signal_Kick_User as u32,signalparam:userid_2}));
                    // }
                }
                let guildid = respond_to.userguildid.clone();
                let u = userChan_world {
                    userid: respond_to.userid,
                    username: respond_to.username,
                    userguildid: respond_to.userguildid,
                    connectid: respond_to.connectid,
                    chanchan: respond_to.logicChann,
                    chanState: respond_to.chanState,
                };
                self.usermap.insert(respond_to.userid, u.clone());
                if guildid > 0 {
                    if let Some(vg) = self.guildmap.get_mut(&guildid) {
                        vg.insert(userid);
                    } else {
                        let mut set = HashSet::new();
                        set.insert(userid);
                        self.guildmap.insert(guildid, set);
                    }
                }
            }
            _ => {}
        }
    }
    //mut sendnetmsg:mpsc::UnboundedSender<VU8>
    pub(crate) async fn run(mut self) {
        // let logic_handle = self.handle_logic(recv);
        loop {
            tokio::select! {
                recvmsg= self.mpscrecv.recv()=> {
                    if let Some(actmsg) = recvmsg {
                        self.handle_logic(actmsg).await ;
                    }
                }
                recvmsgchan= self.chanchan.recv()=>{
                    if let Some(actmsg) = recvmsgchan {
                        self.handle_logic2(actmsg).await ;
                    }
                }
                // _=tokio::time::sleep(Duration::from_millis(3_000)) =>{
                //     if self.sharestate.load(Ordering::Relaxed) == 0 {
                //         break ;
                //     }
                // }
            }
        } //end loop
    }
}

main

use std::sync::atomic::AtomicU8;

mod gobal;

use gobal::*;

use std::any::Any;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::fmt::Debug;
use std::fs::copy;
use std::{
    fs::File,
    io::{self, BufReader},
    net::SocketAddr,
    sync::Arc,
};

use std::io::{ErrorKind, Read};
use std::pin::Pin;

use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
use std::time::Duration;
use tokio::sync::{mpsc, oneshot};

use futures_util::{FutureExt, SinkExt, StreamExt, TryStreamExt};
use rustls_pemfile::{certs, pkcs8_private_keys};
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::{select, signal, time};
use tokio_rustls::{rustls, server, TlsAcceptor, TlsStream};
use tokio_websockets::{proto, Config, Limits, Message, Payload, WebSocketStream};
mod aes_fun;
mod gobalfun;
mod json_config;
mod pb;
mod useractor;
mod worldactor;

use crate::gobalfun::*;
use crate::pb::chatproto::Chatmsg;
use crate::useractor::MyUserActor;
use crate::worldactor::worldActor;
use bytes::Bytes;
use pb::chatproto;
use prost::Message as ProstMssage;
use tokio::sync::mpsc::UnboundedSender;

use crypto;
use crypto::aes::KeySize;
use crypto::digest::Digest;

use serde_json;
use serde_json::Value as json_value;
//use serde_json::Value::{String as json_String};
//use crate::json_config::u8_aes_128_len;
use env_logger::{Builder, Target};
use log::{debug, error, info, log_enabled, Level, LevelFilter};
use std::env;
//use tracing_subscriber::{filter, prelude::*};
//https://blog.csdn.net/BBinChina/article/details/119520531

// const PATH_TO_CERT: &str = "certs/ca.crt"; //"certs/localhost.crt"; //ca.crt  //server.csr
// const PATH_TO_KEY: &str = "certs/server.key"; //"certs/localhost.key";
const PATH_TO_JSON: &str = "chatserver.json"; //配置文件

fn load_certs(path: &str) -> io::Result<Vec<CertificateDer<'static>>> {
    if let Ok(f) = File::open(path) {
        certs(&mut BufReader::new(f)).collect()
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidInput, "file no exist"))
    }
    // certs(&mut BufReader::new(File::open(path)?)).collect()
}

fn load_key(path: &str) -> io::Result<PrivateKeyDer<'static>> {
    if let Ok(f) = File::open(path) {
        pkcs8_private_keys(&mut BufReader::new(f))
            .next()
            .unwrap()
            .map(Into::into)
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidInput, "file no exist"))
    }
    // pkcs8_private_keys(&mut BufReader::new(File::open(path)?))
    //     .next()
    //     .unwrap()
    //     .map(Into::into)
}

static NEXT_CONNECT_ID: AtomicU32 = AtomicU32::new(1);
fn init_log() {
    use chrono::Local;
    use std::io::Write;
    //env_logger 库不合适要写入文件的日志,不能直接输出到文件和日志轮换(rotating)
    let env = env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "trace");
    let mut builder = env_logger::Builder::from_env(env);
    builder.format(|buf, record| {
        writeln!(
            buf,
            "{} {} [{}:{}:{}]",
            Local::now().format("%Y-%m-%d %H:%M:%S"),
            record.level(),
            record.module_path().unwrap_or("<unnamed>"),
            record.line().unwrap_or(0),
            &record.args()
        )
    });
    builder.target(Target::Stdout);
    builder.filter_level(LevelFilter::Warn);
    builder.init();

    info!("env_logger initialized.");
}

#[cfg(unix)]
async fn sigal_ctrl() -> io::Result<()> {
    if let (mut stream) = signal(SignalKind::hangup()) {
        stream.recv().await;
    }
    Ok(())
}

#[cfg(not(unix))]
async fn sigal_ctrl() -> io::Result<()> {
    signal::ctrl_c().await
}

//#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
//#[tokio::main(flavor = "current_thread")]
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() -> Result<(), Box<dyn Error>> {
    //std::error::
    // let mut builder = Builder::from_default_env();
    // builder.target(Target::Stdout);
    // console_subscriber::ConsoleLayer::builder()
    //     // set how long the console will retain data from completed tasks
    //     .retention(Duration::from_secs(60))
    //     // set the address the server is bound to
    //     .server_addr(([127, 0, 0, 1], 5555))
    //     // ... other configurations ...
    //     .init();
    console_subscriber::init();
    //日志///
    init_log();
    // let mut builder = Builder::from_default_env();
    // builder.target(Target::Stdout);
    // builder.filter_level(LevelFilter::Warn);
    // builder.init();
    //
    // debug!("this is a debug {}", "message");
    // error!("this is printed by default");
    // info!("this is infomsg");
    //env_logger::init();
    /
    let chat_cfg = loadchatcfg(PATH_TO_JSON).await?;
    //return  Err(Box::try_from(io::Error::new(io::ErrorKind::Other, "something went wrong")).unwrap()); //Err("read json file error");
    let addr = SocketAddr::from(([0, 0, 0, 0], chat_cfg.nlistenport as u16)); //default 8080
    let certs = load_certs(chat_cfg.szcacrtfile.as_str())?; //load_certs(PATH_TO_CERT)?;
    let key = load_key(chat_cfg.szprivatekeyfile.as_str())?; //load_key(PATH_TO_KEY)?;

    let config = rustls::ServerConfig::builder()
        .with_no_client_auth()
        .with_single_cert(certs, key)
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;

    let acceptor = TlsAcceptor::from(Arc::new(config));

    let listener = TcpListener::bind(&addr).await?;

    //let world_mgr = MyWorldHandle::new();
    let (world_sender, receiver) = mpsc::unbounded_channel();
    let (world_chan_sender, world_chan_receiver) = mpsc::unbounded_channel();
    let world = worldActor::new(Arc::new(AtomicU8::new(1)), receiver, world_chan_receiver);
    let world_handle = tokio::spawn(world.run());
    let (aes_key, aes_iv) = (chat_cfg.u8AES128keyhandshake, chat_cfg.u8AES128iv);
    println!("server running {}", timestamp_seconds());
    loop {
        select! {
        accept_result = listener.accept() => {
                let (mut stream2,addr) = accept_result?;
                let acceptor = acceptor.clone();
                println!("accept tcp connect {}",timestamp_seconds());
                ///
                let world_chan_sender_1 = world_chan_sender.clone();
                let world_clone_1 = world_sender.clone();
                 tokio::spawn(tls_accept(stream2,acceptor,world_chan_sender_1,world_clone_1,addr.clone(),aes_key.clone(),aes_iv.clone())) ;
             },
             // 接收Ctrl+c SIGINT
            // _ = signal::ctrl_c() => {
            //     //info!("KV Server is shutting down!!!");
            //     world_sender.send(ActorMessage::ctw_signal_event(signalType{signaltype:signalTypeId::Signal_Server_Close as u32,signalparam:0}));
            //     break ;
            // }
            _= sigal_ctrl()=>{
                 world_sender.send(ActorMessage::ctw_signal_event(signalType { signaltype: signalTypeId::Signal_Server_Close as u32, signalparam: 0 }));
                break ;
            }

        } //end select!
    } //end loop
      // 等待服务器关闭
    world_handle.await.unwrap();
    println!("server exit {}", timestamp_seconds());
    Ok(())
}

//async  fn readjsonfile(path:&str)->Option<json_value>{
async fn readjsonfile(path: &str) -> Result<json_value, Box<dyn Error>> {
    let mut f = File::open(path).expect("open file fail");
    let mut data = vec![];
    let s = f.read_to_end(&mut data).expect("read file fail");
    if s < 10 {
        //return Err(std::io::Error::other("data short"));
        //  Err("".into());
        return Err(
            Box::try_from(io::Error::new(io::ErrorKind::Other, "something went wrong")).unwrap(),
        );
    }
    let string = std::string::String::from_utf8_lossy(&data);
    Ok(serde_json::from_str(string.as_ref())?)

    // if let Ok( mut f)= File::open(path) {
    //     let mut data = vec![];
    //     if let Ok(s) = f.read_to_end(&mut data) {
    //         if s < 10 {
    //             return  None;
    //         }
    //         let string = String::from_utf8_lossy(&data); // 将字节向量转换为字符串
    //        if  let Ok(v) = serde_json::from_str(string.as_ref()){
    //            return  Some(v);
    //        }
    //     }
    //
    // }else{
    //     println!(" read file {} fail",path);
    // }
    // None
}

async fn stringtrimchar(string: std::string::String) -> std::string::String {
    "".to_string()
}

async fn loadchatcfg(path: &str) -> Result<json_config::chatservercfg, Box<dyn Error>> {
    let chat_v: json_value = readjsonfile(path).await?;
    let mut chatcfg = json_config::chatservercfg::new();

    const LISTENIP: &str = "listenip";
    const LISTENPORT: &str = "listenport";
    const USESSL: &str = "usessl";
    const PRIVATEKEYFILE: &str = "privatekeyfile";
    const SERVERCRTFILE: &str = "servercrtfile";
    const CACRTFILE: &str = "cacrtfile";
    const DOMAINNAME: &str = "domainname";
    const CROSSDOMAINNAME: &str = "crossdomainname";
    const AES128KEYHANDSHAKE: &str = "aes128keyhandshake";
    const AES128IV: &str = "aes128iv";
    const MAXCONN: &str = "maxconn";
    const CHECKHEARTBEAT: &str = "checkheartbeat";
    const OPENBLACKWHITEIP: &str = "openblackwhiteip";
    const SINGLEIPMAXCONN: &str = "singleipmaxconn";

    // macro_rules! getProp {
    //     ($x:expr, $y:expr) => {
    //         $x.get($y)
    //     };
    // }

    // macro_rules! getProp {
    //     ($x:expr)=>{
    //         chat_v.get($x)
    //     }
    // }
    // const type_num_u:u32 = 1 ;
    // const type_num_i:u32 = 2 ;
    // const type_string:u32 = 3 ;
    //
    // macro_rules! getProp {
    //     ($x:expr,$y:expr)=>{
    //         if let Some(v) = chat_v.get($x){
    //             match $y {
    //                 type_num_u=>{
    //                    if let Some(v2) = v.as_u64(){
    //                        return Ok(v2) ;
    //                    }
    //                 }
    //             }
    //         }
    //         return  Err("");
    //     }
    // }

    if let Some(ip) = chat_v.get(LISTENIP) {
        chatcfg.szlistenip = ip.as_str().unwrap().to_string();
    }

    if let Some(port) = chat_v.get(LISTENPORT) {
        chatcfg.nlistenport = port.as_u64().unwrap() as i32;
    }

    if let Some(bssl) = chat_v.get(USESSL) {
        chatcfg.buseSsl = bssl.as_bool().is_some();
    }

    if let Some(maxconn) = chat_v.get(MAXCONN) {
        chatcfg.u16maxconn = maxconn.as_u64().unwrap() as u16;
    }

    if let Some(keyfile) = chat_v.get(PRIVATEKEYFILE) {
        chatcfg.szprivatekeyfile = keyfile.as_str().unwrap().to_string();
    }

    if let Some(cacrtfile) = chat_v.get(CACRTFILE) {
        chatcfg.szcacrtfile = cacrtfile.as_str().unwrap().to_string();
    }

    if let Some(key) = chat_v.get(AES128KEYHANDSHAKE) {
        //chatcfg.u8AES128keyhandshake = key.as_array().unwrap() ;
        let mut v1 = key.as_str().unwrap().as_bytes(); //.as_slice();
                                                       //32  0x20 (space) 空格
                                                       //34  0x22 "  双引号
                                                       //10  0x0A   换行键    \n是换行
                                                       //13  0x0D  CR (carriage return) 回车键  '\r'是回车
                                                       //39  0x27  ' 闭单引号   单引号的ASCII码是39
                                                       // let vlen = v1.len();
                                                       // if vlen < 16{
                                                       //     return Err(Box::from(std::io::Error::new(ErrorKind::Other,"parse error")));
                                                       // }
                                                       //
                                                       // let tailch = v1[vlen-1] ;
                                                       // if 10 == tailch || 13 == tailch ||  32 == tailch || 34 == tailch || 39 == tailch {
                                                       //    // v1 = v1[..(vlen-1)].to_vec() ;
                                                       //     v1.pop() ;
                                                       // }
                                                       //
                                                       // if 10 == v1[0] || 13 == v1[0] ||  32 == v1[0] || 34 == v1[0] || 39 == v1[0] {
                                                       //     v1 = v1[1..].to_vec() ;
                                                       // }
                                                       //0b_1010_1010
                                                       //let num1: u8 = 0b_1010_1010;
                                                       //println!("{:08b}", !num1);按位取反
        let vlen = v1.len();
        //es 128=16*8 192 =24*8 256=32*8
        if vlen % 8 == 0
            && match vlen / 8 {
                2 | 3 | 4 => true,
                _ => false,
            }
        {
            chatcfg.u8AES128keyhandshake = v1.to_vec();
        }

        //赋值数据到切片里
        // let mut x = vec![0; 8];
        // let y = [1, 2, 3];
        // x[..3].clone_from_slice(&y);
        // println!("{:?}", x);
        // Output:
        // [1, 2, 3, 0, 0, 0, 0, 0]
    }

    if let Some(iv) = chat_v.get(AES128IV) {
        let i = iv.as_str().unwrap().as_bytes();
        if i.len() == 16 {
            chatcfg.u8AES128iv.clone_from_slice(&i);
        } else {
            return Err(Box::from(std::io::Error::new(
                ErrorKind::Other,
                "parse error",
            )));
        }
    } else {
        return Err(Box::from(std::io::Error::new(
            ErrorKind::Other,
            "parse error",
        )));
    }

    if chatcfg.u8AES128keyhandshake.len() < 16 {
        return Err(Box::from(std::io::Error::new(
            ErrorKind::Other,
            "parse error",
        )));
    }

    Ok(chatcfg)
    // if let (Some(ip),Some(port),Some(bssl),Some(maxconn),Some(key),Some(iv)) = (getProp!(LISTENIP),getProp!(LISTENPORT),getProp!(USESSL),getProp!(MAXCONN),
    //                                                          getProp!(AES128KEYHANDSHAKE),getProp!(AES128IV)){
    //     chatcfg.szlistenip = ip.to_string() ;
    //
    // }else{
    //     println!("parse error");
    //     return Err(Box::from(std::io::Error::new(ErrorKind::Other,"parse error")));
    // }
    // if (root[LISTENIP].empty() || root[LISTENPORT].empty() || root[MAXCONN].empty()  \
    // || root[USESSL].empty()  || root[AES128KEYHANDSHAKE].empty() || root[AES128IV].empty()) {
    //     printf("read_json_file base fail\n");
    //     return  false;
    //
    // }
    // chatcfg.szlistenip = chat_v.get(LISTENIP).to_string().?;
    // chatcfg.nlistenport = chat_v.get(LISTENPORT)?;
    //
    // chatcfg.buseSsl = chat_v.get(USESSL).expect("ssl")?;
    // chatcfg.szprivatekeyfile = chat_v.get(PRIVATEKEYFILE).expect("keyfile")?;
    // //chatcfg.szservercrtfile = chat_v.get(SERVERCRTFILE).expect("szservercrtfile")?;
    //
    // chatcfg.szcacrtfile = chat_v.get(CACRTFILE).expect("cacrtfile")?;
    //
    // chatcfg.u8AES128keyhandshake = chat_v.get(AES128KEYHANDSHAKE).expect("AES128keyhandshake")?;
    // chatcfg.u8AES128iv = chat_v.get(AES128IV).expect("AES128iv")?;
    // chatcfg.u16maxconn = chat_v.get(MAXCONN).expect("u16maxconn")?;
    // chatcfg.bcheckheartbeat = chat_v.get(CHECKHEARTBEAT).expect("checkheartbeat")?;

    //Ok(chatcfg)
    // pub(crate)   szlistenip:String,
    // pub(crate)   nlistenport:i32,
    // pub(crate)   buseSsl:bool,
    // pub(crate)   szprivatekeyfile:String,
    // pub(crate)   szservercrtfile:String,
    // pub(crate)   szcacrtfile:String,
    // pub(crate)   szdomainname:String,//域名
    // pub(crate)  szcrossdomainname:String, //跨域名
    // pub(crate) u8AES128keyhandshake:[u8;u8_aes_128_len as usize], //16*8=128  16个字节就可以了 yyuilioudkiojun  aes 128=16*8 192 =24*8 256=32*8
    // pub(crate) u8AES128iv:[u8;16],//16个字节 固定的16个字节 不管是ase128 192 256
    // pub(crate) u16maxconn:u16,//最大连接数(总的)
    // pub(crate) bcheckheartbeat:bool,//检测心跳
    // pub(crate) u8openblackwhiteip:u8,//开启黑白名单
    // pub(crate)u8singleipmaxconn:u8,//单个IP 最大连接数
}

//&'static str
//Result<(),dyn std::error::Error>  Box<dyn Error
证书校验 完成
async fn wait_tls_check(
    stream2: TcpStream,
    acceptor: TlsAcceptor,
    timeoutcheck: u64,
) -> Result<server::TlsStream<TcpStream>, &'static str> {
    //
    let dur = Duration::from_millis(timeoutcheck);
    match time::timeout(dur, acceptor.accept(stream2)).await {
        Ok(v) => {
            match v {
                Ok(v1)=>Ok(v1),
                e=>{
                    println!("wait_tls_check accept error");
                    println!("{:?}",e);
                    Err("accept error")
                }
            }
            // if let Ok(v1) = v {
            //     Ok(v1)
            // } else {
            //     println!("wait_tls_check accept error");
            //     // let _= stream2.shutdown().await ;
            //     // let _=  stream2.borrow().shutdown().await.unwrap();
            //     Err("accept error")
            // }
        }
        _ => {
            // Err(io::Error::new(io::ErrorKind::InvalidInput, "file no exist"))
            // stream2.borrow().shutdown().await.unwrap();
            // stream2.borrow().shutdown();
            //怎么关闭 stream2 ????
            println!("wait_tls_check timeout");
            Err("time out")
        }
    }
}

async fn wait_handleshake(
    stream: server::TlsStream<TcpStream>,
    timeoutcheck: u64,
) -> Option<WebSocketStream<server::TlsStream<TcpStream>>> {
    let f1 = async {
        tokio_websockets::ServerBuilder::new()
            .limits(Limits::default().max_payload_len(Some(MAX_PAYLOAD_LEN)))
            .config(Config::default().frame_size(MAX_FRAME_SIZE))
            .accept(stream)
            .await
    };
    let dur = Duration::from_millis(timeoutcheck);
    match time::timeout(dur, f1).await {
        Ok(v) => {
            if let Ok(v1) = v {
                Some(v1)
            } else {
                None
            }
        }
        _ => {
            // stream.shutdown()
            //关闭 stream
            println!("wait_handleshake timeout");
            None
        }
    }
}

async fn recv_frist_msg(
    mut ws: WebSocketStream<server::TlsStream<TcpStream>>,
    timeoutcheck: u64,
) -> Option<(WebSocketStream<server::TlsStream<TcpStream>>, Message)> {
    let dur = Duration::from_millis(timeoutcheck);
    let f1 = async { ws.next().await };
    match time::timeout(dur, f1).await {
        Ok(v) => {
            if let Some(Ok(m)) = v {
                Some((ws, m))
            } else {
                None
            }
        }
        _ => {
            println!("recv_frist_msg timeout {}", timestamp_seconds());
            ws.close().await.unwrap();
            None
        }
    }
}

async fn verify_user_login(
    userid: &UserID,
    username: &String,
    guild_id: &GuildID,
    ase_token: &String,
    md5_v: &String,
    ip_addr: &String,
    aeskey: &VU8,
    iv: &[u8; 16],
) -> Result<(), Box<dyn Error>> {
    let v = concat_string_token(&userid, &username, &guild_id, &ase_token);
    let mut sh = crypto::md5::Md5::new();
    sh.input_str(v.as_str());
    let md5str = sh.result_str();
    if !md5_v.eq(&md5str) {
        return Err("fail".into());
    }

    let keylen = match aeskey.len() as u16 {
        24 | 32 => aeskey.len() as u16,
        _ => 16,
    };
    if let Ok(mut v) = aes_fun::encrypt(ase_token.as_bytes(), &aeskey, iv.as_ref(), keylen * 8) {
        let len_v = v.len();
        if len_v > 10 {
            if v[len_v - 1] == ']' as u8 {
                v.pop();
            }
            if v[0] == '[' as u8 {
                v = v[1..].to_vec();
            }
        }
        if let Ok(str) = std::str::from_utf8(&v) {
            let t_string = str.to_string();
            let raw_parts: Vec<&str> = t_string.split("#").collect();
            //username base64  //小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"(再加上作为垫字的"=",实际上是65个字符)
            //[userid#username#guildid#ipaddr#timestamp#serverid#random]  == 7    //username 为 base64encode 后的
            if raw_parts.len() == 7 {
                if let Ok(v_userid) = raw_parts[0].parse::<u32>() {
                    let v_username = raw_parts[1].to_string();
                    if let Ok(v_guildid) = raw_parts[2].parse::<u32>() {
                        let v_ipaddr = raw_parts[3].to_string();
                        if let Ok(v_timestampe) = raw_parts[4].parse::<u32>() {
                            if let Some(en_username) = aes_fun::base64encode(username.as_str()) { //加密后再比较也一样
                            }
                            if v_userid == *userid && v_guildid == *guild_id && *ip_addr == v_ipaddr
                            {
                                if gobalfun::timestamp_seconds() <= (v_timestampe + 30) as u64 {
                                    //30秒内有效
                                    return Ok(());
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    // let  encrypted_data = aes_fun::encrypt(ase_token.as_bytes(), &aeskey, iv.as_ref(),128).ok().unwrap();

    // if !md5str.eq(&md5_v) {
    //     return Err("fail".into());
    // }
    //  let data ="1233" ;
    //  let v: Value = serde_json::from_str(data)?;
    //  crypto::aes::cbc_decryptor()
    Err("fail".into())
}

async fn tls_accept(
    mut stream2: TcpStream,
    acceptor: TlsAcceptor,
    world_chan_sender_1: UnboundedSender<ActorMessage2>,
    world_clone_1: UnboundedSender<ActorMessage>,
    addr: SocketAddr,
    vecaeskey: VU8,
    iv: [u8; 16],
) {
    if let Ok(v) = wait_tls_check(stream2, acceptor, 6_000).await {
        if let Some(mut ws) = wait_handleshake(v, 4_000).await {
            if let Some((mut ws, req)) = recv_frist_msg(ws, 3_000).await {
                //处理接受的第一个消息
                let world_chan_sender_2 = world_chan_sender_1.clone();
                let world_clone_2 = world_clone_1.clone();
                let connid = NEXT_CONNECT_ID.fetch_add(1, Ordering::Relaxed);
                let (t1, r1) = mpsc::unbounded_channel::<SendClientMsg>();

                let msgData = Vec::from(req.as_payload().to_vec());
                let (msgid, mask) = getProtoMsgIdAndMask(&msgData);

                let res = match msgid {
                    msg_id_login => {
                        if let Ok(req) = chatproto::ChatMessageLoginReq::decode(&msgData[..]) {
                            // error!("recv frirst msg");
                            // crypto::aes::cbc_decryptor(KeySize::KeySize128,"12345678".to_string().encode_to_vec().borrow(),)
                            //检测 req.tokenstr  req.tokenmd5
                            //检查合法性
                            // if req.tokenstr.len() > 20 { //[userid#username#guildid#ipaddr#timestamp#serverid#random]
                            //     if let Ok(_) = verify_user_login(&req.userid,&req.username,&req.guildid,&req.tokenstr,&req.tokenmd5,&addr.to_string(),&vecaeskey,&iv).await {
                            //
                            //     }else{
                            //         let _ =ws.close();
                            //         return;
                            //     }
                            // }else{
                            //     let _ =ws.close();
                            //     return;
                            // }

                            //check_user_login()
                            let world_chan_sender_3 = world_chan_sender_2.clone();
                            if let Ok(res) = query_user_channel2(
                                req.userid,
                                world_chan_sender_2,
                                connid,
                                t1.clone(),
                            )
                            .await
                            {
                                if res.state > 0 {
                                    if res.state > 1 {
                                        //超过最大在线人数
                                        let mut repmsg = chatproto::ChatMessageLoginRep {
                                            msghead: Some(chatproto::ChatMessageHeadNoMask {
                                                msgid: chatproto::Chatmsg::ChcLoginRep as u32,
                                            }),
                                            res: 2,
                                            tokenrelogin: "".to_string(),
                                            timestamp: 0,
                                        };

                                        //   ws.send(Message::text(String::from("Hello, world!").into()))
                                        let mut buf = Vec::new();
                                        if let Ok(_) = repmsg.encode(&mut buf) {
                                            //  Payloads can be created by using the From<Bytes>, From<BytesMut> and From<String>
                                            let sendmsg =
                                                tokio_websockets::Message::binary(Bytes::from(buf));
                                            let _ = ws.send(sendmsg).await;
                                        }
                                    }
                                    let _ = ws.close().await;
                                } else if let Some(s) = res.op {
                                    //用现成的 //挤号

                                    let mut repmsg = chatproto::ChatMessageLoginRep {
                                        msghead: Some(chatproto::ChatMessageHeadNoMask {
                                            msgid: chatproto::Chatmsg::ChcLoginRep as u32,
                                        }),
                                        res: 1,
                                        tokenrelogin: "".to_string(),
                                        timestamp: 0,
                                    };
                                    let mut buf = Vec::new();
                                    if let Ok(_) = repmsg.encode(&mut buf) {
                                        let sendmsg =
                                            tokio_websockets::Message::binary(Bytes::from(buf));
                                        let _ = ws.send(sendmsg).await;
                                    }
                                    tokio::spawn(run_user_actor_network(
                                        ws,
                                        s.sendchann,
                                        r1,
                                        s.actorState,
                                        connid.clone(),
                                    ));
                                } else {
                                    // 创建新的  //登录
                                    let (logicchantx, logicchanrx) = mpsc::unbounded_channel();
                                    let mut useractor = MyUserActor::new(
                                        connid.clone(),
                                        logicchanrx,
                                        t1,
                                        world_clone_2,
                                    );
                                    useractor.setuserinfo(
                                        req.userid.clone(),
                                        req.username.clone(),
                                        req.guildid.clone(),
                                        UserState_INIT,
                                    );
                                    //把发送通道发送给worldactor
                                    let userinfo = userChan_CTW {
                                        msgtype: 0,
                                        userid: req.userid,
                                        username: req.username,
                                        userguildid: req.guildid,
                                        connectid: connid,
                                        logicChann: logicchantx.clone(),
                                        chanState: useractor.getuserstateclone(),
                                    };
                                    let _ = world_chan_sender_3.send(ActorMessage2::ctw_userhann {
                                        respond_to: userinfo,
                                    });
                                    let ustate = useractor.getuserstateclone();

                                    let mut repmsg = chatproto::ChatMessageLoginRep {
                                        msghead: Some(chatproto::ChatMessageHeadNoMask {
                                            msgid: chatproto::Chatmsg::ChcLoginRep as u32,
                                        }),
                                        res: 0,
                                        tokenrelogin: "".to_string(),
                                        timestamp: 0,
                                    };
                                    let mut buf = Vec::new();
                                    if let Ok(_) = repmsg.encode(&mut buf) {
                                        // buf.insert(0,MyMsgType::Binary as u8);
                                        let sendmsg =
                                            tokio_websockets::Message::binary(Bytes::from(buf));
                                        let _ = ws.send(sendmsg).await;
                                    }
                                    useractor.setuserstate(UserState::UserState_NORMAL as u8);
                                    tokio::spawn(run_my_user_actor(useractor)); //逻辑future
                                    tokio::spawn(run_user_actor_network(
                                        ws,
                                        logicchantx,
                                        r1,
                                        ustate,
                                        connid.clone(),
                                    )); //网络发送接受 future
                                }
                            } else {
                                let _ = ws.close().await;
                            }
                        } else {
                            let _ = ws.close().await;
                        }
                        // return Ok(());
                    }
                    msg_id_relogin => {
                        if let Ok(req) = chatproto::ChatMessageReLoginReq::decode(&msgData[..]) {
                            // if let Ok(res) = world_clone_2.query_user_channel(req.userid).await {
                            //
                            // }
                        }

                        // return Ok(());
                    }
                    _ => {
                        let _ = ws.close().await;
                        //return Err("msg is error");
                    }
                };
            } // 3 wait
        }
    }
}

2 toml 文件

[dependencies]
tokio-websockets= { version = "0.5",features = ["server","ring"] }
futures-util = { version = "0.3.30",features = ["sink"] }
rustls-pemfile = "2.0.0"
#tokio = { version = "1.35.1", features = ["full"] }
tokio = { version = "1.35", features = ["full", "tracing"] }
tokio-rustls = "0.25.0"
rustls = "0.22.1"
rustls-pki-types = "1.1.0"
tokio-stream = "0.1.14"
bytes = "1.5.0"
prost="0.12"
prost-types = "0.12"
rust-crypto = "^0.2"
serde_json = "^1.0"
base64 = "0.21.7"
log = "0.4.0"
env_logger = "0.11"
chrono = "0.4.33"
#tracing-subscriber = { version = "0.3", default-features = false, features = ["alloc"] }
console-subscriber = "0.2.0"
#tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_warn"] }
#tokio-console = "0.1.10"

#[dependencies]
#hello_utils = { path = "hello_utils" }
# 以下路径也可以
# hello_utils = { path = "./hello_utils" }
# hello_utils = { path = "../hello_world/hello_utils" }


#运行测试时用到
[build-dependencies]
#tokio-websockets= { version = "0.5",features = ["server","ring"] }
#futures-util = { version = "0.3.30",features = ["sink"] }
#rustls-pemfile = "2.0.0"
#tokio = { version = "1.35.1", features = ["full"] }
#tokio-rustls = "0.25.0"
#rustls = "0.22.1"
#rustls-pki-types = "1.1.0"
#tokio-stream = "0.1.14"
#bytes = "1.5.0"
prost-build = { version = "0.12"}

3:代码说明
在这里插入图片描述
tls_accept 函数里
1> tls 握手(网上抄了张别人的图)这里设定必须N秒完成
在这里插入图片描述
2> websocket 握手 这里设定必须N秒完成
WebSocket握手过程
wobsocket会经过下面几个步骤:
(1)客户端发送WebSocket握手
(2)服务器响应握手请求
(3)客户端验证握手响应
(4)认确握手成功并建立websocket连接

3> 连接成功,接收登录消息 这里设定必须N秒完成
在这里插入图片描述

4> 处理登录验证** 具体代码 到看main.rs
(1) 超过最大人数 处理
(2) 挤号处理
(3) 新连接理
在这里插入图片描述

在这里插入图片描述
5>增加日志
在这里插入图片描述

4:测试
重新修改golang的前端
启动 testclientweb 1001 100 1000 192.168.1.131:8080
1001 启示userid
100 就是 100个连接 usertid [1001,1001+100)
1000 guildid
192.168.1.131:8080 连接的IP:PORT

package main

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/websocket"
	"log"
	"os"
	"strconv"
	"sync"
	"testwebclient/chatproto"
	"time"
)

//var origin = "http://115.159.207.227:7077"  //http://login.yyfjfy.com/websocket/
//var url = "ws://115.159.207.227:7077/websocket"

//var origin = "http://192.168.1.131:9000"  //http://login.yyfjfy.com/websocket/
//var url = "ws://192.168.1.131:7077/"
//var url = "wss://192.168.1.131:9000/websocket"
//var origin = "http://chat.yy9w.com:9501"
//var url = "wss://chat.yy9w.com:9501/websocket"

var origin = "http://192.168.1.131:8080"
var url_wss = "wss://192.168.1.131:8080/websocket"
var url_ws ="ws://192.168.1.131:8080/websocket"
//var origin = "http://124.222.83.132:9501"
//var url = "ws://124.222.83.132:9501/websocket"

func GetProtoMsgID(data []byte) uint32 {
	var sMsgID uint16 = uint16(uint8(data[3] & 0x7f))
	if (uint8(data[3]) & 0x80) > 0 {
		sMsgID += (uint16(data[4]) & 0x7f) << 7
	}
	return uint32(sMsgID)
}

func GetProtoMsgIdAndMask(data []byte) (uint32, uint32) {
	var sMsgID uint16 = uint16(uint8(data[3] & 0x7f))
	if (uint8(data[3]) & 0x80) > 0 {
		sMsgID += (uint16(data[4]) & 0x7f) << 7
	}

	var sMaskID uint32 = uint32(data[6])
	sMaskID |= uint32(data[7]) << 8
	sMaskID |= uint32(data[8]) << 16
	sMaskID |= uint32(data[9]) << 24

	return uint32(sMsgID), sMaskID
}

func  sendMsg(ws *websocket.Conn,pb proto.Message) {
	if ws != nil {
		if data, err2 := proto.Marshal(pb); err2 != nil {
			log.Printf("SendMessage pb=%v err2=%v \n", pb, err2)
		} else {
			if err4 := websocket.Message.Send(ws, data); err4 != nil {
				log.Printf("send error =%v \n", err4)
			}
		}
	}
}

func doLogicMsg(data []byte)  {
	msgId := GetProtoMsgID(data)
	//fmt.Printf("recv msgid=%v	",msgId)
	switch msgId {
	case uint32(chatproto.CHATMSG_CHC_Login_Rep):
		{
			loginReq := &chatproto.ChatMessageLoginRep{}
			if err := proto.Unmarshal(data, loginReq); err != nil {

			} else {
			//	fmt.Printf("CHATMSG_CHC_Login_Rep =%v \n",loginReq.Res)
			}
		}
	case uint32(chatproto.CHATMSG_CCH_Chat_Rep):
		{
			chatrep := &chatproto.ChatMessageChatRep{}
			if err := proto.Unmarshal(data, chatrep); err != nil {

			} else {
			//	fmt.Printf("CHATMSG_CCH_Chat_Rep =%v \n",chatrep.Res)
			}
		}
	case uint32(chatproto.CHATMSG_CHC_Notify_Chat):
		{
			chatmsg := &chatproto.ChatMessageNotifyChat{}
			if err := proto.Unmarshal(data, chatmsg); err != nil {

			} else {
			//	fmt.Printf("CHATMSG_CHC_Notify_Chat =%v fromuserid=%v text=%v \n",chatmsg.Chattype,chatmsg.Senderid,chatmsg.Strcontext)
			}
		}
	case uint32(chatproto.CHATMSG_CHC_Notify_Msg):
		{
			chatmsg := &chatproto.ChatMessageNotifyMsg{}
			if err := proto.Unmarshal(data, chatmsg); err != nil {

			} else {
			//	fmt.Printf("CHATMSG_CHC_Notify_Msg msgtype=%v text=%v \n",chatmsg.Msgtype,chatmsg.Strcontext)
			}
		}
	}

}
func getTimestamp() uint32 {
	return  uint32(time.Now().UTC().Unix())
}

func  testone()  {
	userid :=  getTimestamp()
	guildid := uint32(0)
	delayseconds := int64(1)
	usewss := true
	if len(os.Args) > 1 {
		if s,e := strconv.Atoi(os.Args[1]);e ==nil {
			userid = uint32(s)
		}
	}
	if len(os.Args) > 2 {
		if s,e := strconv.Atoi(os.Args[2]);e ==nil {
			guildid = uint32(s)
		}
	}

	if len(os.Args) > 3 {
		if s,e := strconv.Atoi(os.Args[3]);e ==nil {
			delayseconds = int64(s)
		}
	}

	if len(os.Args) > 4 {
		if s,e := strconv.Atoi(os.Args[4]);e ==nil {
			if s > 0 {
				usewss = true
			}else{
				usewss = false
			}
		}
	}
	url := url_wss
	if !usewss {
		url = url_ws
	}
	ws, err := websocket.Dial(url, "", origin)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("getTimestamp=%v userid=%v guild=%v dayseconds=%v url=%v \n",getTimestamp(),userid,guildid,delayseconds,url)
	if delayseconds > 0 {
		d := time.Duration(delayseconds)*time.Second
		//fmt.Printf("[%v]dayseconds[start] =%v %v \n",getTimestamp(),d,dayseconds)
		time.Sleep(d)
		//	fmt.Printf("[%v]dayseconds[end] =%v \n",getTimestamp(),dayseconds)
	}
	{
		msg := new(chatproto.ChatMessageLoginReq)
		msg.Msghead = &chatproto.ChatMessageHead{uint32(chatproto.CHATMSG_CCH_Login_Req), 1}
		msg.Userid = userid
		msg.Username = "name_"+strconv.Itoa(int(userid))
		msg.Guildid = guildid
		msg.Tokenmd5 = "md5"
		msg.Tokenstr = "Tokenstr"

		sendMsg(ws, msg)
	}
	disflag :=  false
	{
		go func() {
			for{
				buf := make([]byte, 1024*4)
				err := websocket.Message.Receive(ws, &buf)
				if err != nil {
					//log.Printf("websocket.Message.Receive err=%v  ---%s\n", err,self.getAccName())
					disflag = true
					return
				}

				if len(buf) >= 4 {

					doLogicMsg(buf)

					//self.msgQue.PostUserMessage(&ReceiveNetMsg{buf})
				} else {
					log.Printf("[error]recv data=%v \n", buf)
					return
				}
			}

		}()

	}
	time.Sleep(time.Second*3)

	//pub enum  ChatChannel{
	//	ChatChannel_NONE=0,
	//	ChatChannel_NORMAL,
	//	ChatChannel_GUILD,
	//	ChatChannel_WORLD,
	//	ChatChannel_ALL,
	//}


	{
		sendcount := uint32(1)
		num := uint32(0)
		msg := new(chatproto.ChatMessageChatReq)
		msg.Msghead = &chatproto.ChatMessageHead{uint32(chatproto.CHATMSG_CCH_Chat_Req), 1}
		msg.Chattype = 1
		msg.Context ="normal chat "+ strconv.Itoa(int(num))

		for {
			if disflag { //脏数据
				break
			}
			sendMsg(ws, msg)
			time.Sleep(time.Second*2)
			//time.Sleep(time.Millisecond *10)
			num++
			m := num % 3 +1
			msg.Chattype = uint32(m)
			msg.Context ="normal chat "+ strconv.Itoa(int(sendcount))
			fmt.Printf("[%v][%v] send chattype=%v \n",sendcount,getTimestamp(),msg.Chattype)
			sendcount++
			//if m == 3  {
			//	time.Sleep(time.Second*10)
			//}
		}
	}

	ws.Close()//关闭连接
	fmt.Printf("client exit\n")
}
//testclientweb  1001 1 1000 192.168.1.131:8080
func main(){
	wg := new(sync.WaitGroup)
	if len(os.Args) == 5 {
		useridmin := uint32(0)
		var num uint32 = 0
		var guildid uint32 = 0

		//wss://192.168.1.32:8080/websocket
		url_wss =  fmt.Sprintf("wss://%v/websocket",os.Args[4])
		//"http://192.168.1.32:8080"
		origin = fmt.Sprintf("http://%v",os.Args[4])

		fmt.Printf("url=%v origin=%v \n",url_wss,origin)

		if s,e := strconv.Atoi(os.Args[3]);e ==nil {
			guildid = uint32(s)
		}

		if s,e := strconv.Atoi(os.Args[2]);e ==nil {
			num = uint32(s)
		}

		if s,e := strconv.Atoi(os.Args[1]);e ==nil {
			useridmin = uint32(s)
		}
		//wg.Add(int(num))
		testrobot(wg,useridmin,num,guildid)
	//	wg.Add(int(num))
	}else{
		wg.Add(1)
		testone()
		wg.Done()
	}

	wg.Wait()
	fmt.Printf("client wait exit")
	//select {
	//
	//}
}

func loginmsg(userid uint32,guildid uint32)proto.Message  {
	msg := new(chatproto.ChatMessageLoginReq)
	msg.Msghead = &chatproto.ChatMessageHead{uint32(chatproto.CHATMSG_CCH_Login_Req), 1}
	msg.Userid = userid
	msg.Username = "name_"+strconv.Itoa(int(userid))
	msg.Guildid = guildid
	msg.Tokenmd5 = "md5"
	msg.Tokenstr = "Tokenstr"
	return msg
}

func runonerobot(wg *sync.WaitGroup,ws *websocket.Conn,userid ,guildid uint32)  {
	disflag := false
	defer  wg.Done()
	log.Printf("ready recv msg [%v,%v] \n",userid ,guildid)
	go func() {
		recvcount := uint32(0)
		lastcount := uint32(0)
		for{
			buf := make([]byte, 1024*4)
			err := websocket.Message.Receive(ws, &buf)
			if err != nil {
				//log.Printf("websocket.Message.Receive err=%v  ---%s\n", err,self.getAccName())
				disflag = true
				return
			}

			if len(buf) >= 4 {

				doLogicMsg(buf)

				recvcount++
				if (recvcount /50000) > lastcount {
					lastcount = recvcount /50000
					log.Printf("[%v]recv logic msg %v \n",userid,recvcount)
				}
				//self.msgQue.PostUserMessage(&ReceiveNetMsg{buf})
			} else {
				log.Printf("[error]recv data=%v \n", buf)
				return
			}
		}

	}()

	wg.Add(1)
	msg := loginmsg(userid,guildid)
	sendMsg(ws,msg)
	time.Sleep(time.Millisecond *50)
	{
		sendcount := uint32(1)
		num := uint32(0)
		msg := new(chatproto.ChatMessageChatReq)
		msg.Msghead = &chatproto.ChatMessageHead{uint32(chatproto.CHATMSG_CCH_Chat_Req), 1}
		msg.Chattype = 1
		msg.Context ="normal chat "+ strconv.Itoa(int(num))

		//1 normal 2  guild  3 world  4 all server(后续实现)
		for {
			if disflag { //脏数据
				break
			}
			sendMsg(ws, msg)
			//time.Sleep(time.Second)
			time.Sleep(time.Millisecond *1000) //50
			num++
			//m := num % 3 +1
			msg.Chattype = uint32(2)
			msg.Context ="normal chat "+ strconv.Itoa(int(sendcount))
		//	fmt.Printf("[%v][%v] send chattype=%v \n",sendcount,getTimestamp(),msg.Chattype)
			sendcount++
			//if m == 3  {
			//	time.Sleep(time.Second*10)
			//}
		}
	}

	ws.Close()//关闭连接
	fmt.Printf("client exit %v \n",userid)
}

func  testrobot(wg *sync.WaitGroup,useridmin,num uint32,guildid uint32)  {

	fmt.Printf("startuser=%v num=%v guild=%v \n",useridmin,num,guildid)
	//sendMsg(ws, msg)
	for i:=useridmin;i<useridmin+num;i++ {
		//loginmsg
		ws, err := websocket.Dial(url_wss, "", origin)
		if err != nil {
			//log.Fatal(err)
			log.Printf("[%v]Dial fail %v \n",i,err.Error())
			time.Sleep(time.Millisecond *100)
			continue
		}
		go runonerobot(wg,ws,i,guildid)
		time.Sleep(time.Millisecond *200)
		//time.Sleep(time.Millisecond *10)
	}
}

在这里插入图片描述
再来个c++版的 不知道是不是用虚拟机的问题,带宽最大只能达100M 左右 再多开前端 ssl_write 有几率会失败(返回 SSL_ERROR_SSL)
一个父进程(daemon进程)
一个子进程 (网络进程)
一个子进程 (逻辑进程)

c++ protobuf 建议使用 3.21.12及以下 ,往上版本需要abseil的三方库,安装方式比较复杂
这里使用的3.21.11
在这里插入图片描述
主要逻辑处理代码

const uint32_t nlen = pblock->len;
uint64_t msgid_mask = getmsgidandmask(buf, nlen);
const uint32_t msgid = msgid_mask >> 32;
const uint32_t mask = msgid_mask & 0xFFFFFFFF;

switch (msgid)
{
case chatproto::CCH_Login_Req:
{
	chatproto::ChatMessageReLoginReq  req;
	if (!req.ParseFromArray((void*)buf, nlen)) { // 反序列化
		printf("parse fail protobuf(CCH_Login_Req) \n");
	}
	else {
		printf("client login %d %d\n", pblock->fd, req.userid());
	}

	const uint32_t userid = req.userid();
	string  username = req.username();
	const uint32_t guildid = req.guildid();

	UserBaseInfo* puser = UserMgr::GetInstance().getUserBaseInfo(userid);
	if (puser != nullptr) {
       //暂未处理
	}
	else {
		UserBaseInfo* p = new UserBaseInfo();
		p->userid = userid;
		strncpy(p->username, username.c_str(), 63);
		p->userguildid = guildid;
		p->userstate = 1;
		p->fd = pblock->fd;
		p->id = pblock->id;

		UserMgr::GetInstance().addNewUserInfo(p);
		

	}
	chatproto::ChatMessageHeadNoMask* prephead = new chatproto::ChatMessageHeadNoMask();

	prephead->set_msgid(chatproto::CHATMSG::CHC_Login_Rep);
	chatproto::ChatMessageLoginRep rep;
	rep.set_allocated_msghead(prephead);
	rep.set_res(1);
	int len = rep.ByteSize(); //获取长度
//	uint8_t  databuf[1024];
	memset(databuf, 0, 1024);
	rep.SerializeToArray(databuf, len);//序列化
	send_data(pblock->fd,pblock->id, databuf, len, WebSocketFrameType::BINARY_FRAME);
	printf("client login finish  %d\n", userid);
}
break;
case chatproto::CCH_Chat_Req:
{ 
	//const uint32_t userid = req.param();
	const uint64_t key = (uint64_t(pblock->fd) << 32) + pblock->id;
	UserBaseInfo* puser = UserMgr::GetInstance().getUserBaseInfoBySession(key);
	if (puser) {
		//const uint32_t userid = req.param();
		chatproto::ChatMessageChatReq  req;
		if (!req.ParseFromArray((void*)buf, nlen)) { // 反序列化
			printf("parse fail protobuf(ChatMessageChatReq) \n");
		}
		const uint32_t userid = puser->userid;
		const uint32_t channel = req.chattype();
		if (channel == ChatChannel::ChatChannel_GUILD || channel == ChatChannel::ChatChannel_WORLD) {
			chatproto::ChatMessageHeadNoMask* prephead = new chatproto::ChatMessageHeadNoMask();
			prephead->set_msgid(chatproto::CHATMSG::CHC_Notify_Chat);


			string strcontext = req.context();
			chatproto::ChatMessageNotifyChat rep;
			rep.set_allocated_msghead(prephead);
			rep.set_chattype(channel);
			rep.set_senderid(userid);
			rep.set_sendername(puser->username);
			rep.set_strcontext(strcontext);
		//	rep.mutable_sendername() = puser->username;
			//rep.mutable_sendername()->CopyFrom(puser->username);
		//	rep.set_allocated_strcontext(&strcontext); 
			//rep.mutable_strcontext() = ;
			const int len = rep.ByteSize(); //获取长度

			memset(databuf, 0, 1024);
			rep.SerializeToArray(databuf, len);//序列化
			const uint32_t u32len = generateframedata(databuf, len, WebSocketFrameType::BINARY_FRAME,outbuf);
			if (u32len <= len) {
				printf("[error]data generate fail \n");
			}

			if (channel == ChatChannel::ChatChannel_GUILD && puser->userguildid > 0) {
				vector<UserBaseInfo*> v = UserMgr::GetInstance().getGuildInfo(puser->userguildid);
				UserBaseInfo* ptuser = nullptr;
				const uint32_t guildsize = v.size();
				for (uint32_t i = 0; i < guildsize; ++i) {
					ptuser = v[i];
					if (ptuser && ptuser->userstate > 0) {
						//send_data(ptuser->fd, ptuser->id, databuf, len, WebSocketFrameType::BINARY_FRAME);
						senddata_immediately(outbuf, u32len, WebSocketFrameType::BINARY_FRAME, ptuser->fd, ptuser->id);
					}
				}
			}
			else if (channel == ChatChannel::ChatChannel_WORLD) {
				UserBaseInfo* ptuser = nullptr;
				map<uint32_t, UserBaseInfo*> m = UserMgr::GetInstance().getallUsermap();
				for (auto i = m.begin(); i != m.end(); ++i) {
					ptuser = i->second;
					if (ptuser && ptuser->userstate > 0) {
						//send_data(ptuser->fd, ptuser->id, databuf, len, WebSocketFrameType::BINARY_FRAME);
						senddata_immediately(outbuf, u32len, WebSocketFrameType::BINARY_FRAME, ptuser->fd, ptuser->id);
					}
				}
			}

			//send_data(pblock->fd, pblock->id, databuf, len, WebSocketFrameType::BINARY_FRAME);

		}
		else if (channel == ChatChannel::ChatChannel_NORMAL) {

		}
	}
	
}
break;
default:
	break;
}

5:DEMO工程
1>DEMO工程 内存一直在增长 (需要改善)
2> 黑白名单没有
3>日志 写文件没有,当前只有打印
4>限制单个IP的连接数及限流(令牌或水桶)
demo工程下载地址
如果觉得有用,麻烦点个赞,加个收藏

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值