使用Websocket(Erlang,RabbitMQ,Websocket,Gen_bunny,Cowboy)向所有已连接用户广播消息

4
我正在尝试使用ERlang、Cowboy、Websocket和gen_bunny来集成websocket聊天功能。我已经成功地将它们单独运行起来了。
浏览器 -> Cowboy websocket chat(可用) Erlang和RabbitMQ AMQP(可用)
当我将它们结合在一起时,我能够从浏览器中获取消息并将其传递给RabbitMQ,然后再从RabbitMQ中获取它。我甚至可以回复发送消息的用户。但是,我想要将这条消息广播给所有连接的用户。
据我所知,Erlang会为每个用户创建一个单独的进程。那么,在从RabbitMQ中获取响应后,如何向所有连接的用户广播这条消息呢?
3个回答

2

正确的做法是Cowboy创建一个针对每个连接的进程来运行WebSocket处理程序代码。一种方法是让处理程序的websocket_init/3函数向“广播”进程注册自己(并在websocket_terminate/3中取消注册)。收到来自RabbitMQ的消息后,广播进程会将消息重复发送到所有已注册的WebSocket连接,这些连接可以使用websocket_info/3处理程序回调来接收它。

广播进程可以使用监视器来发现WebSocket处理程序何时终止,并自动将其从注册列表中删除。

处理程序的生命周期可能如下所示:

  1. 在Cowboy执行init/3(升级到WebSocket)请求后,将调用websocket_init/3。从这里开始,客户端处理程序向“广播”进程注册自身。
  2. 只要连接保持打开状态,处理程序就会通过websocket_info/3接收消息广播,并通过返回{reply, {text, Message}, State}将消息传递给客户端。
  3. 在终止时,处理程序会将自己从broadcast中注销。如果由于某种原因这不起作用,则broadcast会对所有订阅者进行监视,以便在其死亡时得到通知。

谢谢Martin,但我想避免循环,因为用户数量和消息交换将会很高。所以,如果我从RabbitMQ接收到消息,如果运行一个循环并发送消息给所有人,那么在未来会成为瓶颈。有没有其他框架可以完成广播任务?我已经看过YAWS和Cowboy... - Jack Daniel's
在Erlang中,消息传递非常快(通常是异步的)。除非你已经测量过,否则不要假设它会成为瓶颈。除非你使用某种复杂的类似于Map-Reduce的模式来并行广播,否则你将拥有一个依次向订阅者发送消息的循环。据我所知,这里没有银弹。 - Martin Törnwall
嗯...我曾使用Tsung进行基准测试,但结果并不太理想。尽管如此,我仍在考虑同时使用GProc和RabbitMQ。 - Jack Daniel's
@MartinTörnwall 在你的 #2 中,{reply, {text, Message} ... 将通过 WebSocket 发送,而不是消息 WebSocket 处理程序的 Ref? - quantumpotato

1

请看gproc项目: https://github.com/uwiger/gproc

它有一个发布/订阅模式,您可以用来构建您提到的聊天功能。

来自gproc的维基:

subscribe(EventType) ->
    %% Gproc notation: {p, l, Name} means {(p)roperty, (l)ocal, Name}
    gproc:reg({p, l, {?MODULE, EventType}}).

notify(EventType, Msg) -> 
    Key = {?MODULE, EventType},
    gproc:send({p, l, Key}, {self(), Key, Msg}). 

嗨,Edyardo,感谢您的回复。然而,在使用RabbitMQ之前,我尝试了Gproc。问题在于会有许多cowboy实例运行,并且从可扩展性的角度来看,我想使用消息队列。 - Jack Daniel's
嗯,我明白了。但是你有没有看到gproc支持本地和全局进程? - Eduardo
1
我想我会稍微改变架构,并结合使用GProc和RabbitMQ... - Jack Daniel's

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接