編集: *テスト ハーネスのバグにより、結果が誤って解釈されていました。期待どおりsocket_select()
に動作します。ソケットにデータの準備が整うまで実際に待機します。ただし、クライアントが接続を閉じた後に呼び出すと、準備ができていると報告されます。それはすべて私のせいであることが判明しましたが、他の誰かが.socket_select()
マルチスレッドの PHP アプリケーションがあり、スレッド間の通信にソケットを使用しています。通信はかなりうまくいきますが、データの準備ができていないソケットの不必要な読み取りを何度も行うことになります。おそらく、私が見逃しているソケットプログラミングに関する何かがあります。
PHP ドキュメントには、読み取りがブロックされないかどうかを確認するために、配列にリストされているソケットが監視さsocket_select()
れますread
。
これはまさに私が望んでいる動作です:socket_select()
子スレッドの 1 つが私に話しかけようとするまで待機するように呼び出します。しかし、それは、接続を受け入れた後、スレッドが最初に書き込むときにのみ機能します。その後socket_select()
、ソケットからすべてのデータを読み取った後でも、ソケットの準備ができていると永遠に言います。
そのソケットを「準備ができていない」とマークしてsocket_select()
、さらにデータが到着するまで準備ができていることを報告しないようにする方法はありますか? それとも、すべてのデータを読み取った後にその接続を閉じて、別の接続要求を待つのが一般的ですか? 私は多くのチュートリアルと説明を読みましたが、これを正しく行う方法を理解することができませんでした. 多分私は明らかな何かを見逃していますか?
コードを見るのに役立つ場合は、私がやっていることは次のとおりです。
// Server side setup in the main thread
$this->mConnectionSocket = socket_create(AF_INET, SOCK_STREAM, 0);
$arrOpt = array('l_onoff' => 1, 'l_linger' => 0);
@socket_set_option($this->mConnectionSocket, SOL_SOCKET, SO_LINGER, $arrOpt);
@socket_set_option($this->mConnectionSocket, SOL_SOCKET, SO_REUSEADDR, true);
@socket_bind($this->mConnectionSocket, Hostname, $this->mPortNumber);
@socket_listen($this->mConnectionSocket);
@socket_set_block($this->mConnectionSocket);
.
.
.
// Then call listen(), which looks like this:
public function listen(&$outReadySockets) {
$null = null;
while(true) {
$readyArray = array_merge(array($this->mConnectionSocket), $this->mReceiverSockets);
socket_select($readyArray, $null, $null, $waitTime = null);
if(in_array($this->mConnectionSocket, $readyArray) === true) {
$this->acceptConnection();
$key = array_search($this->mConnectionSocket, $readyArray);
if($key === false) {
throw new IPCException("array_search() returned unexpected value");
} else {
unset($readyArray[$key]);
if(in_array($this->mConnectionSocket, $readyArray) === true) {
throw new IPCException("in_array() says the key is still there");
}
}
}
if(count($readyArray) > 0) {
$outReadySockets = array_merge($readyArray);
break;
}
}
}
// Client side setup in the child thread
$this->mSocket = @socket_create(AF_INET, SOCK_STREAM, 0);
@socket_set_block($this->mSocket);
@socket_connect($this->mSocket, Hostname, $this->mPortNumber);
.
.
.
@socket_write($this->mSocket, $inDataToWrite, $lengthToWrite);
// Main thread reads the socket until it's empty
$data = "";
$totalBytesRead = 0;
while($totalBytesRead < $inNumberOfBytesToRead) {
// Strange that even if we set the socket to block mode, socket_read()
// will not block. If there's nothing there, it will just return an
// empty string. This is documented in the PHP docs.
$tdata = socket_read($inSock, $inNumberOfBytesToRead);
if($tdata === false) {
throw new IPCException("socket_read() failed: " . socket_strerror(socket_last_error()));
} else {
$data .= $tdata;
$bytesReadThisPass = strlen($tdata);
if($bytesReadThisPass === 0) {
break;
}
}
$totalBytesRead += $bytesReadThisPass;
}
.
.
.
// Then calls listen() again
私が言うように、それはうまく機能しますが、2 回目に呼び出すlisten()
と、ソケットがまだ準備ができていることがわかります。それはPHPドキュメントが言っていることのようですが、私はそれを望んでいません。本当にそこにデータがあるのか知りたいです。私はそれを間違っていますか?それとも要点を見失っているだけですか?