9

現在の lua ソケットの実装では、定期的にコールバックするタイマーをインストールして、非ブロッキング API をチェックインして何かを受信したかどうかを確認する必要があることがわかりました。

これはすべて問題ありませんが、UDP の場合、送信者が大量の情報を送信している場合、データを失うリスクがありますか? 別のデバイスが UDP 経由で 2MB の写真を送信し、100 ミリ秒ごとにソケットの受信を確認するとします。2MBps では、呼び出しが基礎となる TCP スタックを照会する前に、基礎となるシステムは 200K ビットを格納する必要があります。

今しなければならないポーリングの代わりに、特定のソケットでデータを受信したときにイベントを発生させる方法はありますか?

4

4 に答える 4

13

この問題を処理するにはさまざまな方法があります。どちらを選択するかは、実行したい作業の量によって異なります。*

ただし、最初に、UDP と TCP のどちらを扱っているかを (自分自身で) 明確にする必要があります。UDP ソケットの「基礎となる TCP スタック」はありません。また、UDP は、テキストや写真などのデータ全体を送信するために使用するプロトコルとしては不適切です。これは信頼性の低いプロトコルであるため、マネージ ソケット ライブラリ ( ENetなど) を使用していない限り、すべてのパケットを受信できる保証はありません。

Lua51/LuaJIT + LuaSocket

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

  • ブロッキング:socket.select時間引数なしで呼び出し、ソケットが読み取り可能になるまで待機します。
  • ノンブロッキング:socket.selectのタイムアウト引数を指定して呼び出し、読み取り元のソケット0で使用sock:settimeout(0)します。

次に、これらを繰り返し呼び出すだけです。ノンブロッキング バージョンではコルーチン スケジューラを使用することをお勧めします。これにより、プログラムの他の部分があまり遅延することなく実行を継続できるようになります。

Lua51/LuaJIT + LuaSocket + Lua レーン(推奨)

上記の方法と同じですが、Lua Lanes (最新ソース) を使用して作成された別のレーン (別のスレッドの軽量 Lua 状態) にソケットが存在します。これにより、データをソケットからバッファに即座に読み取ることができます。次に、lindaを使用してデータを処理のためにメイン スレッドに送信します。

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

これの簡単な例を作成しました。こちらから入手できます。これは、Lua Lanes 3.4.0 ( GitHub リポジトリ) と、パッチが適用された LuaSocket 2.0.2 (ソースパッチブログ投稿 re' patch )に依存しています。

結果は有望ですが、このサンプル コードから派生する場合は、間違いなくリファクタリングする必要があります。

LuaJIT + OS 固有のソケット

少しマゾヒスティックな人は、ソケット ライブラリをゼロから実装してみることができます。LuaJITFFI ライブラリは、純粋な Lua からこれを可能にします。Lua Lanes はこれにも役立ちます。

Windows については、 William Adam のブログを参照することをお勧めします。彼は、LuaJIT と Windows の開発に関して非常に興味深い冒険をしてきました。Linux などについては、C のチュートリアルや LuaSocket のソースを見て、LuaJIT FFI 操作に翻訳してください。

(LuaJIT は、API が必要とする場合、コールバックをサポートします。ただし、Lua から C へのポーリングと比較して、パフォーマンス コストが大幅に低下します。)

LuaJIT + ENet

ENetは優れたライブラリです。TCP と UDP の完璧な組み合わせを提供します。また、LuaSocket と同様に、オペレーティング システム固有の詳細を抽象化します。Lua API を使用してバインドするか、LuaJIT の FFI (推奨) 経由で直接アクセスできます。

意図しないしゃれ。

于 2012-10-15T07:18:58.543 に答える
5

私はすべてのIO多重化にlua-evhttps ://github.com/brimworks/lua-evを使用しています。functionチャームのようにLua(およびその)にフィットするのは非常に使いやすいです。これは、select / poll / epollまたはkqueueベースのいずれかであり、非常に優れたパフォーマンスを発揮します。

 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 + luasocket + lua-evは、効率的で堅牢なネットワークアプリケーション(組み込みデバイス/環境向け)を構築するための単なる夢のチームです。そこにはもっと強力なツールがあります!ただし、リソースが限られている場合は、Luaが適しています。

于 2012-10-19T08:07:13.827 に答える
2

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

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

于 2012-10-15T04:50:07.017 に答える
1

select()おそらく、利用可能な新しいデータがないかソケットを「ポーリング」するためにノンブロッキングを使用しています。Luasocket は (私の知る限り) 利用可能な新しいデータがあるかどうかを確認するための他のインターフェイスを提供していませんが、これを 1 秒間に 10 回実行すると時間がかかりすぎることが懸念される場合は、簡略化されたバージョンを作成することを検討してください。必要なソケットを 1 つだけチェックし、Lua テーブルの作成と破棄を回避します。それができない場合は、読み取る必要のないリストの代わりにに渡すnilことを検討し、一時テーブルの代わりに静的テーブルを渡します。select(){}

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

それ以外の

...select({socket}, {}, 0)
于 2012-10-15T05:56:54.547 に答える