はじめに
本書を読むにあたり必要なものは以下の通り
- Windows以外のOS(WindowsではUNIXソケットの機能の一部は使用できない)
- コマンドライン
- ncコマンド
やり方はひとつじゃない(TIMTOWTDI)
- TIMTOWTDI = “There’s more than one way to do it”
- PHPでのソケットプログラミングには2つのやり方がある
ソケット拡張
- ソケット拡張はコンパイル時のデフォルトでは無効
- ソケット拡張で作成したソケットリソースはsocket_xxx関数からのみ利用可能
- UNIXのシステムコールに近い形式のAPI
- (本書の著者は)使用を推奨しない
ストリームソケット
- ストリーム拡張はPHP 5以降ではデフォルトで有効
- PHP 5以降では、ストリーム(Stream)APIがソケットを扱える
- ストリームAPIで作成したソケットリソースはファイル系の関数で扱える
- ソケットの低レベルでの制御はできない
- 原則として、ストリームAPIを使用してソケットを扱うべき
エコーサーバの例
古典的なサーバプログラムの処理は以下のようになる:
- ソケットにbindする
- ソケットをlistenし、コネクションを待ち受ける
- コネクションをacceptする
- クライアントが送信したデータを受け取る
- レスポンスを返す
- コネクションを切断するか、クライアントが切断するまで待つ
- 3に戻る
実装
<?php
// echo.php
// 本書のサンプルコードを一部修正している
$server = @stream_socket_server('tcp://0.0.0.0:1337', $errno, $errstr);
if (false === $server) {
fwrite(STDERR, "Error: $errno: $errstr\n");
exit(1);
}
$timeout = -1; // タイムアウトしないようにする
$readLength = 4096;
for (;;) {
$conn = @stream_socket_accept($server, $timeout, $peer);
if ($conn) {
while ($buf = fread($conn, $readLength)) {
fwrite($conn, $buf);
}
fclose($conn);
}
}
stream_socket_server
は、ステップ1と2を実行するfor (;;)
で無限ループを作り、内部でstream_socket_accept
でコネクションを待ち受ける(ステップ3)fread
でデータを読み取り(ステップ4)fwrite
でデータ書き込み(ステップ5)fclose
でソケットを閉じる(ステップ6)
サーバの実行
php echo.php
で起動できる- 初回起動時にはポート開放が必要になる
- クライアント(netcat)は
nc 127.0.0.1 1337
で接続できる