A lightweight TCP server framework

A new TCP service and client crate, the entire client and server design is as follows. I would like to hear everyone's opinions on what needs to be improved, what are the shortcomings, and what further improvements are needed? I am glad to receive your letters. Thank you very much :kissing_heart:

Links

crates.io
docs.rs
github

Design

  1. First, use the TcpListener on Tokio to listen on port (0.0.0.0:9177), then start an asynchronous thread and use the created TcpListener to start listening for new TcpStream entries
    â‘ . When a new TcpStream is entered, first query the value of Server_max_Connections (usize) in the app configuration and compare it with the len of the clients (Arc<RwLock<HashMap<SocketAddr, LynnUser>>>) in the app. If the clients have reached their maximum value, then disconnect the current TcpStream. Otherwise, create a new asynchronous thread

  2. Split the TcpStream in a new thread to obtain the read_calf and writable variables
    â‘ . Create a channel in the current thread for asynchronous multi-threaded communication At the same time, create a LynnUser containing a sender for the channel, and insert SocketAddr and LynnUser as keys and values into the app's clients, respectively
    â‘¡. Create a new asynchronous thread in the current thread, use the Receiver of the channel to read it, and when the Receiver receives the message data, send the message out through writable
    â‘¢. In the current thread, use read_malf to listen. When data enters, receive the data and pass it to a custom message parser

  3. Validate message data in a custom message parser
    â‘ . Custom start and end marks were used. If the data meets the mark criteria, it indicates that the data is a complete message. The data enclosed between the start and end marks is encapsulated in a struct (InputBufVo). If the mark criteria are not met, the currently received byte data is discarded (concurrent message from the agreed client)
    â‘¡. Pass the encapsulated struct (InputBufVo) to the task scheduler

  4. The task scheduler contains n created asynchronous threads, each thread containing a channel
    â‘  .The struct (InputBufVo) contains: received byte data, Future
    â‘¡. After receiving the struct (InputBufVo), the task scheduler performs a simple load balancing by evenly sending the struct (InputBufVo) through the sender in the asynchronous thread channel
    â‘¢. Receive through the Receiver of the channel in the thread. When a struct (InputBufVo) enters, use the Future in the struct(InputBufVo) to pass in byte data and wait for the execution to complete

  5. After the asynchronous thread completes the task, create a struct (Result)
    â‘  The struct (Result) contains the field is_dend (boolean), which represents whether it needs to be sent to the client
    â‘¡. If the data needs to be sent to the client, the corresponding channel (Sender) in LynnUser in the app's clients should be sent out, and a complete communication is completed until then

A new version v1.1.0 :hugs:,
Now supports any combination of routing with different parameters
like this:

pub async fn my_service() -> HandlerResult {
    HandlerResult::new_without_send()
}
pub async fn my_service_with_buf(input_buf_vo: InputBufVO) -> HandlerResult {
    println!(
        "service read from :{}",
        input_buf_vo.get_input_addr().unwrap()
    );
    HandlerResult::new_without_send()
}
pub async fn my_service_with_clients(clients_context: ClientsContext) -> HandlerResult {
    HandlerResult::new_with_send(1, "hello lynn".into(), clients_context.get_all_clients_addrs().await)
}
......
        .add_router(1, my_service)
        .add_router(2, my_service_with_buf)
        .add_router(3, my_service_with_clients)
......