protected function connectToAddress(string $address, float $timeout, bool $encrypt) { $url = \sprintf('%s://%s', $this->protocol, $address); $errno = null; $errstr = null; $context = \stream_context_create(\array_replace_recursive($this->options, ['socket' => ['connect' => $address]])); $socket = @\stream_socket_client($url, $errno, $errstr, $timeout ?: null, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT, $context); if (!\is_resource($socket)) { throw new SocketException(\sprintf('Could not connect to "%s" (%s): [%s] %s', $url, $this->peer, $errno, \trim($errstr))); } try { \stream_set_blocking($socket, false); \stream_set_read_buffer($socket, 0); \stream_set_write_buffer($socket, 0); if ($this->tcpNoDelay) { Socket::setTcpNoDelay($socket, true); } if ($encrypt) { yield from $this->encryptSocketClient($socket, $timeout); } else { (yield new AwaitWrite($socket, $timeout)); } return $socket; } catch (\Throwable $e) { Socket::shutdown($socket); throw $e; } }
/** * Set TCP nodelay setting (nagle algorithm) of the underlying socket resource. * * @param bool $nodelay * @return bool */ public function setTcpNoDelay(bool $nodelay) : bool { if (\is_resource($this->socket)) { return Socket::setTcpNoDelay($this->socket, $nodelay); } return false; }
protected function listenLoop(callable $callback, float $timeout) : \Generator { while (true) { try { (yield $this->waiting = new AwaitRead($this->socket)); } finally { $this->waiting = null; } $socket = @\stream_socket_accept($this->socket, 0); if (false !== $socket) { \stream_set_blocking($socket, false); \stream_set_read_buffer($socket, 0); \stream_set_write_buffer($socket, 0); if ($this->tcpNoDelay) { Socket::setTcpNoDelay($socket, true); } // Offload handling the client to another coroutine keeping the listen loop running. new Coroutine($this->handleClient($callback, $socket, $timeout), true); } } }