This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* The SocketHandler class will handle a single socket.
|
||||
* It takes care of the very basic socket functions.
|
||||
* @author jpt
|
||||
* @package Socket
|
||||
*/
|
||||
class Socket_SocketHandler {
|
||||
|
||||
/**
|
||||
* Socket ressource
|
||||
* @var ressource
|
||||
*/
|
||||
protected $socket;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $is_connected;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $is_bound;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $is_listening;
|
||||
|
||||
/**
|
||||
* Default constructor. Sets the socket.
|
||||
* @throws Exception_SocketException
|
||||
* @param ressource $socket
|
||||
* @return void
|
||||
*/
|
||||
function __construct($socket) {
|
||||
if(is_resource($socket) === FALSE) throw new Exception_SocketException("Invalid socket ressource!", 1289663108);
|
||||
$this->socket = $socket;
|
||||
$this->is_bound = FALSE;
|
||||
$this->is_connected = FALSE;
|
||||
$this->is_listening = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor. Closes socket.
|
||||
* @return void
|
||||
*/
|
||||
function __destruct() {
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns socket
|
||||
* @return ressource
|
||||
*/
|
||||
public function getSocket() {
|
||||
return $this->socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isConnected() {
|
||||
return $this->is_connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isListening() {
|
||||
return $this->is_listening;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a specified address.
|
||||
* @throws Exception_SocketException
|
||||
* @param string $address
|
||||
* @param int $port
|
||||
* @return void
|
||||
*/
|
||||
public function connect($address, $port) {
|
||||
if($this->is_connected === TRUE) throw new Exception_SocketException("Socket is already connected!", 1289663170);
|
||||
$result = socket_connect($this->socket, $address, $port);
|
||||
if($result === FALSE) $this->error();
|
||||
$this->is_connected = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the socket to an address + port.
|
||||
* @throws Exception_SocketException
|
||||
* @param string $address
|
||||
* @param int $port
|
||||
* @return void
|
||||
*/
|
||||
public function bind($address, $port) {
|
||||
if($this->is_bound === TRUE) throw new Exception_SocketException("Socket is already bound!", 1289663212);
|
||||
$result = socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);
|
||||
if($result === FALSE) $this->error();
|
||||
$result = socket_bind($this->socket, $address, $port);
|
||||
if($result === FALSE) $this->error();
|
||||
$this->is_bound = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Let's the socket listen for incoming connections.
|
||||
* @throws Exception_SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function listen() {
|
||||
if($this->is_bound === FALSE) throw new Exception_SocketException("Cannot listen on unbound socket!", 1289663220);
|
||||
$result = socket_listen($this->socket);
|
||||
if($result === FALSE) $this->error();
|
||||
$this->is_listening = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the SocketHandler that he got accepted.
|
||||
* @return void
|
||||
*/
|
||||
public function hasBeenAccepted() {
|
||||
$this->is_connected = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a connection to a socket that is bound and listens
|
||||
* The ressource has to be added to the SocketPool manually
|
||||
* @throws Exception_SocketException
|
||||
* @return ressource
|
||||
*/
|
||||
public function accept() {
|
||||
if($this->is_bound === FALSE) throw new Exception_SocketException("Cannot accept connections from unbound socket!", 1289663239);
|
||||
if($this->is_listening === FALSE) throw new Exception_SocketException("Cannot accept connections from socket that is not listening!", 1289663241);
|
||||
$accept = socket_accept($this->socket);
|
||||
if($accept === FALSE) $this->error();
|
||||
return $accept;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ip + port of the remote socket.
|
||||
* @throws Exception_SocketException
|
||||
* @return string
|
||||
*/
|
||||
public function getRemoteName() {
|
||||
if($this->is_connected === FALSE) throw new Exception_SocketException("Socket not connected, cannot retrieve remote name!", 1289928192);
|
||||
$result = socket_getpeername($this->socket, $address, $port);
|
||||
if($result === FALSE) $this->error();
|
||||
return $address . ":" . $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ip + port of the local socket.
|
||||
* @throws Exception_SocketException
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalName() {
|
||||
if($this->is_bound === FALSE ^ $this->is_connected === FALSE) throw new Exception_SocketException("Socket is not bound or connected, no local name available!", 1289928256);
|
||||
$result = socket_getsockname($this->socket, $address, $port);
|
||||
if($result === FALSE) $this->error();
|
||||
return $address . ":" . $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to the socket.
|
||||
* @throws Exception_SocketException
|
||||
* @param string $data
|
||||
* @return void
|
||||
*/
|
||||
public function write($data) {
|
||||
$result = socket_write($this->socket, $data);
|
||||
if($result === FALSE) $this->error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from the socket.
|
||||
* @throws Exception_SocketException
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public function read($length = 16384) {
|
||||
$result = socket_read($this->socket, $length, PHP_BINARY_READ);
|
||||
if($result === FALSE) $this->error();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts the socket down after waiting a bit (waiting might be optional).
|
||||
* @throws Exception_SocketException
|
||||
* @return void
|
||||
*/
|
||||
public function close() {
|
||||
usleep(100000);
|
||||
if($this->is_connected === TRUE) {
|
||||
$result = socket_shutdown($this->socket);
|
||||
if($result === FALSE) $this->error();
|
||||
}
|
||||
if(is_resource($this->socket)) {
|
||||
$result = socket_close($this->socket);
|
||||
if($result === FALSE) $this->error();
|
||||
}
|
||||
$this->is_connected = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets last error from socket.
|
||||
* @throws Exception_SocketException
|
||||
*/
|
||||
protected function error() {
|
||||
$errno = socket_last_error($this->socket);
|
||||
$error = socket_strerror($errno);
|
||||
socket_clear_error();
|
||||
$errormsg = "[" . $errno . "] " . $error;
|
||||
throw new Exception_SocketException("A socket error occured: " . $errormsg, 1289663360);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* The SocketPool class that will handle all the sockets.
|
||||
* Manages a pool of socket ressources with socket_select()
|
||||
* @author jpt
|
||||
* @package Socket
|
||||
*/
|
||||
class Socket_SocketPool {
|
||||
|
||||
/**
|
||||
* Pool that contains socket ressources.
|
||||
* @var array
|
||||
*/
|
||||
protected $sockets;
|
||||
|
||||
/**
|
||||
* Creates sockets.
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
$this->sockets = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all connections.
|
||||
* @return void
|
||||
*/
|
||||
function __destruct() {
|
||||
unset($this->sockets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of active sockets.
|
||||
* @return int
|
||||
*/
|
||||
public function countSockets() {
|
||||
return count($this->sockets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a socket to the pool
|
||||
* @param ressource $add_socket
|
||||
* @return void
|
||||
*/
|
||||
public function addSocket($add_socket) {
|
||||
array_push($this->sockets, $add_socket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given socket from the pool.
|
||||
* The socket will be shutdown.
|
||||
* @param ressource $remove_socket
|
||||
* @return void
|
||||
*/
|
||||
public function removeSocket($remove_socket) {
|
||||
foreach($this->sockets AS $key=>$socket) {
|
||||
if($socket !== $remove_socket) {
|
||||
continue;
|
||||
} else {
|
||||
unset($socket);
|
||||
unset($this->sockets[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TcpSocket and adds it to the pool.
|
||||
* @throws Exception_SocketException
|
||||
* @param boolean $IPv6 will determine whether the socket uses IPv4 or IPv6.
|
||||
* @return ressource
|
||||
*/
|
||||
public function createTcpSocket($IPv6 = FALSE) {
|
||||
$Domain = ($IPv6) ? AF_INET6 : AF_INET;
|
||||
$socket = socket_create($Domain, SOCK_STREAM, SOL_TCP);
|
||||
socket_set_block($socket);
|
||||
if($socket === FALSE) throw new Exception_SocketException("socket_create() failed!", 1290273709);
|
||||
$this->addSocket($socket);
|
||||
return $socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of sockets one can read from.
|
||||
* @param array $read
|
||||
* @param array $write
|
||||
* @param array $except
|
||||
* @param int $timeout
|
||||
* @throws Exception_SocketException
|
||||
* @return array
|
||||
*/
|
||||
public function select($read, $write, $except, $timeout = NULL) {
|
||||
$n = socket_select($read, $write, $except, $timeout);
|
||||
if($n === FALSE) throw new Exception_SocketException("socket_select() failed!", 1290273693);
|
||||
if($n === 0) return array("read" => array(), "write" => array(), "except" => array());
|
||||
return array("read" => $read, "write" => $write, "except" => $except);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user