ひとりアドベントカレンダー2015 第24日目 〜 PHPer でもソケットプログラミングしてみたい その3(select()で多重化するぞ)

  • このエントリーをはてなブックマークに追加
  • Pocket

24日目!!

クリスマスイブでもお構いなしに書き続けます!(かなしみ)

今日はエコーサーバーの多重化をきのうとは違った方法でやってみます。マルチスレッドは断念したので、3つあげたうちの一つめ、「シングルプロセス・シングルスレッドで select() や poll() を使う」というやつですね。きのうやったのはマルチプロセスで接続しているただ一つのソケットが read() で読めるようになるまでブロックする、というやつでしたが、select() は複数の接続中のソケットの状態が変化した時(読めるようになった、新しく接続が来た、などのイベントが発生したとき)に関数がリターンするというものです。ではコードを見ていきましょう。

socket_select()

PHP には poll() や epoll() といったものに対応する高機能な API がないようなので、最も基本的な select() に対応する socket_select() という関数を使います。公式のマニュアルに載っている例に沿って、またまたエコーサーバーを書きます。

main() 関数

main() 関数は昨日と全く同じです。デーモン化して待ち受けソケットを開いて接続を待ち受ける accept ループに入ります:

 accept_loop()

accept ループの中では、接続中のソケットを管理する変数を用意して、socket_select() を以下のように使います:

 ソケットの状態が変化すると socket_select()  関数が変化のあったソケットの個数をリターンします。そこで接続中のソケットを順番に見ていってどれが変化したのかを探していきます。今の場合、

  1. 新しい接続が待ち受けソケットに来た
  2. すでに接続しているソケットにメッセージが来た
  3. すでに接続しているソケットが切断された

というようなパターンがあるので、それをひとつひとつ調べていきます。変化があったソケットを見つけたら、接続受け入れやメッセージの受信などそれぞれのイベントに合った処理を行います。select() を使うパターンだとマルチプロセスの場合に比べて、この accept ループの処理がやや複雑になりますね。

まとめ

select() を使ったサーバーの多重化について見ました。複数の接続をいっぺんに監視し、変化があった( = 処理ができるようになった)時点でリターンするのが socket_select() 関数ですね。このような性質を持つ関数のおかげでシングルプロセス・シングルスレッドでも多重化が可能だというわけです。このように、イベントを監視して、発生し次第入出力処理を行うのをノンブロッキング IO というみたいです。

  • このエントリーをはてなブックマークに追加
  • Pocket

SNSでもご購読できます。

コメントを残す

*