无法连接到非阻塞套接字

3
这让我很烦恼。我需要在php 5.3中创建一个非常简单的非阻塞socket脚本,其中客户端和服务器都使用非阻塞socket。我尝试过phpsocketdaemonphp manual中的示例,但是在连接到服务器时,我都会收到以下错误:
socket_connect() [function.socket-connect]: unable to connect [10035]:
A non-blocking socket operation could not be completed immediately

错误发生的客户端脚本:

$service_port = 2002;
$address = '127.0.0.1';

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($socket); 
$result = socket_connect($socket, $address, $service_port);
...

我正在使用Zend Server 5.6.0 SP1的免费版本在Win 7上。

有人知道如何解决这个问题或者知道一个简单易懂的非阻塞套接字客户端/服务器脚本示例吗?


你确定端口是空闲的并且允许进出数据吗? - bluegman991
@bluegman991 是的,我确定端口是空闲的,并且允许传入数据,但我不知道如何检查它是否允许传出数据。 - HomeCoder
2个回答

10
当你将套接字设置为非阻塞时,不能期望socket_connect()的结果返回TRUE表示连接成功,或者返回FALSE表示连接失败。
参考PHP手册页面

如果套接字是非阻塞的,那么该函数会返回FALSE,并显示错误信息"Operation now in progress"。

这在任何语言中都是正确的。你必须将套接字设置为"阻塞",或者在检查连接是否成功之前,必须对文件描述符进行轮询/选择操作。 在PHP中,你可以在一小段时间后调用socket_connect()函数,以检查它返回的是true、false还是等待超时。
尝试以下代码[已编辑以修复超时例程中的小错误]:
<?php

  $service_port = 2002;
  $address = '127.0.0.1';
  $timeout = 3;

  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  socket_set_nonblock($socket);
  $error = NULL;
  $attempts = 0;
  $timeout *= 1000;  // adjust because we sleeping in 1 millisecond increments
  $connected = FALSE;
  while (!($connected = @socket_connect($socket, $address, $service_port)) && ($attempts++ < $timeout)) {
        $error = socket_last_error();
        if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
              echo "Error Connecting Socket: ".socket_strerror($error) . "\n";
              socket_close($socket);
              return NULL;
        }
        usleep(1000);
  }

  if (!$connected) {
        echo "Error Connecting Socket: Connect Timed Out After " . $timeout/1000 . " seconds. ".socket_strerror(socket_last_error()) . "\n";
        socket_close($socket);
        return NULL;
  }

?>

3

之前的解决方案对我没用,所以我使用socket_select找到了我的解决方案:

<?php
$service_port = 80;
$address = '127.0.0.1';
$timeout = 3;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($socket);
$error = NULL;
$attempts = 0;
$timeout *= 1000;  // adjust because we sleeping in 1 millisecond increments
$connected = FALSE;
$connected = @socket_connect($socket, $address, $service_port);
if (!$connected)
{
    $error = socket_last_error();
    if ($error != 10035 && $error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
        echo "Error Connecting Socket: ".socket_strerror($error) . "\n";
        socket_close($socket);
        exit();
    }
}
$writables = array();
$writables[] = $socket;
$readable = array();
$e = array();
$result = socket_select($readable, $writables, $e, $timeout);
if (!$result)
    die("Unable to connect to socket: Timeout");
/* blablah send lots of things */
socket_close($socket);

它可以在Windows上的XAMPP和我的Linux服务器上运行。


到目前为止,你的代码是唯一一个能够按预期正确运行的代码。其他代码总是返回“超时”,即使主机显然可以连接。 - vantrung -cuncon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接