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; } }