Невозможно подключиться к неблокирующему разъему - PullRequest
3 голосов
/ 18 марта 2012

Это сводит меня с ума.Мне нужно создать очень простой неблокирующий скрипт сокета в php 5.3, где клиент подключается к серверу, используя неблокирующие сокеты.

Я пробовал phpsocketdaemon и примериз php 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.

Кто-нибудь знает, как решить эту проблему, или знает простой и понятный пример неблокирующего сокетаклиент / серверный скрипт?

Ответы [ 2 ]

9 голосов
/ 18 марта 2012

Когда вы устанавливаете свой сокет неблокирующим, вы не можете ожидать, что результат socket_connect() вернет TRUE, если он подключен, или FALSE, если нет.

Страница руководства PHP :

Если сокет не является блокирующим, то эта функция возвращает FALSE с ошибкой. Выполняется операция.

Это верно для любого языка. Вы должны установить сокет «блокировка» или опрашивать / выбирать в своем файловом дескрипторе, прежде чем проверять, правильно ли вы подключены или нет. В PHP вы можете вызвать функцию socket_connect() через небольшой промежуток времени, чтобы проверить, возвращает ли она значение true, false или дождаться истечения времени ожидания.

Попробуйте этот код [ EDITED , чтобы исправить небольшую ошибку в процедуре тайм-аута]:

<?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;
  }

?>
2 голосов
/ 31 марта 2014

Предыдущее решение у меня не сработало, поэтому я нашел его с помощью 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);

Оно работает как на XAMPP в Windows, так и на моем Linux-сервере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...