Lindaライブラリ入手方法Linda serverの本体と、通信プログラムの例です。 通信プログラム作成 の参考にして下さい。cvsでは、以下のプロジェクト名でチェックアウトしてください。 Game_project/Linda Lindaの解説LindaとはLindaとは、タプルと呼ばれるIDとDataがセットになったものを、各クライア ントがサーバに対して out,in,rd などのコマンドを用いて読み書きすることによって通信を行うシステムです。 サーバーに蓄えられたデータへのアクセスは、 APIにタプルのIDを指定することによって行います。 #ref(): File not found: "linda.jpeg" at page "Linda" サーバ (ldserv.c)Lindaサーバのソースはldserv.cのみです。 クライアントAPI (lindaapi.c,lindaapi.h)タプル送受信のAPI(out,in,rdなど)を用いると、タプルはCOMMANDキューに溜められていき、プログラマが指定したタイミングで(psx_sync_n()実行時)、 一気にサーバに送信されます。つまりAPIを実行した段階ですぐに通信が 始まるわけではありません。 また、サーバからのタプルの受信も psx_sync_n() を実行したときに行い ます。受信したタプルは REPLYキュー に蓄えられ、psx_reply() で取り出します。 また、コールバックを用いて受信したときのアクションを登録することができます。 LindaのAPI
マクロLindaではTUPLEのヘッダ情報やデータ部分へアクセスするためのオフ セットと して以下のマクロを用意しています。 #define LINDA_MODE_OFFSET 0 #define LINDA_ID_OFFSET 1 #define LINDA_SEQ_OFFSET 3 #define LINDA_DATA_LENGTH_OFFSET 7 #define LINDA_HEADER_SIZE 12 これらはpsx_reply()で得たTUPLE(unsigned char のポインタ)のデータ部分 やヘッダ部分などを取得するときなどに用いられます。データ取得は プログ ラミングの流れで示します。 以下はpsx_reply()で得たTUPLE (tuple) のヘッ ダ部分を表示しているところです。 printf("MODE: %c\n",*(char*)(tuple+LINDA_MODE_OFFSET)); printf("ID: %d\n",*(short*)(tuple+LINDA_ID_OFFSET)); printf("SEQ: %d\n",*(int*)(tuple+LINDA_SEQ_OFFSET)); printf("DATA_LENGTH: %d\n",*(int*)(tuple+LINDA_DATA_LENGTH_OFFSET); ヘッダ情報は異なるエンディアンのCPU上でも対応するように整数の上位 ビッ トが配列の前の方にくるように揃えているので、予想した結果がでない かも しれません。ヘッダ部分の情報を得るにはpsx_getから始まる関数群を 使って 下さい。 プログラミングの流れまずは、プログラム初頭でstart_linda(hostname)を 実行して通信を行えるようにしておきます。 データを送信する場合
psx_outした時点では、単にキューへためられるだけで、 まだ通信は開始され ていません。 Lindaでは、char型かunsigned char型でしかデータを送ること ができません。 ただ、符号の問題を避けるため、char型ではなくunsigned char型を使いましょう。 少し詳しく言うと、psx_outは、与えられたポインタ のアドレスから、 1byteずつ順番に指定されたbyte数サーバーへ送信するとい う事です。 そこで、送りたいデータを格納している変数や構造体等が unsigned char型以外である場合、unsigned char型に タイプキャストしてや る必要があります。
この時、今までキューにためこまれたLindaのコマンドが、一気に実行されま す。 PlayStation? 2では、描画に関する演算はEmotion Engineの中で行われ ますが、実際の描画処理はGraphics Synthesizerで行われます。 つまり、描 画処理が行われている間、Emotion Engineには余裕ができます。 その時間を 使用して、通信を行うようにプログラミングしましょう。 (そのタイミングを 考慮して、psx_sync_nを実行しましょう)
通信を行う際、待ち合わせを行い、 データを受け取るまでゲームが止まって しまってはいけないので、 Lindaサーバーでは非同期通信を採用しています。 もし送信するデータを確実に相手に受け取って欲しい場合は、 相手から受け 取りのサイン(Ack)を受け取るようにするとよいでしょう。 例えば、送信側が psx_out() したデータを受信側が psx_in() で受け取 るよ うな通信を何回か繰りかえす場合を考えます。 このとき、通信相手がデータ を受け取った事を確認してから、 次のデータを送らなければなりません。 何 も考えずにどんどんpsx_outを行うと、タプルにまだデータが残っているので 新たなデータを書き込めず、キューにためこまれていきます。 そして、処理 がどんどん重くなってしまい、ゲーム自体もスピードが落ち、 キューがいっ ぱいになると、失敗するようになってしまいます。 そこで、その確認を取る ために、相手がデータを受け取ったという サイン(Ack)を、psx_inやpsx_rdを 使用して受け取ります。 Ackを受け取ってから、次のデータをpsx_outして下 さい。 ただし、プログラムが通信を行う部分でループして、 Ackを得るまで プログラムが止まるというわけではありません! メインの処理は、Ackを待つ 間も動き続ける書き方をして下さい!! そのために、psx_replyはif文で括ら れているのです。
データを受信する場合(callbackを使わない)
sequence番号とは、実行したコマンドに与えられる、 整理券の番号みたいな ものです。
データが来ていれば、それに対する処理を実行する。 来ていなければ、その ままプログラムの処理を進める。
データを任意の変数・構造体に展開する際、 データを送信するために 1byte ずつに分解されたデータ を、元の形に組み立てる必要があります。 psx_reply() で得たポインタ(仮に reply とします)の 指す先にはTUPLEのヘッ ダが含まれているので、 実データ(RealData?型とします)は (RealData *)(reply + LINDA_HEADER_SIZE) でアクセスできます。LINDA_HEADER_SIZE は 12 に置き換えられます。 memcpyを使用すると便利です。
通信で受け取ったデータは、psx_sync_n()の実行時にmallocされ、 メモリの 何処かへ蓄えられています。 それを放っておくと、データを受け取る度に、 そのデータ分だけ メモリを消費し続ける事になり、メモリ不足の原因となり ます。 よってデータを任意の変数・構造体に展開し終えた後に、 psx_reply で得たポインタをfreeして下さい。 勿論、データを任意の変数・構造体に格 納せずに、 psx_reply で得たポインタをそのまま使用しても構いません。
必要ならば データを受け取ったというサインを送信者へ送ります。 送信者が Ack だと分かるものなら、送るデータは何でも構いません。
データを受信する場合(callbackを使う)
callbackを使う場合は引き数にcallbackする関数と、 その関数の引き数にす る構造体を指定します。この callbackする関数の型は void function(char * tuple, void * obj); となっています。objは任意の構造体のポインタです。 この関数の内部の処理 は自由に作ってもいいのですが、 REPLYキューに蓄えられないので、 psx_reply()を実行しても 答えは返ってきません。 引き数の tuple は psx_sync_n() 内で malloc されているので、 いらなくなったら free() して ください。 データを受け取ったという情報をAckとして 送る場合などは、この function() 内で送信する必要があります。 この callback 関数を上手く書くと、psx_reply() がいらない ようなプログ ラムも可能です。 Linda's TipsLindaでのプログラミングの際、以下のことに留意しておいて下さい。
|