Merge branch 'refs/heads/master' into unittests

This commit is contained in:
Chris Boden 2011-11-24 21:03:19 -05:00
commit 4129036356
16 changed files with 154 additions and 77 deletions

View File

@ -1,13 +1,13 @@
#Ratchet #Ratchet
A PHP 5.3 (PSR-0 compliant) application for serving and consuming sockets. A PHP 5.3 (PSR-0 compliant) component library for serving/consuming sockets and building socket based applications.
Build up your application (like Lego!) through simple interfaces using the decorator and command patterns. Build up your application (like Lego!) through simple interfaces using the decorator and command patterns.
Re-use your application without changing any of its code just by wrapping it in a different protocol. Re-use your application without changing any of its code just by wrapping it in a different protocol.
##WebSockets ##WebSockets
* Supports the HyBi-10 and Hixie76 protocol versions (at the same time) * Supports the HyBi-10 and Hixie76 protocol versions (at the same time)
* Tested on Chrome 14, Firefox 7, Safari 5, iOS 4.2 * Tested on Chrome 13 - 15, Firefox 6 - 8, Safari 5, iOS 4.2, iOS 5
##Requirements ##Requirements
@ -15,8 +15,8 @@ Shell access is required and a dedicated (virtual) machine with root access is r
To avoid proxy/firewall blockage it's recommended WebSockets are run on port 80, which requires root access. To avoid proxy/firewall blockage it's recommended WebSockets are run on port 80, which requires root access.
Note that you can not run two applications (Apache and Ratchet) on the same port, thus the requirement for a separate machine. Note that you can not run two applications (Apache and Ratchet) on the same port, thus the requirement for a separate machine.
Cookies from your Apache/Nginx/IIS server will be passed to the socket server, allowing you to identify users. Cookies from your domain will be passed to the socket server, allowing you to identify users.
It's recommended using a database/cache solution to store session data, so it's accessible on both servers. It's recommended using a database/cache solution to store session data, so it's accessible on both web and socket servers.
A demonstration of this will be posted (eventually). A demonstration of this will be posted (eventually).
See https://github.com/cboden/socket-demos for some out-of-the-box working demos using Ratchet. See https://github.com/cboden/socket-demos for some out-of-the-box working demos using Ratchet.

View File

@ -2,42 +2,49 @@
namespace Ratchet\Application; namespace Ratchet\Application;
use Ratchet\Resource\Connection; use Ratchet\Resource\Connection;
/**
* This is the interface to build a Ratchet application with
* It impelemtns the decorator and command pattern to build an application stack
*/
interface ApplicationInterface { interface ApplicationInterface {
/** /**
* Decorator pattern * Decorator pattern
* @param Ratchet\ObserverInterface Application to wrap in protocol * @param Ratchet\ApplicationInterface Application to wrap in protocol
* @throws UnexpectedValueException
*/ */
public function __construct(ApplicationInterface $app = null); public function __construct(ApplicationInterface $app = null);
/** /**
* When a new connection is opened it will be passed to this method * When a new connection is opened it will be passed to this method
* @param SocketInterface The socket/connection that just connected to your application * @param Ratchet\Resource\Connection The socket/connection that just connected to your application
* @return Ratchet\Resource\Command\CommandInterface|null * @return Ratchet\Resource\Command\CommandInterface|null
* @throws Exception
*/ */
function onOpen(Connection $conn); function onOpen(Connection $conn);
/** /**
* Triggered when a client sends data through the socket * Triggered when a client sends data through the socket
* @param SocketInterface The socket/connection that sent the message to your application * @param Ratchet\Resource\Connection The socket/connection that sent the message to your application
* @param string The message received * @param string The message received
* @return Ratchet\Resource\Command\CommandInterface|null * @return Ratchet\Resource\Command\CommandInterface|null
* @throws Exception
*/ */
function onMessage(Connection $from, $msg); function onMessage(Connection $from, $msg);
/** /**
* This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed. * This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed.
* @param SocketInterface The socket/connection that is closing/closed * @param Ratchet\Resource\Connection The socket/connection that is closing/closed
* @return Ratchet\Resource\Command\CommandInterface|null * @return Ratchet\Resource\Command\CommandInterface|null
* @throws Exception
*/ */
function onClose(Connection $conn); function onClose(Connection $conn);
/** /**
* If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown, * If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,
* the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method * the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method
* @param SocketInterface * @param Ratchet\Resource\Connection
* @param \Exception * @param \Exception
* @return Ratchet\Resource\Command\CommandInterface|null * @return Ratchet\Resource\Command\CommandInterface|null
* @throws Exception
*/ */
function onError(Connection $conn, \Exception $e); function onError(Connection $conn, \Exception $e);
} }

