【发布时间】:2013-08-25 23:17:47
【问题描述】:
编辑: *测试工具中的错误导致我误解了结果。 socket_select() 的工作原理完全正确如您所料:它确实会等到套接字上准备好数据。但是如果您在客户端关闭连接后调用它,它将报告就绪。原来这都是我的错,但我会把问题留在这里,以防其他人怀疑socket_select() 的行为。
我有一个多线程 PHP 应用程序,并且我正在使用套接字在线程之间进行通信。通信工作得很好,但我最终对没有准备好数据的套接字进行了很多不必要的读取。也许我缺少一些关于套接字编程的东西。
socket_select() 的 PHP doc 表示 read 数组中列出的套接字将被监视以查看读取是否不会阻塞。
这正是我想要的行为:调用socket_select() 等到我的一个子线程尝试与我交谈。但这仅适用于线程第一次写入,在我接受连接之后。在那之后,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
正如我所说,它工作得很好,除了当我第二次调用listen() 时,它告诉我套接字仍然准备就绪。这似乎是 PHP 文档所说的,但我不希望那样。我想知道那里真的有数据。我做错了吗?还是没抓住重点?
【问题讨论】:
标签: php multithreading sockets