我正在尝试从 PHP 服务器向 Nginx 服务器发出异步 HTTP POST 请求。我读了这个非常有用的blog post关于这个问题,决定使用 pfsockopen
函数的技术,并导入 code这样做是由博客作者编写的。我包括以下关键部分:
private function createSocket() {
if ($this->socket_failed)
return false;
$protocol = $this->ssl() ? "ssl" : "tcp";
$host = $this->options["host"];
$port = $this->ssl() ? 443 : 80;
$timeout = $this->options["timeout"];
try {
# Open our socket to the API Server.
# Since we're try catch'ing prevent PHP logs.
$socket = @pfsockopen($protocol . "://" . $host, $port, $errno,
$errstr, $timeout);
# If we couldn't open the socket, handle the error.
if (false === $socket) {
...
return false;
}
return $socket;
} catch (Exception $e) {
...
return false;
}
}
private function makeRequest($socket, $req, $retry = true) {
$bytes_written = 0;
$bytes_total = strlen($req);
$closed = false;
# Write the request
while (!$closed && $bytes_written < $bytes_total) {
try {
# Since we're try catch'ing prevent PHP logs.
$written = @fwrite($socket, substr($req, $bytes_written));
} catch (Exception $e) {
...
$closed = true;
}
if (!isset($written) || !$written) {
$closed = true;
} else {
$bytes_written += $written;
}
}
# If the socket has been closed, attempt to retry a single time.
if ($closed) {
fclose($socket);
if ($retry) {
$socket = $this->createSocket();
if ($socket) return $this->makeRequest($socket, $req, false);
}
return false;
}
$success = true;
...
return $success;
}
它大部分工作得很好,但我观察到以下问题。通常,在大约 30 秒不活动后,当我以这种方式发送请求时,Nginx 会响应一个 TCP RST(重置)数据包,I read表示套接字已在远程端关闭。我还可以使用 netstat -na | 查看连接状态grep 8080
到那时,连接 PHP -> Nginx 处于 CLOSE_WAIT
状态,而 Nginx -> PHP 处于 FIN_WAIT2
。 This guide确认这意味着远程服务器要关闭连接。
我知道问题是由远程端的连接超时设置引起的,因为当我增加它时,netstat
显示的连接会保持状态 ESTABLISHED
的时间更长, 如果 PHP 服务器决定重用这样的连接,它工作正常。但是,我不想将连接超时设置为非常高的值,因为我担心端口用完。
有什么方法可以在 PHP 中检测到连接进入了 CLOSE_WAIT
状态?我尝试了以下方法,但均无效:
- 检查
pfsockopen
返回的句柄是否为假。 - 正在检查由
pfsockopen
编写的$errno
变量。 - 尝试从
pfsockopen
和fwrite
捕获异常。 - 检查
fwrite($socket)
是否返回 false。 - 检查
fflush($socket)
是否返回 false。 - 正在检查
stream_get_meta_data($socket)['timed_out']
。
最佳答案
这是一百万个问题,从我读过的唯一方法来检查正在执行 fread($socket)
并且如果返回值为 false 则出现错误,那可能是数以百万计的东西,但如果远程服务器关闭了连接,fread
将始终返回 false。如果这让您失望了,我很抱歉,但我认为没有其他办法。
关于php - 如何检测 PHP pfsockopen 被远程服务器关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34769361/