PHPでTCPサーバを作ってみる

この記事はPHP Advent Calender 2012の2日目の記事になります、詳細は以下をどうぞ。

PHP Advent Calender 2012

フレームワークCMS的な記事が多いので、あまり参考例のないTIPSを書きたいと思います。

PHPでTCPサーバを立ててみる

PHPでTCPなサーバを作るとなると、socket関数やfsockopenなどを使った例を多く見かけます。
PHPというよりかはLinuxなネタになってしまいますが、ここではxinetdを使った例を書いてみたいと思います。

xinetdとは?

今回は、スーパーサーバーと呼ばれる xinetd の設定方法について説明していきます。スーパーサーバーとは、ポート監視用のデーモンプログラムで、あるポートに対してアクセスがあると、設定ファイル (/etc/xinetd.d/ 等) を元にポートに対応したサービス (ftp 等) を起動します。この際、ポートとサービスの関係は、/etc/services によって導かれます。

http://www.express.nec.co.jp/linux/distributions/knowledge/network/xinetd.html

ということで、xinetdとは定義した設定ファイルを元にサービスを起動してくれるデーモンということです。
これを使ってPHPでサーバを立ててみます。

まずはxinetdの設定ファイルを作成します。
xinetdがLinuxに入っていない場合にはyum install xinetdを行えばインストールできます。

/etc/xinetd.d/php-server

# サービス名を指定
service php-server
{
    # 設定の有効無効を指定します、noに設定すると有効になる
    disable = no

    # サービスの種類を指定、/etc/rpc, /etc/servicesに記述のないサービスを扱うにはUNLISTEDを指定
    type = UNLISTED

    # ソケットの種類を指定します、ここではTCPサーバを扱うのでstreamを指定
    socket_type = stream

    # 使用するプロトコルを指定、/etc/protocols内に記述されたプロトコルを指定
    protocol = tcp

    # サービスを実行するユーザーを指定
    user = root

    # マルチスレッドの有効無効を指定、noの場合シングルスレッド
    wait = no

    # サービスで利用するポート番号を指定
    port = 10000

    # ポートにアクセスされた際に起動するプログラムを指定
    server = /srv/server.php
}

上記の通り、xinetd設定自体は非常に簡単です。
portで指定したポート番号はiptablesで開放しておきましょう。

次に「server = 〜」で指定したプログラムを作成します。

/srv/server.php

#!/usr/bin/php -q
<?php
$stdin = fopen('php://stdin','r');

while (true) {
    $buffer = trim(fgets($stdin, 4096));

    if ('exit' === $buffer) {
        break;
    }

    echo $buffer . "\n";
}

プログラム自体は非常に簡単で、入力を受け取り単純に入力された値を表示するだけのプログラムです。
exitが入力された際にはプログラムが終了します。
作成したプログラムには実行権限をつけておきます。

chmod +x /srv/server.php

ここまで作成したらxinetdを再起動します。

/etc/init.d/xinetd restart

以上で完了です、では接続してみましょう。
下記の画像のように入力したものが応答で帰ってきます、最後にexitを入力し終了させています。

f:id:ryster:20121203070204j:plain

非常に簡単にPHPを使ったTCPサーバーが作成できました。
あとは実装次第で色々なサーバを作ることが出来るでしょう、勉強のためにハニーポットなんかを作ってみるのもいいかもしれません。