146 lines
3.3 KiB
PHP
146 lines
3.3 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace App\Classes\Sock;
|
||
|
|
||
|
use Illuminate\Support\Facades\Log;
|
||
|
|
||
|
final class SocketClient {
|
||
|
public \Socket $connection; // @todo make private
|
||
|
private string $address = '';
|
||
|
private int $port = 0;
|
||
|
|
||
|
public function __construct (\Socket $connection) {
|
||
|
socket_getsockname($connection,$this->address,$this->port);
|
||
|
Log::info(sprintf('Connection from [%s] on port [%d]',$this->address,$this->port),['m'=>__METHOD__]);
|
||
|
|
||
|
$this->connection = $connection;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $timeout
|
||
|
* @return int
|
||
|
*/
|
||
|
public function canSend(int $timeout): int
|
||
|
{
|
||
|
$write = [$this->connection];
|
||
|
|
||
|
return $this->socketSelect(NULL,$write,NULL,$timeout);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Close the connection with the client
|
||
|
*/
|
||
|
public function close(): void
|
||
|
{
|
||
|
socket_shutdown($this->connection);
|
||
|
socket_close($this->connection);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a client socket
|
||
|
* @return static
|
||
|
*/
|
||
|
public static function create(string $address,int $port): self
|
||
|
{
|
||
|
Log::debug(sprintf('Creating connection to [%s:%d]',$address,$port));
|
||
|
|
||
|
$address = gethostbyname($address);
|
||
|
|
||
|
/* Create a TCP/IP socket. */
|
||
|
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
|
||
|
if ($socket === FALSE)
|
||
|
throw new SocketException(SocketException::CANT_CREATE_SOCKET,socket_strerror(socket_last_error($socket)));
|
||
|
|
||
|
$result = socket_connect($socket,$address,$port);
|
||
|
if ($result === FALSE)
|
||
|
throw new SocketException(SocketException::CANT_CONNECT,socket_strerror(socket_last_error($socket)));
|
||
|
|
||
|
return new self($socket);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the client's address
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getAddress(): string
|
||
|
{
|
||
|
return $this->address;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the port in use
|
||
|
*
|
||
|
* @return int
|
||
|
*/
|
||
|
public function getPort(): int
|
||
|
{
|
||
|
return $this->port;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $timeout
|
||
|
* @return int
|
||
|
* @note use socketSelect()
|
||
|
* @todo Node used by bink yet?
|
||
|
* @todo to test
|
||
|
*/
|
||
|
public function hasData(int $timeout): int
|
||
|
{
|
||
|
$read = [$this->connection];
|
||
|
$write = $except = NULL;
|
||
|
|
||
|
//$rc = socket_select($read,$write,$except,$timeout);
|
||
|
//return $rc;
|
||
|
return $this->socketSelect($read,NULL,NULL,$timeout);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send data to the client
|
||
|
*
|
||
|
* @param $message
|
||
|
* @param int $timeout
|
||
|
* @param null $length
|
||
|
* @return false|int
|
||
|
*/
|
||
|
public function send($message,int $timeout,$length=NULL) {
|
||
|
if ($timeout AND (! $rc = $this->canSend($timeout)))
|
||
|
return $rc;
|
||
|
|
||
|
if (is_null($length))
|
||
|
$length = strlen($message);
|
||
|
|
||
|
return socket_write($this->connection,$message,$length);
|
||
|
}
|
||
|
|
||
|
private function socketSelect(?array $read,?array $write,?array $except,int $timeout): int
|
||
|
{
|
||
|
return socket_select($read,$write,$except,$timeout);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read data from the socket.
|
||
|
* If we only want 1 character, we'll return the ASCII value of the data received
|
||
|
*
|
||
|
* @param int $timeout
|
||
|
* @param int $len
|
||
|
* @return false|int|string|null
|
||
|
*/
|
||
|
public function read(int $timeout,int $len=1024)
|
||
|
{
|
||
|
Log::debug(sprintf('+ Start [%d]',$len),['m'=>__METHOD__]);
|
||
|
|
||
|
if ($timeout AND (! $rc = $this->hasData($timeout)))
|
||
|
return $rc;
|
||
|
|
||
|
if (($buf=socket_read($this->connection,$len,PHP_BINARY_READ)) === FALSE) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Log::debug(sprintf(' - Read [%d]',strlen($buf)),['m'=>__METHOD__]);
|
||
|
|
||
|
// For single character reads, we'll return the ASCII value of the buf
|
||
|
return ($len == 1 and (ord($buf) != 0)) ? ord($buf) : $buf;
|
||
|
}
|
||
|
}
|