Web サーバー上で HTML のレンダリングをしたり JSON を返したりなどの用途に使われることが多い PHP ですが、もちろんソケットやプロセスの操作などもできる汎用プログラミング言語なのでその辺りをいろいろ試してみたい。
ということで、まずは PHP で エコーサーバー を書いてみました。TCP で接続してきたクライアントが送信した文字列をそのまま返信する、というものです。
ストリームモジュール
今回は生のソケットをすこし抽象化した形で扱う「 ストリームモジュール 」を使ってみます。
ストリームモジュールは PHP の組込みモジュールでファイル、ネットワーク、データ圧縮などに関する共通の取り扱いを提供します。ソケットがファイルと同じように扱えます。
公式のマニュアルはこちら:http://php.net/manual/ja/book.stream.php
ストリームモジュールは PHP にあらかじめ組み込まれているので特別な設定をせずに使えるのも利点かと思います。生ソケットを扱うソケットサービスは pecl などを使って追加インストールが必要になります:http://php.net/manual/ja/book.sockets.php
エコーサーバー
サーバーのソースは以下のとおりです。
<?php
// サーバーソケットの作成
$socket = stream_socket_server('tcp://0.0.0.0:8000', $errno, $errstr);
if (!$socket) {
die("$errstr ($errno)\n");
}
// 接続待ちループ
while ($conn = @stream_socket_accept($socket, -1)) {
echo "client connected.\n";
// welcome メッセージを送信
$welcome = "welcome to simple php echo server!\n";
fwrite($conn, $welcome, strlen($welcome));
// 送受信ループ
while ($read = fread($conn, 4096)) {
echo "message receive: $read";
// エコーバックする
fwrite($conn, $read, strlen($read));
}
if(!fclose($conn)) {
echo "fclose failed.\n";
} else {
echo "connection closed.\n";
}
}
短いソースで、コメントのとおりなのであまり説明することもありませんが、ソケットサービスであれば socket_create()
や socket_accept()
を使うところで stream_socket_server()
や stream_socket_accept()
などの関数を使っています。また、送受信やソケットのクローズに fread()
, fwrite()
, fclose()
などファイルを操作するのと同じ関数を使っています。生のソケットが抽象化されて、読み書きできるファイル(ストリーム!)のように見えているわけですね。
動作確認
サーバーの起動
$ php streamserver.php
で起動します。
クライアントの接続
クライアントとして telnet を使ってみます:
$ telnet 192.168.33.10 8000
Trying 192.168.33.10...
Connected to 192.168.33.10.
Escape character is '^]'.
welcome to simple php echo server! <-- welcome メッセージ
test1 <-- 入力
test1 <-- 返答
test2 <-- 入力
test2 <-- 返答
このように、サーバーからのエコーバックが確認できました。