現在、プログラムで luarpc を使用してプロセス間通信を行っています。問題は、クラスインスタンスをユーザーデータとして保存する tolua++ バインディングが原因で、これらの関数を使用できないため、luarpc がユーザーデータを処理できないことです。私の質問は、ユーザーデータが常にポインター (4 バイト) のみであり、呼び出しおよびインデックス作成操作用にメタテーブルが添付されていることがわかっている場合、ユーザーデータを送信できるかどうか (およびその方法) です。
2 に答える
できません。
ユーザーデータがポインターかオブジェクトかは問題ではありません。それらを介して任意に RPC できない理由は、データがLuaに保存されていないためです。そのため、LuaRPC は正しく送信できません。
アドレス空間へのポインターは、他のプロセスにとってはまったく価値がありません。それが別のマシンで実行されている場合はなおさらです。RPC を機能させるには、実際にデータ自体を送信する必要があります。LuaRPC はこの送信を行うことができますが、LuaRPC が理解できるデータに対してのみです。そして、それが理解できる唯一のデータは Lua に保存されたデータです。
さて、私は今それを働かせました。私がしたことは、ユーザーデータの引数/戻り値に対して、実際のptr +メタテーブル名(typename)をクライアントに送信することです。次にクライアントは、型名を持つ新しいヘルパーを作成し、アクセスしたいフィールドを持つヘルパーを追加する __index メソッドでメタテーブルをアタッチします。次に、そのユーザーデータからフィールドを呼び出すか読み取ると、クライアントは型テーブルのフィールドを呼び出すためのデータとユーザーデータをサーバーに送信します。
読み取り変数:
lua_pushlightuserdata(L,msg.read<void*>());
#ifndef RPC_SERVER
luaL_getmetatable(L,"rpc.userdata");
int len = msg.read<int>();
char* s = new char[len];
msg.read((uint8*)s,len);
s[len] = '\0';
lua_pushlstring(L,s,len);
lua_setfield(L,-2,"__name");
lua_pushlightuserdata(L,TlsGetValue(transporttls));
lua_setfield(L,-2,"__transport");
lua_setmetatable(L,-2);
#endif
書き込み変数:
else
{
msg.append<RPCType>(RPC_USERDATA);
msg.append<void*>(lua_touserdata(L,idx));
#ifdef RPC_SERVER
lua_getmetatable(L,idx);
lua_rawget(L,LUA_REGISTRYINDEX);
const char* s = lua_tostring(L,-1);
int len = lua_strlen(L,-1);
msg.append<int>(len);
msg.append(s,len);
#endif
lua_settop(L,stack_at_start);
}
ユーザーデータのインデックス作成:
checkNumArgs(L,2);
ASSERT(lua_isuserdata(L,1) && isMetatableType(L,1,"rpc.userdata"));
if(lua_type(L,2) != LUA_TSTRING)
return luaL_error( L, "can't index a handle with a non-string" );
const char* s = lua_tostring(L,2);
if(strlen(s) > MAX_PATH - 1)
return luaL_error(L,"string to long");
int stack = lua_gettop(L);
lua_getmetatable(L,1);
lua_getfield(L,-1,"__name");
const char* name = lua_tostring(L,-1);
if(strlen(name) > MAX_PATH - 1)
return luaL_error(L,"string to long");
lua_pop(L,1); // remove name
lua_getfield(L,-1,"__transport");
Transport* t = reinterpret_cast<Transport*>(lua_touserdata(L,-1));
lua_pop(L,1);
Helper* h = Helper::create(L,t,name);
Helper::append(L,h,s);
return 1;
まあ、名前付きパイプとウィンドウで動作するように完全なrpcライブラリを多かれ少なかれ書き直しましたが、コードはそれを実装するのに十分な情報を誰にでも与えるべきだと思います。
これにより、次のようなコードが可能になります。
local remote = rpc.remoteobj:getinstance()
remote:dosmthn()
クライアントサイドで。現在、新しいフィールドを追加することはできませんが、今のところ必要なのはこれだけです:D