Проблема с неблокируемым сокетом

AnrDaemon

Продвинутый новичок
PHP:
$smtp = stream_socket_client('tcp://192.168.1.7:25', $_errn, $_errs);

if(empty($smtp))
  die(1);

stream_set_blocking($smtp, 0);
stream_set_timeout($smtp, 5);

while(true)
{
  $rc = fread($smtp, 1024);
  $meta = stream_get_meta_data($smtp);
  ob_start();
  var_dump($rc);
  $rc = ob_get_clean();
  printf("%d:%d:%s\n", $meta['blocked'], $meta['timed_out'], trim($rc));
  sleep(1);
  if($meta['timed_out']) break;
}
Кручу вот такой фрагмент. Но даже если я шатдауню SMTP сервер, к которому он приконнектился, код продолжает работать, как ни в чём не бывало.
~15 минут крутился, пока я руками не прервал процесс.
ЧЯДНТ?
Если я вообще всё ДНТ, то как определить смерть сокета? Только по отсутствию данных?
 

флоппик

promotor fidei
Команда форума
Партнер клуба
все делаешь правильно - tcp по-определению задуман устойчивым к разрывам, а в те времена, когда пинги были большими, а скорости передачи данных маленькими, и был задуман tcp, поэтому у него таймаут коннекта:
tcp_retries2 (integer; default: 15; since Linux 2.2)
The maximum number of times a TCP packet is retransmitted in
established state before giving up. The default value is 15, which
corresponds to a duration of approximately between 13 to 30 minutes,
depending on the retransmission timeout. The RFC 1122 specified
minimum limit of 100 seconds is typically deemed too short.
по хорошему, либо сервер должен рассылать клиентам нотифай при отключении (что не всегда возможно), либо клиенты могут крутить пустую команду для проверки таймаута.
рфцшка про смтп говорит, что:

An SMTP server MUST NOT intentionally close the connection under
normal operational circumstances (see Section 7.8) except:

o After receiving a QUIT command and responding with a 221 reply.

o After detecting the need to shut down the SMTP service and
returning a 421 response code. This response code can be issued
after the server receives any command or, if necessary,
asynchronously from command receipt (on the assumption that the
client will receive it after the next command is issued).

o After a timeout, as specified in Section 4.5.3.2, occurs waiting
for the client to send a command or data.
Про таймауты рфцшка говорит, что - http://tools.ietf.org/html/rfc5321#section-4.5.3.2

А вообще - у stream_socket_client четвертый параметр - таймаут сокета :)
 

AnrDaemon

Продвинутый новичок
У stream_socket_client
timeout
Number of seconds until the connect() system call should timeout.
Т.е. 4-й параметр задаёт таймаут на время УСТАНОВЛЕНИЯ СВЯЗИ.

"Там же, тогда же" (q) ...
stream_set_timeout задаёт таймаут на чтение информации из сокета. При этом не уточняется, будет ли он действовать, если информация из сокета не поступает.

SMTP выбран просто как пример - мне легко до него достучаться(локальный процесс), у него простой протокол, он первым посылает данные (строка приветствия отсылается сразу по установлению соединения), мне легко им манипулировать, симулируя обрывы связи.
 

AnrDaemon

Продвинутый новичок
Любопытно. feof показывает смерть сокета сразу.
Слегка модифицировал код, оставил его крутиться с фоне. Посмотрим, чем кончится.
 

AnrDaemon

Продвинутый новичок
0.000 blocked:0; timed:0; EOF:0; data: string(0) ""
0.000 blocked:0; timed:0; EOF:0; data: string(42) "220 SMTP server ready. Relaying enabled.
"
0.000 blocked:0; timed:0; EOF:0; data: string(0) ""
180.016 blocked:0; timed:0; EOF:1; data: string(0) ""
Такое ощущение, что неблокируемый сокет вообще не выходит в таймаут. (В этот раз соединение закрыл сам сервер.)
 
Сверху