サーチ…
TCPクライアントソケット
TCP(伝送制御プロトコル)を使用するソケットを作成すると、
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
ソケットが正常に作成されていることを確認します。 onSocketFailure
関数は、このトピックの「 ソケットエラーの処理」の例にあります。
if(!is_resource($socket)) onSocketFailure("Failed to create socket");
ソケットを指定されたアドレスに接続する
接続が失敗した場合、2行目は正常に失敗します。
socket_connect($socket, "chat.stackoverflow.com", 6667)
or onSocketFailure("Failed to connect to chat.stackoverflow.com:6667", $socket);
サーバーへのデータの送信
socket_write
関数はソケットを通してバイトを送信します。 PHPでは、バイト配列は文字列で表され、通常はエンコーディングを区別しません。
socket_write($socket, "NICK Alice\r\nUSER alice 0 * :Alice\r\n");
サーバーからのデータ受信
次のスニペットは、 socket_read
関数を使用してサーバーからデータを受信します。
PHP_NORMAL_READ
を3番目のパラメータとして渡すと\r
/ \n
バイトまで読み込まれ、このバイトが戻り値に含まれます。
反対に、 PHP_BINARY_READ
渡すと、必要な量のデータがストリームから読み込まれます。
先にsocket_set_nonblock
が呼び出され、 PHP_BINARY_READ
が使用された場合、 socket_read
は直ちにfalse
を返しfalse
。それ以外の場合、メソッドは、(2番目のパラメータの長さに達するか、または行末に到達する)十分なデータが受信されるか、ソケットが閉じられるまでブロックします。
この例では、IRCサーバーと推定されるデータを読み取ります。
while(true) {
// read a line from the socket
$line = socket_read($socket, 1024, PHP_NORMAL_READ);
if(substr($line, -1) === "\r") {
// read/skip one byte from the socket
// we assume that the next byte in the stream must be a \n.
// this is actually bad in practice; the script is vulnerable to unexpected values
socket_read($socket, 1, PHP_BINARY_READ);
}
$message = parseLine($line);
if($message->type === "QUIT") break;
}
ソケットを閉じる
ソケットを閉じると、ソケットとそれに関連するリソースが解放されます。
socket_close($socket);
TCPサーバーソケット
ソケットの作成
TCPを使用するソケットを作成します。これは、クライアントソケットの作成と同じです。
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
ソケットバインディング
指定されたネットワーク(パラメータ2)から特定のポート(パラメータ3)への接続をソケットにバインドします。
2番目のパラメータは通常"0.0.0.0"
、すべてのネットワークからの接続を受け付けます。それはまた、
socket_bind
のエラーの一般的な原因の1つは、指定されたアドレスがすでに別のプロセスにバインドされていることです。ソケットが解放されるように、通常は他のプロセスが強制終了され(通常、誤って重大なプロセスを停止するのを防ぐために手動で)
socket_bind($socket, "0.0.0.0", 6667) or onSocketFailure("Failed to bind to 0.0.0.0:6667");
リスニングするソケットを設定する
ソケットがsocket_listen
を使用して着信接続をsocket_listen
ます。 2番目のパラメータは、それらが受け入れられる前にキューイングを可能にする接続の最大数です。
socket_listen($socket, 5);
接続の処理
TCPサーバーは、実際には子接続を処理するサーバーです。 socket_accept
は新しい子接続を作成します。
$conn = socket_accept($socket);
socket_accept
からの接続のためのデータ転送は、 TCPクライアントソケットのものと同じです。
この接続を閉じるときは、 socket_close($conn);
呼び出しsocket_close($conn);
直接。これは元のTCPサーバーソケットには影響しません。
サーバーを閉じる
一方、 socket_close($socket);
サーバーが使用されなくなったときに呼び出される必要があります。これによりTCPアドレスも解放され、他のプロセスがアドレスにバインドできるようになります。
ソケットエラーの処理
socket_last_error
は、ソケット拡張から最後のエラーのエラーIDを取得するために使用できます。
socket_strerror
は、IDを人間が読める文字列に変換するために使用できます。
function onSocketFailure(string $message, $socket = null) {
if(is_resource($socket)) {
$message .= ": " . socket_strerror(socket_last_error($socket));
}
die($message);
}
UDPサーバーソケット
UDP(ユーザデータグラムプロトコル)サーバは、TCPと異なり、ストリームベースではありません。これはパケットベースです。つまり、クライアントはサーバーに「パケット」と呼ばれる単位でデータを送信し、クライアントはそのアドレスでクライアントを識別します。 (同じクライアントからのデータがsocket_accept
によって作成された特定のリソースによって処理されるTCPとは異なり、)同じクライアントから送られた異なるパケットを関連付ける組み込み関数はありません。 UDPパケットが到着するたびに、新しいTCP接続が受け入れられて閉じられると考えられます。
UDPサーバーソケットの作成
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
ソケットにアドレスをバインドする
パラメータはTCPサーバと同じです。
socket_bind($socket, "0.0.0.0", 9000) or onSocketFailure("Failed to bind to 0.0.0.0:9000", $socket);
パケットを送信する
この行は、UDPパケットの$data
を$address
: $port
送り$port
。
socket_sendto($socket, $data, strlen($data), 0, $address, $port);
パケットを受信する
次のスニペットは、クライアントインデックス方式でUDPパケットを管理しようとします。
$clients = [];
while (true){
socket_recvfrom($socket, $buffer, 32768, 0, $ip, $port) === true
or onSocketFailure("Failed to receive packet", $socket);
$address = "$ip:$port";
if (!isset($clients[$address])) $clients[$address] = new Client();
$clients[$address]->handlePacket($buffer);
}
サーバーを閉じる
socket_close
は、UDPサーバーソケットリソースで使用できます。これによりUDPアドレスが解放され、他のプロセスがこのアドレスにバインドできるようになります。