使用Actix构建WebSocket客户端 如何保留连接句柄向服务端发消息
解决方案
你只需要把WebSocket连接的写端句柄存储在RosClient结构体中,后续就可以在消息处理器中直接调用发送接口,具体修改步骤如下:
- 新增依赖导入,修改
RosClient结构体,预留写端存储字段
use actix::MessageHandler; use actix_codec::Framed; use awc::ws::Message; use futures::sink::SplitSink; use futures::SinkExt; pub struct RosClient { pub address: String, // 存储WebSocket写端 pub ws_sink: Option<SplitSink<Framed<BoxedSocket, Codec>, Message>>, pub hb: Instant, } impl RosClient { pub fn new(address: &str) -> Self { Self { address: address.to_string(), ws_sink: None, hb: Instant::now(), } } }
- 连接成功时存储写端句柄
修改started方法中连接成功的回调逻辑,拆分后把写端存入结构体:
ws.connect() .into_actor(self) .map(|res, act, ctx| match res { Ok((client_response, frame)) => { info!("Response: {:?}", client_response); let (r, w) = frame.split(); // 存储写端 act.ws_sink = Some(w); let _ = ctx.add_stream(r); } Err(err) => { info!("Websocket Client Actor failed to connect: {:?}", err); ctx.stop(); } }) .wait(ctx);
- 实现消息处理器,对外提供发送能力
你可以自定义一个消息类型,后续通过actor地址发送该类型消息即可触发WebSocket数据发送:
// 自定义要发送的消息类型 #[derive(Message)] #[rtype(result = "()")] pub struct SendWsMessage(pub String); impl MessageHandler<SendWsMessage> for RosClient { type Result = (); fn handle(&mut self, msg: SendWsMessage, ctx: &mut Self::Context) -> Self::Result { if let Some(sink) = &mut self.ws_sink { // 按需求构造消息发送 let send_fut = sink.send(Message::Text(msg.0)) .into_actor(self) .map(|res, _, ctx| { if let Err(e) = res { info!("发送消息失败: {}", e); ctx.stop(); } }); ctx.spawn(send_fut); } } }
后续调用时,只要拿到RosClient的actor地址,执行addr.send(SendWsMessage("待发送内容".to_string()))即可完成服务端消息推送。
内容的提问来源于stack exchange,提问作者Fabrex
相关产品推荐
相关产品推荐

