- ベストアンサー
ソケット通信でチャットプログラム(unix c言語)
c言語のソケット通信でチャットプログラムを作り中です 仕様:あるクライアントからメッセージがサーバに送信された時点でサーバは接続されたいる全てのクライアントにメッセージを送信する。 以下のようにクライアントからの接続(accept)がある度に、その返り値であるファイルディスクリプタにに対するreadと全クライアントに対するwriteの処理を行うchild関数をforkで起動します。これだとforkが起動した時点での全てのファイルディスクリプタ(接続されている全クライアント)の情報をchild関数に渡せますが、それ以降増え続けていくファイルディスクリプタの情報をchild関数に渡せないので、最初の方に接続したクライアントからのメッセージをそれ以降接続した他のクライアントに送信できないという状態です。 main() { socket() bind() listen() while(1){ accept() if(fork()==0) { child() } } } child() { select() if(FD_ISSET()) { read() write() } } ※forkやソケット通信に関してかなり初心者なので、ソースや説明分が意味不明かもしれませんがよろしくお願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
子プロセス自身がその他の子プロセスにデータを出すのではなくて、一度親プロセスにデータを渡し、親プロセスが全ての子プロセスにデータを配信するように作ればいいと思います。親プロセス側は子プロセスと pipe() で繋げばいいんじゃないでしょうか。(UNIX系OSの場合。でもその他のOSでもパイプってありますよね?) ちなみに accept() で接続がなかったときに停止させないようにする方法は fcntl() で O_NONBLOCK を設定すればできます。pipe() の入出力でデータがないときに停止させないようにするには select() を使えばできます。
その他の回答 (2)
- MASA_H
- ベストアンサー率42% (64/151)
fork()後にメインプロセスで取得されたディスクリプタに対して書き込みできないことはこちらでも確認しました。原因はfork()した時点でのファイルとディスクリプタの対応関係がコピーされるだけで共有はされなく、ファイルとディスクリプタの関係はプロセスごとに保持されるためのようです。 要するにファイルディスクリプタを異なるプロセス間で共有しても意味がないようです。 間違った解答を答えてしまい申し訳ないです。 よって解決策はnoboru2000さんがおっしゃっているようにするか、fork()でなくpthread_create()を使うことになるかと思います。pthread_create()であれば同一のプロセスなのでプロセス間通信など考えずにすみます。
お礼
わざわざ調べていただきありがとう御座います。でも共有メモリなど使ったこと無かったので勉強になりました。
- MASA_H
- ベストアンサー率42% (64/151)
fork()しているということは別のプロセスになっているのでプロセス間通信を考えなくてはいけません。 ソースの変更が少なそうな方法としては、ファイルディスクリプタの配列を共有メモリ上に作るといった方法です。書き込むのは親プロセスのみなので書き込み時に気をつければセマフォは別に使わなくてもいいでしょう。
補足
ありがとうございます グローバル変数として宣言しておいたファイルディスクリプタを共有メモリにしたところ、確かに親プロセスで新たにacceptのあったファイルディスクリプタも子プロセスでみれるようになったのですが、子プロセスでそのファイルディスクリプタにwriteしてみても、子プロセスが起動された時点にすでにあったファイルディスクリプタに対してしかwriteができませんでした。 原因となるのは何か分かりますでしょうか?
お礼
ありがとうございました、fcntl、pipeを使うことによって実現できました。初心者なのでpipe等の使い方も良く分からず調べていて時間がかかりました。