2017-10-18 3 views
4

CrystalとKemalを使用して非ブロッキングサーバーを作成しようとしました。これは、(a)UDPメッセージのストリームをリッスンし、(b)そのメッセージをws接続を開始したすべてのブラウザにWebSocketに送信します。Crystal/Kemalを使用してUDPパケットをリッスンする

はこれまでのところ、私が管理することができる最高は次のとおりです。

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 

は、すべてが少し洗練ようだこれ、と確かに、期待通りに動作しない理由は次のとおりで送ら

  • すべてのUDPパケット開始されたCrystalサーバーとCrystalサーバーに接続する最初のWebブラウザーとの間のキャッシュがキャッシュされ、1つの大きなバックログで送信されます。 NDループは私がUDPパケットはむしろ継続的にポーリングするブロックサーバーよりも、受信された場合にのみ、コードを実行するために私を可能にするserver.on_messageタイプの処理を期待していたクリスタル・サーバ

を終了するまで継続します。 Crystal/Kemalを使ってこれを達成する別の方法がありますか?

ありがとうございます!

答えて

3

あなたのアプローチにはいくつかの問題があります。

まず、socket.on_closeこの行は到達しませんので、動作することはできませんが。 whileループはudp_working == trueまで実行され、on_closeフックではfalseにのみ設定されます。

UDPデータグラムが重なり合わないようにするには、WebSocketが接続されていない場合は、最初から受信し、必要な処理(?)を実行する必要があります。 UDPServerのフックはon_messageではありませんが、すでにreceiveは非ブロッキングです。だから、あなたはそれをループで(それ自身のファイバー内で)実行し、メソッドが戻るたびに動作することができます。詳細については、Crystal Concurrencyを参照してください。 TCPSocketを使用した例もありますが、UDPはこの点で似ているはずです。

3

クリスタルがあなたのために非ブロッキングを処理する場合は、別のファイバーにブロックコードを書き込み、チャネルを使用して通信したいと思うでしょう。 Crystalは非閉塞コードとselect()コールをバックグラウンドで使用します。

さらに、受信するすべてのWebソケットに受信したメッセージをコピーするには、フレームワークまたは独自のコードが必要です。これはしばしばパブリッシュ/サブスクライブまたはパブ/サブと呼ばれます。


...

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 

すなわちsocket.on_close、

をトリガされていないあなたは、まずsocket.on_closeを実行したい、そうでない場合はイベントハンドラは勝ちました追加されないループの後まで実行されませんが、そのためループは事実上無限になります。また、udp_working varと#send

への呼び出しの間でソケットが閉じられている場合、閉じたソケットのために socket.send messageがエラーになる可能性はわずかです
関連する問題