Ошибка socket_recv()

botbot

Новичок
Ошибка socket_recv()

Есть сервер, который выполняет роль чата. Запущен не через апач, а как отдельный процесс в ОС, написанный на php. Основной цикл приёма сообщений/событий от клиентов:
PHP:
while(true) {
 $changed_sockets = $this->sockets;  // все подключённые клиенты + сокет на ожидание новых подключений
 $write = array(); // это чтобы не ругался интерпретатор
 $except = array(); // это тоже.

 $num_changed_sockets = socket_select($changed_sockets, $write, $except, NULL);

 // анализ изменений в сокетах
 foreach($changed_sockets as $socket) {

  if ($socket == $this->master) {

   // новое подключение
   if (($client = socket_accept($this->master)) < 0) {
    continue;
   } else {
    array_push($this->sockets, $client);
   }

  } else {

   // кто-то из существующих юзеров
   $bytes = socket_recv($socket, $buffer, 2048, 0);  // <- ВОТ ТУТ ошибка

   if ($bytes == 0) {

    // закрылась конекция
    $index = array_search($socket, $this->sockets);
    unset($this->sockets[$index]);
    socket_close($socket);

   }else{

    // приём сообщения

   }
  }
 }
}
Все не относящиеся к делу строчки убрал. Так вот, временами (не всегда, но время от времени), вся это конструкция падает со словами
2: socket_recv(): unable to read from socket [110]: Connection timed out
Кому лень разбирать весь код: сначала вызывается socket_select, она оставляет в $read сокеты, которым есть что сказать. Потом вызывается socket_recv для этих сокетов, и иногда она падает и рушит весь скрипт.
Пробовал обрамллять socket_recv() try/catch конструкцией, но генерируется не исключение, а именно ошибка, которая попадает в мой error_handler.
Вопрос: как можно понять, что сокет нельзя читать? Как сделать, чтобы чат не падал?
 

botbot

Новичок
Автор оригинала: tz-lom
http://ru2.php.net/manual/en/function.socket-get-status.php
для неблокирующего сокета таймаут читаться не будет
Поменял то место на
PHP:
$status = socket_get_status($socket);
if($status['timed_out']) {
 add_log("Socket $socket timeout \n");
 $bytes = 0;	// это вызовет удаление
}
else {
 $bytes = socket_recv($socket, $buffer, 2048, 0);
}
Теперь ругается:
Warning: socket_get_status(): supplied resource is not a valid stream resource
Код создания слушающего сокета:
PHP:
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
 add_log("socket_create() failed, reason: " . socket_strerror($master) . "\n");
 exit;
}

socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);

if (($ret = socket_bind($master, 'айпишник сервака', 5080)) < 0) {
 add_log("socket_bind() failed, reason: " . socket_strerror($ret) . "\n");
 exit;
}

if (($ret = socket_listen($master, 5)) < 0) {
 add_log("socket_listen() failed, reason: " . socket_strerror($ret) . "\n");
 exit;
}

$this->master = $master;
$this->sockets = array($master);
Я теперь вообще ничего непонимаю.
 

tz-lom

Продвинутый новичок
тэксь,вообщем надо было внимательнее мне смотреть
во первых в доке классно написанно что socket_get_status с такими сокетами действительно не работает

далее
у нас есть socket_last_error - вернёт последнюю ошибку на сокете
снимать флаг ошибки он не будет,так что вручную socket_clear_error когда обработаешь ошибку
далее
за ошибками тоже надо следить,так что в $except наверное стоит передать копию $changed_sockets
копию потому что скорее всего в этом массиве будут оставаться только сокеты с ошибкой на себе
кстати если я правильно всё понимаю то в $changed_sockets после функции будет только одна запись
 
Сверху