clrghouz/app/Classes/Sock/SocketServer.php
2021-06-13 01:31:32 +10:00

114 lines
2.8 KiB
PHP

<?php
namespace App\Classes\Sock;
use Illuminate\Support\Facades\Log;
final class SocketServer {
private $server; // Our server resource
private string $bind; // The IP address to bind to
private int $port; // The Port to bind to
private int $backlog = 5; // Number of incoming connections queued
private array $handler; // The class and method that will handle our connection
public function __construct(int $port,string $bind='0.0.0.0')
{
$this->bind = $bind;
$this->port = $port;
$this->_init();
}
/**
* Bind to our Socket
*
* @throws SocketException
*/
private function _bindSocket(): void
{
if (socket_bind($this->server,$this->bind,$this->port) === FALSE)
throw new SocketException(SocketException::CANT_BIND_SOCKET,socket_strerror(socket_last_error($this->server)));
}
/**
* Create our Socket
*
* @throws SocketException
*/
private function _createSocket(): void
{
/**
* Check dependencies
*/
if (! extension_loaded('sockets'))
throw new SocketException(SocketException::CANT_ACCEPT,'Missing sockets extension');
if (! extension_loaded('pcntl'))
throw new SocketException(SocketException::CANT_ACCEPT,'Missing pcntl extension');
$this->server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if ($this->server === FALSE)
throw new SocketException(SocketException::CANT_CREATE_SOCKET,socket_strerror(socket_last_error()));
socket_set_option($this->server,SOL_SOCKET,SO_REUSEADDR,1);
}
/**
* Setup Socket and Bind
*
* @throws SocketException
*/
private function _init(): void
{
$this->_createSocket();
$this->_bindSocket();
}
/**
* Our main loop where we listen for connections
*
* @throws SocketException
*/
public function listen()
{
if (! $this->handler)
throw new SocketException(SocketException::CANT_LISTEN,'Handler not set.');
if (socket_listen($this->server,$this->backlog) === FALSE)
throw new SocketException(SocketException::CANT_LISTEN,socket_strerror(socket_last_error($this->server)));
Log::info(sprintf('Listening on [%s:%d]',$this->bind,$this->port),['m'=>__METHOD__]);
$this->loop();
socket_close($this->server);
Log::info(sprintf('CLosed [%s:%d]',$this->bind,$this->port),['m'=>__METHOD__]);
}
/**
* Manage and execute incoming connecitons
*
* @throws SocketException
*/
private function loop()
{
while (TRUE) {
if (($accept = socket_accept($this->server)) === FALSE)
throw new SocketException(SocketException::CANT_ACCEPT,socket_strerror(socket_last_error($this->server)));
$this->handler[0]->{$this->handler[1]}(new SocketClient($accept));
}
}
/**
* Set our connection handler Class and Method
*
* @param array $handler
*/
public function setConnectionHandler(array $handler): void
{
$this->handler = $handler;
}
}