Cowboy框架websocket_send函数参数错误问题排查求助
问题分析与解决方案
核心错误点
- 错误保存连接标识:你在
init中将Req保存为socket,但Req只是HTTP升级请求的上下文,并非websocket连接的有效状态载体,正确的状态应该是Cowboy websocket handler维护的#state{}记录。 - 参数顺序与类型错误:从你提供的
websocket_send实现的spec可以看到,函数定义是websocket_send(cow_ws:frame(), #state{}),即第一个参数是websocket帧(如{text, Msg}),第二个参数是handler的#state{}记录。但你调用时传反了参数,且第一个参数是无效的Reqmap,导致undef错误。 - 调用场景错误:
cowboy_websocket:websocket_send是websocket handler进程内部的函数,不能直接在外部进程通过传入"socket"调用,因为外部无法获取到包含传输信息的#state{}记录。
正确实现步骤
1. 维护连接的进程PID
首先需要在全局存储(比如ETS表)中记录每个websocket连接的进程PID,这是跨进程发送消息的基础:
% 初始化ETS表(在应用启动时执行) init_ets() -> ets:new(connected_clients, [named_table, public, set]). % websocket handler的init函数 init(Req, _Opts) -> ?LOG_INFO("New client"), % 记录当前websocket进程的PID Self = self(), ets:insert(connected_clients, {Self}), % 不需要保存Req到state,Cowboy会维护必要的连接状态 {cowboy_websocket, Req, #state{}}.
2. 在handler中处理消息发送指令
让websocket进程自己处理发送消息的请求,通过进程间消息传递触发:
% websocket handler的handle_info回调 handle_info({broadcast_msg, Msg}, State) -> % 正确调用websocket_send:帧在前,state在后 cowboy_websocket:websocket_send({text, Msg}, State), {ok, State}; handle_info(_OtherMsg, State) -> {ok, State}. % 处理连接断开,移除PID terminate(_Reason, _Req, _State) -> ets:delete(connected_clients, self()), ok.
3. 实现广播函数
遍历所有连接的PID,发送消息指令让每个进程自行调用websocket_send:
send_message_to_all_clients(Msg) -> % 获取所有连接的进程PID Pids = [Pid || {Pid} <- ets:tab2list(connected_clients)], % 给每个进程发送消息指令 lists:foreach(fun(Pid) -> Pid ! {broadcast_msg, Msg} end, Pids).
关于websocket_send的正确参数说明
从你提供的实现代码的spec定义:
-spec websocket_send(cow_ws:frame(), #state{}) -> ok | stop | {error, atom()}.
- 第一个参数:websocket帧,支持的格式包括
{text, binary()}、{binary(), binary()}、{close, integer(), binary()}等 - 第二个参数:websocket handler的
#state{}记录,必须是当前进程维护的state(包含socket和transport信息) - 调用场景:只能在websocket handler进程内部调用,不能跨进程直接传入外部获取的"socket"值
内容的提问来源于stack exchange,提问作者N-K
相关产品推荐
相关产品推荐

