public function start()
{
$this->onStart();
if ($this->timer) {
$timer = $this->_createTimer();
}
while (true) {
//prepare the array of sockets that need to be processed
$read = $this->clients + $this->services;
if ($this->_server) {
$read[] = $this->_server;
}
if ($this->_service) {
$read[] = $this->_service;
}
if ($this->_master) {
$read[] = $this->_master;
}
if ($this->timer) {
$read[] = $timer;
}
if (!$read) {
return;
}
$write = array();
if ($this->_write) {
foreach ($this->_write as $connectionId => $buffer) {
if ($buffer) {
$write[] = $this->getConnectionById($connectionId);
}
}
}
$except = $read;
stream_select($read, $write, $except, null);
//update the array of sockets that can be processed
if ($this->timer && in_array($timer, $read)) {
unset($read[array_search($timer, $read)]);
fread($timer, self::SOCKET_BUFFER_SIZE);
$this->onTimer();
}
if ($read) {
//data were obtained from the connected clients
foreach ($read as $client) {
if ($this->_server == $client) {
//the server socket got a request from a new client
if (count($this->clients) + count($this->services) < self::MAX_SOCKETS && ($client = @stream_socket_accept($this->_server, 0))) {
stream_set_blocking($client, 0);
$clientId = $this->getIdByConnection($client);
$this->clients[$clientId] = $client;
$this->_onOpen($clientId);
}
} elseif ($this->_service == $client) {
//the local socket got a request from a new client
if (count($this->clients) + count($this->services) < self::MAX_SOCKETS && ($client = @stream_socket_accept($this->_service, 0))) {
stream_set_blocking($client, 0);
$clientId = $this->getIdByConnection($client);
$this->services[$clientId] = $client;
$this->onServiceOpen($clientId);
}
} else {
$connectionId = $this->getIdByConnection($client);
if (in_array($client, $this->services)) {
if (is_null($this->_read($connectionId))) {
//connection has been closed or the buffer was overflow
$this->close($connectionId);
continue;
}
while ($data = $this->_readFromBuffer($connectionId)) {
$this->onServiceMessage($connectionId, $data);
//call user handler
}
} elseif ($this->_master == $client) {
if (is_null($this->_read($connectionId))) {
//connection has been closed or the buffer was overflow
$this->close($connectionId);
continue;
}
while ($data = $this->_readFromBuffer($connectionId)) {
$this->onMasterMessage($data);
//call user handler
}
} else {
if (!$this->_read($connectionId)) {
//connection has been closed or the buffer was overwhelmed
$this->close($connectionId);
continue;
}
$this->_onMessage($connectionId);
}
}
}
}
if ($write) {
foreach ($write as $client) {
if (is_resource($client)) {
//verify that the connection is not closed during the reading
$this->_sendBuffer($client);
}
}
}
if ($except) {
foreach ($except as $client) {
$this->_onError($this->getIdByConnection($client));
}
}
}
}