php - 如何检测 PHP pfsockopen 被远程服务器关闭?

标签 php sockets nginx tcp

我正在尝试从 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_WAIT2This guide确认这意味着远程服务器要关闭连接。

我知道问题是由远程端的连接超时设置引起的,因为当我增加它时,netstat 显示的连接会保持状态 ESTABLISHED 的时间更长, 如果 PHP 服务器决定重用这样的连接,它工作正常。但是,我不想将连接超时设置为非常高的值,因为我担心端口用完。

有什么方法可以在 PHP 中检测到连接进入了 CLOSE_WAIT 状态?我尝试了以下方法,但均无效:

  • 检查 pfsockopen 返回的句柄是否为假。
  • 正在检查由 pfsockopen 编写的 $errno 变量。
  • 尝试从 pfsockopenfwrite 捕获异常。
  • 检查 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/

相关文章:

php - 来自 MYSQL 数据库的结果和查询未以 HTML 格式显示

sockets - 是否有用于实时通信(websocket或ajax轮询等)的基准?

sockets - epoll_wait() 接收套接字关闭两次(read()/recv() 返回 0)

c - recv() 阻止第二次调用

php - 带有 SVN-VC 的多开发人员设置和每个开发人员的远程测试服务器。最佳实践?

php - 如何使用 If Within Input Div 向用户显示基于数据库值的消息

nginx - 如何重新启动由乘客安装的 nginx

nginx - 如何在 Gitlab Omnibus 服务器旁边为其他虚拟主机提供服务? [完整的逐步解决方案]

php - 使用 MySQL LONGBLOB 上传和下载二进制文件时出错

nginx - 使用Chef和Vagrant时如何禁用默认的Nginx网站?