[dependencies]
tokio ={version ="1.36.0", features =["net","macros","io-std","rt-multi-thread"]}
tokio-tungstenite ={ version ="0.21.0"}
futures-util ="0.3.30"
futures-channel ="0.3.30"
url ="2.5.0"
1. 客户端案例
usefutures_util::{future, pin_mut,StreamExt};usetokio::io::{AsyncRead,AsyncReadExt,AsyncWrite,AsyncWriteExt};usetokio::net::TcpStream;usetokio_tungstenite::tungstenite::error::ErrorasWsError;usetokio_tungstenite::tungstenite::handshake::client::{generate_key,Request,Response};usetokio_tungstenite::tungstenite::http::{request::BuilderasHttpReqBuilder,response::BuilderasHttpRespBuilder,ResponseasHttpResp,Uri,Version,};usetokio_tungstenite::{
client_async, connect_async,tungstenite::protocol::Message,MaybeTlsStream,WebSocketStream,};asyncfncli_async()->Result<(WebSocketStream<TcpStream>,Response),WsError>{let req =HttpReqBuilder::new();let uri ="ws://127.0.0.1:9000/";let host ="127.0.0.1:9000";let stream =tokio::net::TcpStream::connect(host).await.unwrap();matchclient_async(
req.method("GET").header("Host", host).header("Connection","Upgrade").header("Upgrade","websocket").header("Sec-WebSocket-Version","13").header("Sec-WebSocket-Key",generate_key()).header("Key",generate_key()).header("MCookie","&xjwshenHZJLSDH").uri(uri).body(()).unwrap(),
stream,).await{Ok((ws_stream, resp))=>Ok((ws_stream, resp)),Err(e)=>Err(WsError::Io(std::io::Error::new(std::io::ErrorKind::Other,
e.to_string(),))),}}asyncfnurl_async()->Result<(WebSocketStream<MaybeTlsStream<TcpStream>>,Response),WsError>{let url =url::Url::parse("ws://127.0.0.1:9000/").unwrap();matchconnect_async(url).await{Ok((ws_stream, resp))=>Ok((ws_stream, resp)),Err(e)=>Err(WsError::Io(std::io::Error::new(std::io::ErrorKind::Other,
e.to_string(),))),}}#[tokio::main]asyncfnmain(){let(ws_stream, resp)=url_async().await.unwrap();println!("WebSocket handshake has been successfully completed");println!("STATUS:{:?}", resp.status());ifVersion::HTTP_09== resp.version(){println!("Version: HTTP_09");}elseifVersion::HTTP_10== resp.version(){println!("Version: HTTP_10");}elseifVersion::HTTP_11== resp.version(){println!("Version: HTTP_11");}let(stdin_tx, stdin_rx)=futures_channel::mpsc::unbounded();tokio::spawn(read_stdin(stdin_tx));let(write, read)= ws_stream.split();let stdin_to_ws = stdin_rx.map(Ok).forward(write);let ws_to_stdout ={
read.for_each(|message|async{let data = message.unwrap().into_data();tokio::io::stdout().write_all(&data).await.unwrap();})};pin_mut!(stdin_to_ws, ws_to_stdout);future::select(stdin_to_ws, ws_to_stdout).await;}// Our helper method which will read data from stdin and send it along the// sender provided.asyncfnread_stdin(tx:futures_channel::mpsc::UnboundedSender<Message>){letmut stdin =tokio::io::stdin();loop{letmut buf =vec![0;1024];let n =match stdin.read(&mut buf).await{Err(_)|Ok(0)=>break,Ok(n)=> n,};
buf.truncate(n);
tx.unbounded_send(Message::binary(buf)).unwrap();}}
2. 服务端案例
usestd::{collections::HashMap,
env,io::ErrorasIoError,net::SocketAddr,sync::{Arc,Mutex},};usefutures_channel::mpsc::{unbounded,UnboundedSender};usefutures_util::{future, pin_mut,stream::TryStreamExt,StreamExt};usetokio::net::{TcpListener,TcpStream};usetokio_tungstenite::tungstenite::protocol::Message;typeTx=UnboundedSender<Message>;typePeerMap=Arc<Mutex<HashMap<SocketAddr,Tx>>>;asyncfnhandle_connection(peer_map:PeerMap, raw_stream:TcpStream,
addr:SocketAddr){println!("Incoming TCP connection from: {}", addr);letmut ws_stream =tokio_tungstenite::accept_async(raw_stream).await.expect("Error during the websocket handshake occurred");println!("WebSocket connection established: {}", addr);// Insert the write part of this peer to the peer map.let(tx, rx)=unbounded();
peer_map.lock().unwrap().insert(addr, tx);let(outgoing, incoming)= ws_stream.split();let broadcast_incoming = incoming.try_for_each(|msg|{println!("Received a message from {}: {}",
addr,
msg.to_text().unwrap());let peers = peer_map.lock().unwrap();// We want to broadcast the message to everyone except ourselves.let broadcast_recipients = peers
.iter().filter(|(peer_addr, _)| peer_addr !=&&addr).map(|(_, ws_sink)| ws_sink);for recp in broadcast_recipients {
recp.unbounded_send(msg.clone()).unwrap();}future::ok(())});let receive_from_others = rx.map(Ok).forward(outgoing);pin_mut!(broadcast_incoming, receive_from_others);future::select(broadcast_incoming, receive_from_others).await;println!("{} disconnected",&addr);
peer_map.lock().unwrap().remove(&addr);}#[tokio::main]asyncfnmain()->Result<(),IoError>{let addr =env::args().nth(1).unwrap_or_else(||"127.0.0.1:9000".to_string());let state =PeerMap::new(Mutex::new(HashMap::new()));// Create the event loop and TCP listener we'll accept connections on.let try_socket =TcpListener::bind(&addr).await;let listener = try_socket.expect("Failed to bind");println!("Listening on: {}", addr);// Let's spawn the handling of each connection in a separate task.whileletOk((stream, addr))= listener.accept().await{tokio::spawn(handle_connection(state.clone(), stream, addr));}Ok(())}