PHP socket_write在非阻塞套接字的循环中只有最后写入成功

时间:2018-02-09 14:18:11

标签: php sockets tcp stream nonblocking

我想通过套接字将数据发送到2个不同的端点。这是用于通过WebSockets和Push-Services发送消息(一个单独的工作者实例就是这样)。 由于我的应用程序不需要端点的答案,我将套接字设置为非阻塞,以便我的应用程序快速完成请求。

问题是,只完成了最后一个socket_write。第一个端点不接收数据。

以下是代码:

foreach ($workerInstances as $workerInstance) {
  // $workerInstance contains a hostname

  $sock=socket_create(AF_INET, SOCK_STREAM,SOL_TCP);
  socket_set_nonblock($sock);

  $connRes = socket_connect($sock, $workerInstance, 8018);
  if ($connRes) {
    $written = socket_write($sock, $data,strlen($data));
    socket_close($sock);

    if ($written === FALSE) {
      $result[] = $workerInstance . ': Connected but failed to write';
      ++$failures;
    } else {
      $result[] = $workerInstance . ': OK - ' . $written . ' bytes written';
    }

  } else {
    ++$failures;
    $result[]=$workerInstance . ': Failed';
  }
}
然后

$结果:

[
    "app01.local: Connected but failed to write",
    "app02.local: OK - 63 bytes written"
]

我认为socket_write在非阻塞模式下的返回是不可靠的,对吧?但是第一个端点确实没有收到任何数据。在阻塞模式下,两个端点都获取其数据。

我做错了什么?

1 个答案:

答案 0 :(得分:0)

http://php.net/manual/en/function.socket-connect.php#84465

上找到解决方案

在非阻塞模式下,我必须等到套接字连接完成后再写入套接字。因此,我们在循环中进行连接,直到结果不为FALSE或错误不是"正在进行连接" (或者我们等待足够长时间建立连接)。

foreach ($workerInstances as $workerInstance) {
  $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  socket_set_nonblock($sock);

  // wait until connection established
  $attempts = 30;
  while (!($connRes = socket_connect($sock, $workerInstance,
      8018)) && $attempts) {
    $error = socket_last_error();
    if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
      $result[] = $workerInstance . ' Socket connect error: ' . socket_strerror($error);
      break;
    } else {
      $result[] = $workerInstance . ' Connecting...';
    }

    usleep(1000);
    --$attempts;
  }


  if ($connRes) {
     $written = socket_write($sock, $data,strlen($data));

     if ($written === FALSE) {
        $result[] = $workerInstance . ': Connected but failed to write';
        ++$failures;
     } else {
        $result[] = $workerInstance . ': OK - ' . $written . ' bytes written';
     }

  } elseif ($attempts === 0) {
    ++$failures;
    $result[]=$workerInstance . ': Failed - Timeout!';

  } else {
    ++$failures;
    $result[]=$workerInstance . ': Failed';
  }
  socket_close($sock);
}

现在$ result是

[
    "app01.local Connecting...",
    "app01.local: OK - 63 bytes written",
    "app02.local Connecting...",
    "app02.local: OK - 63 bytes written",
]