6

私は、ソケットを使用して外の世界と通信する小さな Lua アプリ (Lua for Windows の下で、それが重要な場合) に取り組んでいます。(ルアソケット)

そして、いくつかのリクエストを並行して行おうとしています。だから私はLuaLanesが行くべき道だと思った. (もちろん、より良い解決策があれば代替案を受け入れますが、このためにコルーチンを処理したくないでしょう。)

このようなもの:

server = assert (socket.bind ('*', 1234))
client = server : accept ()
-- set id to some unique value
allClients [id] = client
theLane = lanes.gen ("", laneTest) ( id )
print (theLane [1])

関数laneTestは次のように定義されます。

function laneTest (id)
    local client = allClients [id]
    print ('peer: ', client:getpeername())
end

私の問題は、laneTest関数内でレーンとして実行すると、次のような素敵なエラー メッセージが表示されることです。

ローカルの「クライアント」(ユーザーデータ値) のインデックス作成を試みます

(ラインよりclient:getpeername()

だから..ここで何が起こっているのかわかりませんか? レーンはソケットと互換性がありませんか、それとも何か非常に間違っていますか?

Lua for Windows に同梱されているレーンのバージョンは古いもの ( luaforwindows ) であり、ソケットでは動作しない可能性があると思いますが、最新バージョンは可能でしょうか? (レーン 2.0.4 vs 最近の 3.xx)

持っている Lanes のバージョンを更新する方法がよくわかりません。それが私が向かっている可能性のある場所であるか、または私が間違ったことをしたことがより明らかな何かがある場合は、アドバイスをいただければ幸いです。

編集:先に進み、luarocksを介してレーンをインストールしましたが、ロックとしてインストールされたレーン3.1.6-1を使用して同じ問題を抱えています。

編集2 :これを試しました(それでも失敗しました):

require ('socket')
require ('lanes')
local allClients = {}

function theLane (id)
    print ('the id:', id) -- correctly prints out the id passed to the function
    local SOCKET = require ('socket')
    local client = allClients [id]
    print ('peer:', client:getpeername())
    client : close ()
end

local server = assert (SOCKET.bind ('*', 1234))
local ip, port = server:getsockname ()
local laneFunc = lanes.gen('', theLane)
local client = server:accept ()
allClients [1] = client
local x = laneFunc (1)
print (x[1])
  1. これは主張に失敗します:attempt to call global 'require' (a nil value)
  2. 関数内の行を削除してrequire ('socket')再試行しても、次のように言って失敗します。attempt to index local 'client' (a userdata value)

明らかなことを見逃してしまったことを前もってお詫びしますが... どうすればソケットをレーンで動作させることができますか?

編集3:

さて、私は将来の参考のためにこれを編集しています:)

私が知る限り、luasocket にパッチを当てずにレーンをソケットで使用する方法はありません。詳細については、こちらのディスカッションを参照してください。要するに(Decoの回答で説明されているように):レーンはユーザーデータでは機能しません。luasocket は、ソケット/ソケット情報にアクセスする他の方法を提供しません。

私は luasocket にパッチを当てたいとは思っていません。

皆さんありがとう!

4

2 に答える 2

5

Lua Lanesは、レーンごとにまったく新しい(ただし最小限の)Lua状態を作成します。渡されたアップバリューまたは引数はすべてコピーされ、参照されません。これは、allClientsテーブルがそれに含まれるソケットとともにコピーされていることを意味します。

ソケットがuserdataであるため、エラーが発生しています。LuaLanesは、Cモジュールからのアドバイスなしにコピーする方法を知りません。残念ながら、LuaSocketはそのようなアドバイスを提供していません。(これを回避する方法はいくつかありますが、注意が必要です。LuaSocketはスレッドセーフではなく、同期のバグを追跡するのは非常に困難です。)

問題は解決しませんが、スポーンされたレーンにLuaSocketが必要であることに注意してください。デフォルトではコピーされません。

ソリューション!

これらは簡単なものから難しいものの順に並べられています(そしてほとんどの場合、ここにある他の回答から転記されています)。

シングルスレッドポーリング

LuaSocketでポーリング関数を繰り返し呼び出します。

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

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

(この解決策を選択する場合は、Paulの回答を確認することをお勧めします。)

デュアルスレッドポーリング

メインスレッドはソケットをまったく処理しません。代わりに、LuaSocketを必要とする別のレーンを生成し、すべてのクライアントを処理し、lindaを介してメインスレッドと通信します。

これはおそらくあなたにとって最も実行可能なオプションです。

マルチスレッドポーリング

上記と同じですが、各スレッドがすべてのクライアントのサブセットを処理する点が異なります(1対1は可能ですが、収穫逓減は大量のクライアントで発生します)。

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

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

LuaJIT + ENet

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

于 2012-11-04T20:30:50.350 に答える
5

プログラミング Lua には、非プリエンプティブ マルチスレッド(コルーチンを使用) の例があり、おそらくほとんど直接使用できます。私の意見では、コルーチンはあなたのユースケースにとってより良い解決策になるでしょう。

「TCP/IP サーバーで使用できるコルーチンに基づくディスパッチャ」と自称するcopas ライブラリもありますが、実際には非同期でリクエストを送信するためにも使用できます (addthreadstep呼び出しの組み合わせを使用)。

于 2012-11-04T22:18:27.203 に答える