added new socket manager, errorhandling and testing is not finished yet

This commit is contained in:
kremsy
2015-06-21 20:43:18 +02:00
parent eaf8819a57
commit fc5a3e04b6
32 changed files with 2627 additions and 0 deletions

View File

@ -0,0 +1,42 @@
<?php
namespace React\Socket;
use React\Stream\Stream;
class Connection extends Stream implements ConnectionInterface
{
public function handleData($stream)
{
// Socket is raw, not using fread as it's interceptable by filters
// See issues #192, #209, and #240
$data = stream_socket_recvfrom($stream, $this->bufferSize);
if ('' !== $data && false !== $data) {
$this->emit('data', array($data, $this));
}
if ('' === $data || false === $data || !is_resource($stream) || feof($stream)) {
$this->end();
}
}
public function handleClose()
{
if (is_resource($this->stream)) {
// http://chat.stackoverflow.com/transcript/message/7727858#7727858
stream_socket_shutdown($this->stream, STREAM_SHUT_RDWR);
stream_set_blocking($this->stream, false);
fclose($this->stream);
}
}
public function getRemoteAddress()
{
return $this->parseAddress(stream_socket_get_name($this->stream, true));
}
private function parseAddress($address)
{
return trim(substr($address, 0, strrpos($address, ':')), '[]');
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace React\Socket;
class ConnectionException extends \ErrorException
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace React\Socket;
use Evenement\EventEmitterInterface;
use React\Stream\ReadableStreamInterface;
use React\Stream\WritableStreamInterface;
interface ConnectionInterface extends ReadableStreamInterface, WritableStreamInterface
{
public function getRemoteAddress();
}

View File

@ -0,0 +1,71 @@
<?php
namespace React\Socket;
use Evenement\EventEmitter;
use React\EventLoop\LoopInterface;
/** @event connection */
class Server extends EventEmitter implements ServerInterface
{
public $master;
private $loop;
public function __construct(LoopInterface $loop)
{
$this->loop = $loop;
}
public function listen($port, $host = '127.0.0.1')
{
if (strpos($host, ':') !== false) {
// enclose IPv6 addresses in square brackets before appending port
$host = '[' . $host . ']';
}
$this->master = @stream_socket_server("tcp://$host:$port", $errno, $errstr);
if (false === $this->master) {
$message = "Could not bind to tcp://$host:$port: $errstr";
throw new ConnectionException($message, $errno);
}
stream_set_blocking($this->master, 0);
$this->loop->addReadStream($this->master, function ($master) {
$newSocket = stream_socket_accept($master);
if (false === $newSocket) {
$this->emit('error', array(new \RuntimeException('Error accepting new connection')));
return;
}
$this->handleConnection($newSocket);
});
}
public function handleConnection($socket)
{
stream_set_blocking($socket, 0);
$client = $this->createConnection($socket);
$this->emit('connection', array($client));
}
public function getPort()
{
$name = stream_socket_get_name($this->master, false);
return (int) substr(strrchr($name, ':'), 1);
}
public function shutdown()
{
$this->loop->removeStream($this->master);
fclose($this->master);
$this->removeAllListeners();
}
public function createConnection($socket)
{
return new Connection($socket, $this->loop);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace React\Socket;
use Evenement\EventEmitterInterface;
/** @event connection */
interface ServerInterface extends EventEmitterInterface
{
public function listen($port, $host = '127.0.0.1');
public function getPort();
public function shutdown();
}