Socket fd was inexplicable to delete

Issue #41 invalid
54phper created an issue

event.php

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); 
socket_bind($socket, "192.168.6.20", 9090);
socket_listen($socket, 1024);


$base = new EventBase();
$event = new Event($base, $socket, Event::READ|Event::PERSIST,  function ($socket) use($base){

    $client = socket_accept($socket);
    $event = new Event($base, $client, Event::READ|Event::PERSIST,  function ($socket){
          var_dump($socket);
    }); 
    $event->add();
});

$event->add();
$base->loop( EventBase::EPOLL_USE_CHANGELIST )

server : strace php event.php

client : nc 192.168.6.20 9090

socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("192.168.6.20")}, 16) = 0
listen(3, 1024)                         = 0
........................
........................
epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
epoll_wait(4, {{EPOLLIN, {u32=3, u64=3}}}, 32, -1) = 1
gettimeofday({1502611043, 724745}, NULL) = 0
accept(3, {sa_family=AF_INET, sin_port=htons(18060), sin_addr=inet_addr("192.168.6.20")}, [16]) = 7
epoll_ctl(4, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0

//is closed
close(7)                           = 0
//is removed 
epoll_ctl(4, EPOLL_CTL_DEL, 7, {EPOLLIN, {u32=7, u64=7}}) = -1 EBADF (Bad file descriptor)

event Extension version 2.3.0

libevent2 headers version 2.1.8-stable

php -v

PHP 7.0.7 (cli) (built: Aug 11 2017 12:30:13) ( ZTS ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

Comments (6)

  1. Ruslan Osmanov repo owner

    If you mean that the client connection should not be closed, then this is not a bug.

    The problem with your code is that the $client variable is destroyed when the scope of the anonymous function ends (as any other local variable). Hence, the underlying file descriptor is closed. You should keep references to the client sockets (file descriptors) until one of the following events occurs:

    • the event loop finishes its work;
    • the client closes connection;
    • you intentionally close the client's connection.

    The $event variable's lifetime is not different from any other PHP variable. It is destroyed at the end of the scope by garbage collector, since there are no more references to this variable. When Event object is destroyed, the object is removed from the event loop as well.

    Here is a simple example for clarity:

    class ClientConnections
    {
        private $sockets = [], $events = [];
    
        function push($socket, Event $event)
        {
            $this->sockets[] = $socket;
            $this->events[] = $event;
        }
    }
    
    $connections = new ClientConnections;
    
    $event = new Event($base, $socket, Event::READ|Event::PERSIST,  function ($socket) use($base, $connections) {
        $client = socket_accept($socket);
        $event = new Event($base, $client, Event::READ|Event::PERSIST,  function ($socket) {
              var_dump($socket);
        });
        $event->add();
    
        $connections->push($client, $event);
    }
    
  2. 54phper reporter

    I thought about the problem before, so I tried to store the event. But the event is still deleted, your method is right. Fd and event need to be stored.

    thank you very much

  3. Log in to comment