View File

@ -21,8 +21,8 @@ class App implements ApplicationInterface {
protected $_connections = array(); protected $_connections = array();
/** /**
* The decorated application to send events to
* @var Ratchet\Application\ApplicationInterface * @var Ratchet\Application\ApplicationInterface
* Maybe temporary?
*/ */
protected $_app; protected $_app;
@ -41,18 +41,27 @@ class App implements ApplicationInterface {
$this->_app = $application; $this->_app = $application;
} }
/**
* Set the incoming buffer size in bytes
* @param int
* @return App
* @throws InvalidArgumentException If the parameter is less than 1
*/
public function setBufferSize($recv_bytes) { public function setBufferSize($recv_bytes) {
if ((int)$recv_bytes < 1) { if ((int)$recv_bytes < 1) {
throw new \InvalidArgumentException('Invalid number of bytes set, must be more than 0'); throw new \InvalidArgumentException('Invalid number of bytes set, must be more than 0');
} }
$this->_buffer_size = (int)$recv_bytes; $this->_buffer_size = (int)$recv_bytes;
return $this;
} }
/* /*
* Run the server infinitely
* @param Ratchet\SocketInterface * @param Ratchet\SocketInterface
* @param mixed The address to listen for incoming connections on. "0.0.0.0" to listen from anywhere * @param mixed The address to listen for incoming connections on. "0.0.0.0" to listen from anywhere
* @param int The port to listen to connections on * @param int The port to listen to connections on (make sure to run as root if < 1000)
* @throws Ratchet\Exception * @throws Ratchet\Exception
* @todo Validate address. Use socket_get_option, if AF_INET must be IP, if AF_UNIX must be path * @todo Validate address. Use socket_get_option, if AF_INET must be IP, if AF_UNIX must be path
* @todo Consider making the 4kb listener changable * @todo Consider making the 4kb listener changable
@ -134,6 +143,7 @@ class App implements ApplicationInterface {
public function onOpen(Connection $conn) { public function onOpen(Connection $conn) {
$new_socket = clone $conn->getSocket(); $new_socket = clone $conn->getSocket();
$new_socket->set_nonblock();
$new_connection = new Connection($new_socket); $new_connection = new Connection($new_socket);
$this->_resources[] = $new_connection->getSocket()->getResource(); $this->_resources[] = $new_connection->getSocket()->getResource();

View File

@ -7,6 +7,7 @@ use Ratchet\Resource\Command\Factory;
use Ratchet\Resource\Command\CommandInterface; use Ratchet\Resource\Command\CommandInterface;
use Ratchet\Resource\Command\Action\SendMessage; use Ratchet\Resource\Command\Action\SendMessage;
use Ratchet\Application\WebSocket\Util\HTTP; use Ratchet\Application\WebSocket\Util\HTTP;
use Ratchet\Application\WebSocket\Version;
/** /**
* The adapter to handle WebSocket requests/responses * The adapter to handle WebSocket requests/responses
@ -15,6 +16,7 @@ use Ratchet\Application\WebSocket\Util\HTTP;
* @todo Make sure this works both ways (client/server) as stack needs to exist on client for framing * @todo Make sure this works both ways (client/server) as stack needs to exist on client for framing
* @todo Learn about closing the socket. A message has to be sent prior to closing - does the message get sent onClose event or CloseConnection command? * @todo Learn about closing the socket. A message has to be sent prior to closing - does the message get sent onClose event or CloseConnection command?
* @todo Consider chaning this class to a State Pattern. If a WS App interface is passed use different state for additional methods used * @todo Consider chaning this class to a State Pattern. If a WS App interface is passed use different state for additional methods used
* @todo I think I need to overhaul the architecture of this...more onus should be on the VersionInterfaces in case of changes...let them handle more decisions, not just parsing
*/ */
class App implements ApplicationInterface, ConfiguratorInterface { class App implements ApplicationInterface, ConfiguratorInterface {
/** /**
@ -24,6 +26,7 @@ class App implements ApplicationInterface, ConfiguratorInterface {
protected $_app; protected $_app;
/** /**
* Creates commands/composites instead of calling several classes manually
* @var Ratchet\Resource\Command\Factory * @var Ratchet\Resource\Command\Factory
*/ */
protected $_factory; protected $_factory;
@ -47,6 +50,8 @@ class App implements ApplicationInterface, ConfiguratorInterface {
} }
/** /**
* Return the desired socket configuration if hosting a WebSocket server
* This method may be removed
* @return array * @return array
*/ */
public static function getDefaultConfig() { public static function getDefaultConfig() {
@ -66,6 +71,10 @@ class App implements ApplicationInterface, ConfiguratorInterface {
$conn->WebSocket->headers = ''; $conn->WebSocket->headers = '';
} }
/**
* Do handshake, frame/unframe messages coming/going in stack
* @todo This needs some major refactoring
*/
public function onMessage(Connection $from, $msg) { public function onMessage(Connection $from, $msg) {
if (true !== $from->WebSocket->handshake) { if (true !== $from->WebSocket->handshake) {
if (!isset($from->WebSocket->version)) { if (!isset($from->WebSocket->version)) {
@ -136,12 +145,17 @@ class App implements ApplicationInterface, ConfiguratorInterface {
return $this->prepareCommand($this->_app->onClose($conn)); return $this->prepareCommand($this->_app->onClose($conn));
} }
/**
* @todo Shouldn't I be using prepareCommand() on the return? look into this
*/
public function onError(Connection $conn, \Exception $e) { public function onError(Connection $conn, \Exception $e) {
return $this->_app->onError($conn, $e); return $this->_app->onError($conn, $e);
} }
/** /**
* Incomplete, WebSocket protocol allows client to ask to use a sub-protocol, I'm thinking/wanting to somehow implement this in an application decorated class
* @param string * @param string
* @todo Implement or delete...
*/ */
public function setSubProtocol($name) { public function setSubProtocol($name) {
} }
@ -153,6 +167,10 @@ class App implements ApplicationInterface, ConfiguratorInterface {
*/ */
protected function prepareCommand(CommandInterface $command = null) { protected function prepareCommand(CommandInterface $command = null) {
if ($command instanceof SendMessage) { if ($command instanceof SendMessage) {
if (!isset($command->getConnection()->WebSocket->version)) { // Client could close connection before handshake complete or invalid handshake
return $command;
}
$version = $command->getConnection()->WebSocket->version; $version = $command->getConnection()->WebSocket->version;
return $command->setMessage($version->frame($command->getMessage())); return $command->setMessage($version->frame($command->getMessage()));
} }
@ -167,11 +185,11 @@ class App implements ApplicationInterface, ConfiguratorInterface {
} }
/** /**
* @param array of HTTP headers * Detect the WebSocket protocol version a client is using based on the HTTP header request
* @param string HTTP handshake request
* @return Version\VersionInterface * @return Version\VersionInterface
* @throws UnderFlowException If we think the entire header message hasn't been buffered yet * @throws UnderFlowException If we think the entire header message hasn't been buffered yet
* @throws InvalidArgumentException If we can't understand protocol version request * @throws InvalidArgumentException If we can't understand protocol version request
* @todo Can/will add more versions later, but perhaps a chain of responsibility, ask each version if they want to handle the request
*/ */
protected function getVersion($message) { protected function getVersion($message) {
if (false === strstr($message, "\r\n\r\n")) { // This CAN fail with Hixie, depending on the TCP buffer in between if (false === strstr($message, "\r\n\r\n")) { // This CAN fail with Hixie, depending on the TCP buffer in between
@ -180,26 +198,33 @@ class App implements ApplicationInterface, ConfiguratorInterface {
$headers = HTTP::getHeaders($message); $headers = HTTP::getHeaders($message);
if (isset($headers['Sec-Websocket-Version'])) { // HyBi foreach ($this->_versions as $name => $instance) {
if ((int)$headers['Sec-Websocket-Version'] >= 6) { if (null !== $instance) {
return $this->versionFactory('HyBi10'); if ($instance::isProtocol($headers)) {
return $instance;
}
} else {
$ns = __NAMESPACE__ . "\\Version\\{$name}";
if ($ns::isProtocol($headers)) {
$this->_version[$name] = new $ns;
return $this->_version[$name];
}
} }
} elseif (isset($headers['Sec-Websocket-Key2'])) { // Hixie
return $this->versionFactory('Hixie76');
} }
throw new \InvalidArgumentException('Could not identify WebSocket protocol'); throw new \InvalidArgumentException('Could not identify WebSocket protocol');
} }
/** /**
* @return Version\VersionInterface * Disable a version of the WebSocket protocol *cough*Hixie76*cough*
* @param string The name of the version to disable
* @throws InvalidArgumentException If the given version does not exist
*/ */
protected function versionFactory($version) { public function disableVersion($name) {
if (null === $this->_versions[$version]) { if (!array_key_exists($name, $this->_versions)) {
$ns = __NAMESPACE__ . "\\Version\\{$version}"; throw new \InvalidArgumentException("Version {$name} not found");
$this->_version[$version] = new $ns;
} }
return $this->_version[$version]; unset($this->_versions[$name]);
} }
} }

View File

@ -3,6 +3,9 @@ namespace Ratchet\Application\WebSocket\Command\Action;
use Ratchet\Resource\Command\Action\SendMessage; use Ratchet\Resource\Command\Action\SendMessage;
use Ratchet\Application\ApplicationInterface; use Ratchet\Application\ApplicationInterface;
/**
* Not yet implemented/completed
*/
class Disconnect extends SendMessage { class Disconnect extends SendMessage {
protected $_code = 1000; protected $_code = 1000;

View File

@ -3,6 +3,9 @@ namespace Ratchet\Application\WebSocket\Command\Action;
use Ratchet\Resource\Command\ActionTemplate; use Ratchet\Resource\Command\ActionTemplate;
use Ratchet\Application\ApplicationInterface; use Ratchet\Application\ApplicationInterface;
/**
* Not yet implemented/completed
*/
class Ping extends ActionTemplate { class Ping extends ActionTemplate {
public function execute(ApplicationInterface $scope = null) { public function execute(ApplicationInterface $scope = null) {
} }

View File

@ -3,6 +3,9 @@ namespace Ratchet\Application\WebSocket\Command\Action;
use Ratchet\Resource\Command\ActionTemplate; use Ratchet\Resource\Command\ActionTemplate;
use Ratchet\Application\ApplicationInterface; use Ratchet\Application\ApplicationInterface;
/**
* Not yet implemented/completed
*/
class Pong extends ActionTemplate { class Pong extends ActionTemplate {
public function execute(ApplicationInterface $scope = null) { public function execute(ApplicationInterface $scope = null) {
} }

View File

@ -3,6 +3,7 @@ namespace Ratchet\Application\WebSocket\Util;
/** /**
* A helper class for handling HTTP requests * A helper class for handling HTTP requests
* @todo Needs re-write...http_parse_headers is a PECL extension that changes the case to unexpected values
*/ */
class HTTP { class HTTP {
/** /**

View File

@ -14,6 +14,10 @@ namespace Ratchet\Application\WebSocket\Version;
* @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 * @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
*/ */
class Hixie76 implements VersionInterface { class Hixie76 implements VersionInterface {
public static function isProtocol(array $headers) {
return isset($headers['Sec-Websocket-Key2']);
}
/** /**
* @param string * @param string
* @return string * @return string

View File

@ -10,6 +10,19 @@ use Ratchet\Application\WebSocket\Util\HTTP;
class HyBi10 implements VersionInterface { class HyBi10 implements VersionInterface {
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
/**
* @todo When I support later version (that implement extension) change >= 6 to 6 through 10 (or w/e #)
*/
public static function isProtocol(array $headers) {
if (isset($headers['Sec-Websocket-Version'])) {
if ((int)$headers['Sec-Websocket-Version'] >= 6) {
return true;
}
}
return false;
}
/** /**
* @return array * @return array
* I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string * I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string

View File

@ -8,6 +8,14 @@ namespace Ratchet\Application\WebSocket\Version;
* The current method names suggest you could create a new message/frame to send, which they can not do * The current method names suggest you could create a new message/frame to send, which they can not do
*/ */
interface VersionInterface { interface VersionInterface {
/**
* Given an HTTP header, determine if this version should handle the protocol
* @param array
* @return bool
* @throws UnderflowException If the protocol thinks the headers are still fragmented
*/
static function isProtocol(array $headers);
/** /**
* Perform the handshake and return the response headers * Perform the handshake and return the response headers
* @param string * @param string
@ -28,6 +36,7 @@ interface VersionInterface {
/** /**
* @param string * @param string
* @return string * @return string
* @todo Change to use other classes, this will be removed eventually
*/ */
function frame($message); function frame($message);
} }

View File

@ -9,6 +9,7 @@ use Ratchet\Application\ApplicationInterface;
*/ */
interface WebSocketAppInterface extends ApplicationInterface { interface WebSocketAppInterface extends ApplicationInterface {
/** /**
* Currently instead of this, I'm setting header in the Connection object passed around...not sure which I like more
* @param string * @param string
*/ */
function setHeaders($headers); function setHeaders($headers);

View File

@ -1,41 +0,0 @@
<?php
namespace Ratchet;
/**
* Observable/Observer design pattern interface for handing events on a socket
* @todo Consider an onDisconnect method for a server-side close()'ing of a connection - onClose would be client side close()
* @todo Is this interface needed anymore?
* @deprecated
*/
interface ObserverInterface {
/**
* When a new connection is opened it will be passed to this method
* @param SocketInterface The socket/connection that just connected to your application
* @return Ratchet\Resource\Command\CommandInterface|null
*/
function onOpen(SocketInterface $conn);
/**
* Triggered when a client sends data through the socket
* @param SocketInterface The socket/connection that sent the message to your application
* @param string The message received
* @return Ratchet\Resource\Command\CommandInterface|null
*/
function onMessage(SocketInterface $from, $msg);
/**
* This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed.
* @param SocketInterface The socket/connection that is closing/closed
* @return Ratchet\Resource\Command\CommandInterface|null
*/
function onClose(SocketInterface $conn);
/**
* If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,
* the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method
* @param SocketInterface
* @param \Exception
* @return Ratchet\Resource\Command\CommandInterface|null
*/
function onError(SocketInterface $conn, \Exception $e);
}

View File

@ -9,7 +9,7 @@ use Ratchet\Application\ApplicationInterface;
interface CommandInterface { interface CommandInterface {
/** /**
* The Server class will call the execution * The Server class will call the execution
* @param Ratchet\ObserverInterface Scope to execute the command under * @param Ratchet\ApplicationInterface Scope to execute the command under
* @return CommandInterface|NULL * @return CommandInterface|NULL
*/ */
function execute(ApplicationInterface $scope = null); function execute(ApplicationInterface $scope = null);

View File

@ -64,7 +64,7 @@ class Socket implements SocketInterface {
$len = strlen($message); $len = strlen($message);
do { do {
$sent = $this->write($message, 4); $sent = $this->write($message, $len);
$len -= $sent; $len -= $sent;
$message = substr($message, $sent); $message = substr($message, $sent);
} while ($len > 0); } while ($len > 0);
@ -72,7 +72,7 @@ class Socket implements SocketInterface {
public function bind($address, $port = 0) { public function bind($address, $port = 0) {
if (false === @socket_bind($this->getResource(), $address, $port)) { if (false === @socket_bind($this->getResource(), $address, $port)) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
@ -85,15 +85,24 @@ class Socket implements SocketInterface {
public function connect($address, $port = 0) { public function connect($address, $port = 0) {
if (false === @socket_connect($this->getResource(), $address, $port)) { if (false === @socket_connect($this->getResource(), $address, $port)) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
} }
public function getRemoteAddress() {
$address = $port = '';
if (false === @socket_getpeername($this->getResource(), $address, $port)) {
throw new Exception($this);
}
return $address;
}
public function get_option($level, $optname) { public function get_option($level, $optname) {
if (false === ($res = @socket_get_option($this->getResource(), $level, $optname))) { if (false === ($res = @socket_get_option($this->getResource(), $level, $optname))) {
throw new Exception; throw new Exception($this);
} }
return $res; return $res;
@ -101,12 +110,20 @@ class Socket implements SocketInterface {
public function listen($backlog = 0) { public function listen($backlog = 0) {
if (false === @socket_listen($this->getResource(), $backlog)) { if (false === @socket_listen($this->getResource(), $backlog)) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
} }
public function read($length, $type = PHP_BINARY_READ) {
if (false === ($res = @socket_read($this->getResource(), $length, $type))) {
throw new Exception($this);
}
return $res;
}
/** /**
* @see http://ca3.php.net/manual/en/function.socket-recv.php * @see http://ca3.php.net/manual/en/function.socket-recv.php
* @param string Variable to write data to * @param string Variable to write data to
@ -150,7 +167,7 @@ class Socket implements SocketInterface {
public function set_block() { public function set_block() {
if (false === @socket_set_block($this->getResource())) { if (false === @socket_set_block($this->getResource())) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
@ -158,7 +175,7 @@ class Socket implements SocketInterface {
public function set_nonblock() { public function set_nonblock() {
if (false === @socket_set_nonblock($this->getResource())) { if (false === @socket_set_nonblock($this->getResource())) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
@ -166,7 +183,7 @@ class Socket implements SocketInterface {
public function set_option($level, $optname, $optval) { public function set_option($level, $optname, $optval) {
if (false === @socket_set_option($this->getResource(), $level, $optname, $optval)) { if (false === @socket_set_option($this->getResource(), $level, $optname, $optval)) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
@ -174,7 +191,7 @@ class Socket implements SocketInterface {
public function shutdown($how = 2) { public function shutdown($how = 2) {
if (false === @socket_shutdown($this->getResource(), $how)) { if (false === @socket_shutdown($this->getResource(), $how)) {
throw new Exception; throw new Exception($this);
} }
return $this; return $this;
@ -182,7 +199,7 @@ class Socket implements SocketInterface {
public function write($buffer, $length = 0) { public function write($buffer, $length = 0) {
if (false === ($res = @socket_write($this->getResource(), $buffer, $length))) { if (false === ($res = @socket_write($this->getResource(), $buffer, $length))) {
throw new Exception; throw new Exception($this);
} }
return $res; return $res;

View File

@ -34,6 +34,7 @@ interface SocketInterface {
// function accept(); // function accept();
/** /**
* Bind the socket instance to an address/port
* @param string * @param string
* @param int * @param int
* @return SocketInterface * @return SocketInterface
@ -47,6 +48,7 @@ interface SocketInterface {
function close(); function close();
/** /**
* Initiates a connection to a socket
* @param string * @param string
* @param int * @param int
* @return SocketInterface * @return SocketInterface
@ -54,6 +56,13 @@ interface SocketInterface {
*/ */
function connect($address, $port = 0); function connect($address, $port = 0);
/**
* Get the address the socket connected from
* @return string
* @throws Exception
*/
function getRemoteAddress();
/** /**
* @param int * @param int
* @param int * @param int
@ -63,12 +72,22 @@ interface SocketInterface {
function get_option($level, $optname); function get_option($level, $optname);
/** /**
* Listen for incoming connections on this socket
* @param int * @param int
* @return SocketInterface * @return SocketInterface
* @throws Exception * @throws Exception
*/ */
function listen($backlog = 0); function listen($backlog = 0);
/**
* Read a maximum of length bytes from a socket
* @param int Number of bytes to read
* @param int Flags
* @return string Data read from the socket
* @throws Exception
*/
function read($length, $type = PHP_BINARY_READ);
/** /**
* Called when the client sends data to the server through the socket * Called when the client sends data to the server through the socket
* @param string Variable to write data to * @param string Variable to write data to
@ -84,12 +103,15 @@ interface SocketInterface {
// function select(array &$read, array &$write, array &$except, $tv_sec, $tv_usec = 0); // function select(array &$read, array &$write, array &$except, $tv_sec, $tv_usec = 0);
/** /**
* Sets the blocking mode on the socket resource
* Wen an operation (receive, send, connect, accept, etc) is performed after set_block() the script will pause execution until the operation is completed
* @return SocketInterface * @return SocketInterface
* @throws Exception * @throws Exception
*/ */
function set_block(); function set_block();
/** /**
* Sets nonblocking mode for socket resource
* @return SocketInterface * @return SocketInterface
* @throws Exception * @throws Exception
*/ */