2012-10-15 51 views
9

現在のluaソケットの実装では、定期的にコールバックするタイマーをインストールする必要があるので、何も受信していないかどうかを調べるために非ブロッキングAPIをチェックします。Luaソケット - 非同期イベント

これはすべてうまくいきますが、UDPの場合、送信者に多くの情報が送信されると、データが失われる危険があります。別のデバイスがUDP経由で2MBの写真を送信し、100msecごとにソケットの受信をチェックするとします。 2MBpsでは、呼び出しが基になるTCPスタックを照会する前に、基礎となるシステムが200Kビットを格納する必要があります。

ここで行うポーリングではなく、特定のソケットでデータを受信したときにイベントを発生させる方法はありますか?

答えて

13

local rset = {socket} 
... later 
...select(rset, nil, 0) 

:それはオプションではありません場合は、あなたの代わりに一時的なものの静的なテーブルを読んで渡す必要はありませんこれらのリストのためのselect()代わりの{}nilを渡す考えますこの問題を処理するさまざまな方法です。どちらを選択するかは、どれくらいの仕事をしたいかによって決まります。 *

しかし、最初に、あなたがUDPかTCPを扱っているかどうかを明らかにしてください。 UDPソケットのための「基礎となるTCPスタック」はありません。また、UDPは、テキストや写真などの全データを送信するために使用する間違ったプロトコルです。それは信頼性の低いプロトコルなので、マネージソケットライブラリ(ENetなど)を使用している場合を除き、すべてのパケットを受信する保証はありません。

Lua51/LuaJIT + LuaSocket

ポーリングは唯一の方法です。

  • ブロッキング:時間引数なしでsocket.selectを呼び出して、ソケットが読み込めるのを待ちます。
  • ノンブロッキング:0というタイムアウト引数を使用してsocket.selectと呼び出し、読み込み中のソケットでsock:settimeout(0)を使用してください。

これらを繰り返し呼び出します。 プログラムの他の部分が遅すぎることなく実行を続けることができるように、ノンブロッキング版にcoroutine schedulerを使用することをお勧めします。

Lua51/LuaJIT + LuaSocket + Lua Lanes上記方法として

同じ(推奨)が、ソケットが別のレーン(別のスレッドで軽量のLUA状態)に存在するLua Laneslatest source)を用いました。これにより、ソケットからバッファにデータを即座に読み取ることができます。次に、lindaを使用して、処理のためにメインスレッドにデータを送信します。

これは、おそらくあなたの問題に対する最良の解決策です。

私はこの簡単な例を作成しました。利用可能なのはhereです。これはLuaのレーン3.4.0(GitHub repo)とパッチの当たっLuaSocket 2.0.2(sourcepatchblog post re' patch

あなたはそこから派生する場合は、間違いなく私のサンプルコードをリファクタリングすべきものの結果は、有望であるに依存しています。

LuaJIT + OS固有のソケット

あなたは少し自虐している場合は、最初からソケットライブラリを実装してみてください。 LuaJITFFI libraryは、これを純粋なLuaから可能にします。ルアレーンもこれに役立ちます。

Windowsの場合は、William Adam's blogをご覧ください。彼はLuaJITとWindows開発で非常に興味深い冒険をしています。 Linuxとそれ以外の場合は、CのチュートリアルやLuaSocketのソースを見て、それらをLuaJIT FFI操作に変換してください。

(APIがそれを必要とする場合LuaJITはcallbacksをサポートしていますが、signficantパフォーマンスコストのLUAからCへのポーリングに比べてあります)

LuaJIT + ENET

ENetは素晴らしいライブラリです。これは、TCPとUDPの完璧な組み合わせを提供します。必要に応じて信頼性があり、そうでなければ信頼性がありません。また、LuaSocketのように、オペレーティングシステム固有の詳細を抽象化します。 Lua APIを使用してバインドするか、LuaJITのFFIを介して直接アクセスすることができます(推奨)。

*プンは意図的ではありません。

3

ルアは本質的にシングルスレッドです。 「出来事」のようなものはありません。 Luaコードの実行を中断する方法はありません。だから、あなたはイベントのように見える何かをつくることができますが、利用可能なイベントをポーリングした関数を呼び出した場合は、これを取得するだけです。

一般に、このような低レベルの作業にLuaを使用しようとすると、間違ったツールが使用されています。この種のデータにアクセスするには、Cなどを使用していて、準備ができたらLuaに渡す必要があります。

+1

私はLuaが実際にコールバックを使用するシステムイベントを持つシングルスレッドシステムであることを認識しています。私はちょうどそれを見続ける代わりに利用可能なデータがあるときにコールバックを得ることを望んでいた。 – user4749

+0

コールバックを受け取るためにコールバックを行っていた人には、コントロールを転送する必要があります。だからあなたがそれをしたときはいつでも、データがそこにあるかどうかを調べるだけです。 –

+0

私は大きく反対します。 lua-evや別のイベントを使っても、ポーリングは行われません!Lua +の使用「Some Event Loop」は、非常に優れたパフォーマンスとメモリ占有量の少ない重要な作業のために、組み込み機器(node.jsが大きい)で生産性高く使用されています。状況によっては、これは完璧なマッチです。非常に低レベル(https://github.com/justincormack/ljsyscall)のOSで作業するのがとても簡単なモジュールがあります。 – lipp

1

利用可能な新しいデータのソケットを "ポーリング"するには、おそらく非ブロックselect()を使用しています。 Luasocketは、(私が知る限り)新しいデータがあるかどうかを確認するための他のインタフェースは提供していませんが、これを毎秒10回実行する際に時間がかかると懸念される場合は、あなたが必要とするソケットを1つだけチェックし、Luaテーブルの作成と投棄を避けます。代わりに、そこ

...select({socket}, {}, 0) 
+0

OK ..これは良いアイデアだとうまくいくかもしれません – user4749

5

すべてのIO多重化処理にはlua-ev https://github.com/brimworks/lua-evを使用します。 Lua(そしてそのfunction)に似合う魅力がとても使いやすいです。それはselect/poll/epollかkqueueベースのどちらかであり、とても良い動作もします。私の意見のLua + luasocketの+のLUA-EVで

local ev = require'ev' 
local loop = ev.Loop.default 
local udp_sock -- your udp socket instance 
udp_sock:settimeout(0) -- make non blocking 
local udp_receive_io = ev.IO.new(function(io,loop) 
     local chunk,err = udp_sock:receive(4096) 
     if chunk and not err then 
      -- process data 
     end 
    end,udp_sock:getfd(),ev.READ) 

udp_receive_io:start(loop) 
loop:loop() -- blocks forever 

は(組み込み機器/環境用)効率的かつ堅牢なネットワークアプリケーションを構築するためだけのドリームチームです。そこにはより強力なツールがあります!しかし、あなたのリソースが限られている場合、Luaは良い選択です!

+0

これはiPhone/AndroidとGiderosで使用できますか? (www.giderosmobile.com)私はiPhone/Androidのポートを見ていない。 – user4749

+0

申し訳ありませんが、gideros /コロナの世界で "ネイティブ" CバインディングでLuaモジュールを拡張できるかどうかはわかりません。 lua-ev(libevに基づいています)は "any" Unix用にコンパイルされます。 – lipp

関連する問題