使用Crystal/Kemal侦听UDP数据包
我一直在尝试使用Crystal和Kemal创建一个非阻塞服务器,该服务器将(a)侦听发送给它的UDP消息流,然后(b)将该消息转发到WebSocket,发送到任何启动ws连接的浏览器 到目前为止,我能做的最好的事情是:使用Crystal/Kemal侦听UDP数据包,udp,crystal-lang,kemal,Udp,Crystal Lang,Kemal,我一直在尝试使用Crystal和Kemal创建一个非阻塞服务器,该服务器将(a)侦听发送给它的UDP消息流,然后(b)将该消息转发到WebSocket,发送到任何启动ws连接的浏览器 到目前为止,我能做的最好的事情是: require "kemal" require "socket" server = UDPSocket.new server.bind "localhost", 1234 puts "Started..." ws "/" do |socket| udp_workin
require "kemal"
require "socket"
server = UDPSocket.new
server.bind "localhost", 1234
puts "Started..."
ws "/" do |socket|
udp_working = true
while udp_working
message, client_addr = server.receive
socket.send message
end
socket.on_close do
puts "Goodbye..."
udp_working = false
end
end
这一切似乎有点不雅观,事实上,并不像预期的那样有效,因为:
- 在启动的Crystal服务器和连接到Crystal服务器的第一个web浏览器之间发送的所有UDP数据包都被缓存,并在一个巨大的积压中发送
- 未正确处理从WebSocket断开的浏览器,即未触发socket.on_close,循环将继续,直到我终止Crystal服务器
谢谢 您的方法有几个问题: 首先,
socket.on\u close
无法工作,因为从未到达此行。只要udp\u working==true,while循环就会运行,并且它只会在on\u close
钩子中设置为false
如果您不想让UDP数据报堆积起来,您需要从一开始就接收它们,如果没有连接websocket,则需要执行任何您想要的操作(可能是处置?)。UDPServer
的消息上没有,但是receive
已经是非阻塞的。因此,您可以在循环中运行它(在它自己的光纤中),并在该方法返回时执行操作。详情见:;还有一个使用TCPSocket的示例,但UDP在这方面应该类似。Crystal为您处理非阻塞,您需要在单独的光纤中编写阻塞代码,并使用通道进行通信。Crystal将在后台使用非阻塞代码和select()调用
此外,您还需要一个框架或一些自己的代码来将收到的消息复制到每个侦听websocket。这通常称为发布/订阅或发布/订阅
i、 e.未触发插座on_关闭
您需要先运行socket.on\u close
,否则事件处理程序将不会被添加,因此直到循环结束后才会运行,但是循环实际上是无限的。此外,如果在检查udp\u工作
var和调用\send
var之间关闭套接字,则socket.send message
很可能由于套接字关闭而出错
ws "/" do |socket|
udp_working = true
while udp_working
message, client_addr = server.receive
socket.send message
end
socket.on_close do
puts "Goodbye..."
udp_working = false
end
end