!!! リポジトリ,コンパイル,実行 まずはサンプルプログラムで動作を確認しましょう. 8< svn export https://wiki.cis.iwate-u.ac.jp/svn/csd/kimura/giochannel cd giochannel make >8 班長さんが,自分の端末でサーバを立ち上げます.ポート番号(1000以上の大きい数字)を忘れずに. 8< ./server 1234 >8 班員は,各自,自分の端末からクライアントを立ち上げます. 8< ./client 1234 サーバのIP >8 ここで,ポート番号は班長さんが入力した番号,「サーバのIP」は班長さんの端末のIPアドレスです.(班長さんが自分の端末でifconfig eth0を実行すれば確認できます) このクライアントは,複数同時に接続できます. 各クライアントは,サーバに対してメッセージ(エントリボックスに入力された文字列)を送り,サーバは,そのメッセージを受け取って('\n'が現れるまで受信して)ウィンドウ上に表示します.クライアントごとに,何かキーボードから打ち込んで試してみてください. !!! 概要説明 !! 通信相手 Cのプログラムからは,通信相手(のプロセス)がどう見えているか? * オープンされたファイル,として見えます.具体的にはファイル識別子(ただの整数)です. 相手へメッセージを送るには? * ファイル識別子に対して書き込みを行う(writeシステムコールする)と,相手にバイト列が送られます. 相手からのメッセージを読むには? * ファイル識別子から読む(この例ではg_io_channel_read_line)と,相手から送られたバイト列が届きます. メッセージが届いているか確かめる * g_io_add_watchを使うと,「ファイル識別子にデータが届いているかどうか」を調べることができます. ** 同時に複数の通信相手から送られてくるデータの到着も調べることができます. ** これにより,複数の相手に対する非同期的な通信が実現できます. !! サーバとクライアント socketには,サーバソケットとクライアントソケットが存在します. * 接続される方がサーバで, * 接続する方がクライアントです, !! ソケットの作成 '''サーバ側''' 6< [server.c|https://svn.cis.iwate-u.ac.jp/svn/csd/kimura/giochannel/server.c]のServerSetup()関数 socketシステムコール * ソケットを作成します. * エラーがなければ,ファイル識別子が返ってきます. bindシステムコール * ソケットには,sockaddr_in構造体でサーバ側のIPアドレスとポート番号を与えます. * ソケットを持ったプロセスと,IPアドレス/ポート番号をもったパケットが結び付きます. >9 '''クライアント側''' 6< [client.c|https://svn.cis.iwate-u.ac.jp/svn/csd/kimura/giochannel/client.c]のClientSetup()関数 socketシステムコール * サーバのIPアドレスとポート番号を指定して,クライアントソケットを作ります. * エラーがなければファイル識別子が返ってきます. * 実際に接続されるのはconnectを呼んでから,です.(socketだけでは接続されません) connectシステムコール * サーバに対して接続にいきます. >9 接続が完了すれば,socketシステムコールで得たファイル識別子に対してread/writeすることでサーバと通信できます. !! GIOChannel 例えばGTK+のようなイベント駆動型のプログラムでは,以下のようにプログラミングしなければなりません. * メイン・イベント・ループ中で,通信を行うためのファイル識別子を監視しつつ, * データが届いたら,対応するコールバックを呼ぶ これらは,'''GIOChannel''' を利用することで比較的簡単に実現できます. * GIOChannelは,通信専用というわけではなく,ファイルやパイプ,ソケット等を汎用的に利用するための仕組みです. '''サーバ側''' 6< ファイル識別子 s_fd から,IOチャネルを作成 8< GIOChannel *channel = g_io_channel_unix_new( s_fd ); >8 IOチャネルchannelに対し, データの入力があった場合(G_IO_IN)に関数read_callbackを(引数windowとして)呼び出すようにgtkのメインループに登録 8< g_io_add_watch(channel, G_IO_IN, read_callback, window); >8 コールバック関数read_callback中では,IOチャネルchannelからデータを読み込んでtextに格納するように 8< gchar *text = NULL; GError *error = NULL; g_io_channel_read_line( channel, &text, NULL, NULL, &error); >8 >9 '''クライアント側''' 6< IOチャネルchannelから,それに結びついているファイル識別子fdを抽出 8< int fd = g_io_channel_unix_get_fd( channel ); >8 ファイル識別子fdに対して,データを書き込み(以下の例では,msgが指すアドレスからlenバイト分を送る) 8< write( fd, msg, len ); >8 なお,このサンプルでは,一旦クライアントソケットからGIOChannelを作り,そのIOチャネルからまたソケットID(ファイル識別子)を取り出す,という回りくどい方法になっていますが,単なる説明のためですので気にしなくてOKです. >9