- edited description
Add event - Ev::CLOSE for EvIo watcher
Now event CLOSE of the socket, fire as Ev::READ event, you can add a new Ev::CLOSE event, to appoint a separate handler?
Something like this
$loop->io($fd, Ev::CLOSE, function ($w) {...});
Comments (4)
-
reporter -
repo owner - changed status to wontfix
There is no such kind of event as "closed file descriptor(socket)" neither in
libev
, nor in the back ends supported bylibev
, AFAIK.Also, I don't know how to check if a socket is open or closed without actually accessing it(
recv
orwrite
system calls, for example). You might think offeof()
orstream_get_meta_data()
, but these won't work withEvIo::$fd
because the underlying logic is based on internal flags changed by performing PHP stream operations. SoEvIo::$fd
is not quite true PHP stream.Thus, you have to check if corresponding operation on socket succeeds in the
Ev::READ
callback. For example, a server based onsockets
extension might look like the following:<?php $address = '127.0.0.1'; $port = 10000; error_reporting(E_ALL); ob_implicit_flush(); // Writing to a socket that has been closed by the other end will result in // the process receiving SIGPIPE signal. The default action for this signal is // to terminate process. Although it may not happen in PHP, we'll ignore this // signal explicitly. pcntl_signal(SIGPIPE, SIG_IGN); if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { fprintf(STDERR, "socket_create failed: %s\n", socket_strerror(socket_last_error()) ); exit(1); } if (socket_bind($sock, $address, $port) === false) { fprintf(STDERR, "socket_bind failed: %s\n", socket_strerror(socket_last_error()) ); exit(1); } if (socket_listen($sock, 5) === false) { fprintf(STDERR, "socket_listen failed: %s\n", socket_strerror(socket_last_error()) ); exit(1); } do { if (($msgsock = socket_accept($sock)) === false) { fprintf(STDERR, "socket_accept failed: %s\n", socket_strerror(socket_last_error()) ); break; } // Set O_NONBLOCK flag socket_set_nonblock($msgsock); $msg = "Welcome to the test server. To quit tpe 'quit'.\n"; socket_write($msgsock, $msg, strlen($msg)); $read_watcher = new EvIo($msgsock, Ev::READ, function ($watcher, $events) use ($msgsock) { if ($events & Ev::ERROR) { $watcher->stop(); Ev::stop(Ev::BREAK_ALL); return; } if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) { fprintf(STDERR, "socket_read failed: %s\n", socket_strerror(socket_last_error())); return; } $buf = trim($buf); if ($buf == 'quit') { $watcher->stop(); socket_close($msgsock); return; } $talkback = "You said: $buf\n"; if (! socket_write($msgsock, $talkback, strlen($talkback))) { $errno = socket_last_error(); fprintf(STDERR, "socket_write failed: %s\n", socket_strerror($errno)); $watcher->stop(); socket_close($msgsock); echo "Connection closed\n"; return; } echo "$buf\n"; }); echo "Running Ev loop\n"; Ev::run(); if (is_resource($msgsock)) { socket_close($msgsock); } } while (true); socket_close($sock);
-
repo owner You might want to check if
socket_last_error() == SIGPIPE
. -
reporter Ok, thank.
- Log in to comment