/** * Initializes a TCP stream resource. * * @param ParametersInterface $parameters Initialization parameters for the connection. * * @return resource */ protected function tcpStreamInitializer(ParametersInterface $parameters) { $uri = "tcp://{$parameters->host}:{$parameters->port}"; $flags = STREAM_CLIENT_CONNECT; if (isset($parameters->async_connect) && (bool) $parameters->async_connect) { $flags |= STREAM_CLIENT_ASYNC_CONNECT; } if (isset($parameters->persistent) && (bool) $parameters->persistent) { $flags |= STREAM_CLIENT_PERSISTENT; $uri .= strpos($path = $parameters->path, '/') === 0 ? $path : "/{$path}"; } $resource = @stream_socket_client($uri, $errno, $errstr, (double) $parameters->timeout, $flags); if (!$resource) { $this->onConnectionError(trim($errstr), $errno); } if (isset($parameters->read_write_timeout)) { $rwtimeout = (double) $parameters->read_write_timeout; $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1; $timeoutSeconds = floor($rwtimeout); $timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000; stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds); } if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) { $socket = socket_import_stream($resource); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay); } return $resource; }
public function listen($port, $host = '127.0.0.1', $protocol = 'tcp') { if (strpos($host, ':') !== false) { // enclose IPv6 addresses in square brackets before appending port $host = '[' . $host . ']'; } $opts = ['socket' => ['backlog' => 1024, 'so_reuseport' => 1]]; $flags = $protocol == 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $context = stream_context_create($opts); $this->master = @stream_socket_server("{$protocol}://{$host}:{$port}", $errorCode, $errorMessage, $flags, $context); if (false === $this->master) { $message = "Could not bind to tcp://{$host}:{$port}: {$errorMessage}"; throw new ConnectionException($message, $errorCode); } // Try to open keep alive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $protocol == 'tcp') { $socket = socket_import_stream($this->master); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); } stream_set_blocking($this->master, 0); $this->loop->addReadStream($this->master, function ($master) { $newSocket = stream_socket_accept($master, 0, $remote_address); if (false === $newSocket) { $this->notifyError(new \RuntimeException('Error accepting new connection')); return; } $this->handleConnection($newSocket); }); return $this; }
public function createReceiver($address) { if (!defined('MCAST_JOIN_GROUP')) { throw new BadMethodCallException('MCAST_JOIN_GROUP not defined (requires PHP 5.4+)'); } if (!function_exists('socket_import_stream')) { throw new BadMethodCallException('Function socket_import_stream missing (requires ext-sockets and PHP 5.4+)'); } $parts = parse_url('udp://' . $address); $stream = @stream_socket_server('udp://0.0.0.0:' . $parts['port'], $errno, $errstr, STREAM_SERVER_BIND); if ($stream === false) { throw new RuntimeException('Unable to create receiving socket: ' . $errstr, $errno); } $socket = socket_import_stream($stream); if ($stream === false) { throw new RuntimeException('Unable to access underlying socket resource'); } // allow multiple processes to bind to the same address $ret = socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); if ($ret === false) { throw new RuntimeException('Unable to enable SO_REUSEADDR'); } // join multicast group and bind to port $ret = socket_set_option($socket, IPPROTO_IP, MCAST_JOIN_GROUP, array('group' => $parts['host'], 'interface' => 0)); if ($ret === false) { throw new RuntimeException('Unable to join multicast group'); } return new DatagramSocket($this->loop, $stream); }
/** * Toggle TCP nodelay flag (nagle algorithm) for the given socket. * * @param resource $socket The socket resource. * @param bool $nodelay New setting fpr tcp_nodelay. * @return bool Returns true when the setting was applied. */ public static function setTcpNoDelay($socket, bool $nodelay) : bool { static $nodelay; static $sockets; if ($nodelay ?? ($nodelay = \version_compare(\PHP_VERSION, '7.1.0', '>='))) { return \stream_context_set_option($socket, 'socket', 'tcp_nodelay', $nodelay); } if ($sockets ?? ($sockets = \extension_loaded('sockets'))) { if ($resource = @\socket_import_stream($socket)) { return @\socket_set_option($resource, \SOL_TCP, \TCP_NODELAY, $nodelay ? 1 : 0); } } return false; }
private function createSocketServer($uri) { $scheme = parse_url($uri, PHP_URL_SCHEME); if ($scheme == 'unix') { $uri = 'unix://' . parse_url($uri, PHP_URL_PATH); } $errno = 0; $errstr = ''; $context = @stream_context_create($this->settings); $server = @stream_socket_server($uri, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context); if (function_exists('socket_import_stream')) { if ($scheme === 'tcp' || $scheme === 'unix') { $socket = socket_import_stream($server); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, (int) $this->keepAlive); if ($scheme === 'tcp') { socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $this->noDelay); } } } if ($server === false) { throw new Exception($errstr, $errno); } return $server; }
/** * Initializes a TCP stream resource. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return resource */ private function tcpStreamInitializer(ConnectionParametersInterface $parameters) { $uri = "tcp://{$parameters->host}:{$parameters->port}/"; $flags = STREAM_CLIENT_CONNECT; if (isset($parameters->async_connect) && $parameters->async_connect) { $flags |= STREAM_CLIENT_ASYNC_CONNECT; } if (isset($parameters->persistent) && $parameters->persistent) { $flags |= STREAM_CLIENT_PERSISTENT; } $resource = @stream_socket_client($uri, $errno, $errstr, $parameters->timeout, $flags); if (!$resource) { $this->onConnectionError(trim($errstr), $errno); } if (isset($parameters->read_write_timeout)) { $rwtimeout = $parameters->read_write_timeout; $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1; $timeoutSeconds = floor($rwtimeout); $timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000; stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds); } if (isset($parameters->tcp_nodelay) && version_compare(PHP_VERSION, '5.4.0') >= 0) { $socket = socket_import_stream($resource); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay); } return $resource; }
/** * {@inheritdoc} */ protected function createStreamSocket(ParametersInterface $parameters, $address, $flags, $context = null) { $socket = null; $timeout = isset($parameters->timeout) ? (double) $parameters->timeout : 5.0; $resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags); if (!$resource) { $this->onConnectionError(trim($errstr), $errno); } if (isset($parameters->read_write_timeout) && function_exists('socket_import_stream')) { $rwtimeout = (double) $parameters->read_write_timeout; $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1; $timeout = array('sec' => $timeoutSeconds = floor($rwtimeout), 'usec' => ($rwtimeout - $timeoutSeconds) * 1000000); $socket = $socket ?: socket_import_stream($resource); @socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout); @socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout); } if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) { $socket = $socket ?: socket_import_stream($resource); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay); } return $resource; }
/** * Creates stream according to options passed in constructor. * * @return resource */ protected function getStream() { if ($this->stream === null) { // TODO: SSL // see https://github.com/nrk/predis/blob/v1.0/src/Connection/StreamConnection.php $uri = "tcp://{$this->options["host"]}:{$this->options["port"]}"; $flags = STREAM_CLIENT_CONNECT; if (isset($this->options["async_connect"]) && !!$this->options["async_connect"]) { $flags |= STREAM_CLIENT_ASYNC_CONNECT; } if (isset($this->options["persistent"]) && !!$this->options["persistent"]) { $flags |= STREAM_CLIENT_PERSISTENT; if (!isset($this->options["path"])) { throw new ClientException("If you need persistent connection, you have to specify 'path' option."); } $uri .= strpos($this->options["path"], "/") === 0 ? $this->options["path"] : "/" . $this->options["path"]; } $this->stream = @stream_socket_client($uri, $errno, $errstr, (double) $this->options["timeout"], $flags); if (!$this->stream) { throw new ClientException("Could not connect to {$this->options["host"]}:{$this->options["port"]}: {$errstr}.", $errno); } if (isset($this->options["read_write_timeout"])) { $readWriteTimeout = (double) $this->options["read_write_timeout"]; if ($readWriteTimeout < 0) { $readWriteTimeout = -1; } $readWriteTimeoutSeconds = floor($readWriteTimeout); $readWriteTimeoutMicroseconds = ($readWriteTimeout - $readWriteTimeoutSeconds) * 10000000.0; stream_set_timeout($this->stream, $readWriteTimeoutSeconds, $readWriteTimeoutMicroseconds); } if (isset($this->options["tcp_nodelay"]) && function_exists("socket_import_stream")) { $socket = socket_import_stream($this->stream); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $this->options["tcp_nodelay"]); } if ($this->options["async"]) { stream_set_blocking($this->stream, 0); } } return $this->stream; }
<?php $stream0 = stream_socket_server("udp://0.0.0.0:58380", $errno, $errstr, STREAM_SERVER_BIND); $sock0 = socket_import_stream($stream0); leak_variable($stream0, true); $stream1 = stream_socket_server("udp://0.0.0.0:58381", $errno, $errstr, STREAM_SERVER_BIND); $sock1 = socket_import_stream($stream1); leak_variable($sock1, true); echo "Done.\n";
function M_Connect(&$conn) { $ctx = stream_context_create(); if ($conn['method'] == M_CONN_SSL) { stream_context_set_option($ctx, 'ssl', 'cafile', $conn['ssl_cafile']); stream_context_set_option($ctx, 'ssl', 'verify_peer', $conn['ssl_verify']); stream_context_set_option($ctx, 'ssl', 'verify_peer_name', $conn['ssl_verify']); stream_context_set_option($ctx, 'ssl', 'allow_self_signed', !$conn['ssl_verify']); stream_context_set_option($ctx, 'ssl', 'disable_compression', true); stream_context_set_option($ctx, 'ssl', 'ciphers', $conn['ssl_ciphers']); stream_context_set_option($ctx, 'ssl', 'SNI_enabled', true); if ($conn['ssl_cert'] != NULL) { stream_context_set_option($ctx, 'ssl', 'local_cert', $conn['ssl_cert']); } if ($conn['ssl_key'] != NULL) { stream_context_set_option($ctx, 'ssl', 'local_pk', $conn['ssl_key']); } } /* Always use TCP, not ssl:// as we need to upgrade it later after we set socket * options for best compatibility */ $url = "tcp://" . $conn['host'] . ":" . $conn['port']; $error = ""; $errorString = ""; $conn['fd'] = @stream_socket_client($url, $error, $errorString, $conn['conn_timeout'], STREAM_CLIENT_CONNECT, $ctx); if (!$conn['fd']) { $conn['conn_error'] = "Failed to connect to {$url}: {$error}: {$errorString}"; return false; } /* Use blocking reads, we'll set timeouts later */ stream_set_blocking($conn['fd'], TRUE); /* Disable the nagle algorithm, should reduce latency */ if (version_compare(PHP_VERSION, '5.4.0') >= 0) { $socket = socket_import_stream($conn['fd']); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) 1); } /* Upgrade the connection to use SSL/TLS. We need to do this *after* setting Nagle due to * bug https://bugs.php.net/bug.php?id=70939 */ if (!stream_socket_enable_crypto($conn['fd'], true, $conn['ssl_protocols'])) { $conn['conn_error'] = "Failed to negotiate SSL/TLS"; fclose($conn['fd']); $conn['fd'] = false; return false; } if ($conn['verify_conn'] && !M_verifyping($conn)) { $conn['conn_error'] = "PING request failed"; fclose($conn['fd']); $conn['fd'] = false; return false; } return true; }
/** * Get the last error from the client socket * * @return string The error string */ private function getLastSocketError() { $errStr = '-1: Unknown error'; if (function_exists('socket_import_stream')) { $socket = socket_import_stream($this->socket); $errCode = socket_last_error($socket); $errStr = $errCode . ': ' . socket_strerror($errCode); } return $errStr; }
/** * Check connection is successfully established or faild. * * @param resource $socket * @return void */ public function checkConnection($socket) { // Check socket state. if ($address = stream_socket_get_name($socket, true)) { // Remove write listener. Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. stream_set_blocking($socket, 0); stream_set_read_buffer($socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $raw_socket = socket_import_stream($socket); socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } // Register a listener waiting read event. Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); // There are some data waiting to send. if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } $this->_status = self::STATUS_ESTABLISH; $this->_remoteAddress = $address; // Try to emit onConnect callback. if ($this->onConnect) { try { call_user_func($this->onConnect, $this); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } // Try to emit protocol::onConnect if (method_exists($this->protocol, 'onConnect')) { try { call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } } else { // Connection failed. $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } if ($this->_status === self::STATUS_CLOSED) { $this->onConnect = null; } } }
<?php var_dump(socket_import_stream()); var_dump(socket_import_stream(1, 2)); var_dump(socket_import_stream(1)); var_dump(socket_import_stream(new stdclass())); var_dump(socket_import_stream(fopen(__FILE__, "rb"))); var_dump(socket_import_stream(socket_create(AF_INET, SOCK_DGRAM, SOL_UDP))); $s = stream_socket_server("udp://127.0.0.1:58392", $errno, $errstr, STREAM_SERVER_BIND); var_dump($s); var_dump(fclose($s)); var_dump(socket_import_stream($s)); echo "Done.";
<?php $stream = stream_socket_server("udp://0.0.0.0:58381", $errno, $errstr, STREAM_SERVER_BIND); $sock = socket_import_stream($stream); var_dump($sock); $so = socket_set_option($sock, IPPROTO_IP, MCAST_JOIN_GROUP, array("group" => '224.0.0.23', "interface" => "lo")); var_dump($so); $sendsock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); var_dump($sendsock); $br = socket_bind($sendsock, '127.0.0.1'); $so = socket_sendto($sendsock, $m = "my message", strlen($m), 0, "224.0.0.23", 58381); var_dump($so); stream_set_blocking($stream, 0); var_dump(fread($stream, strlen($m))); echo "Done.\n";
public function syncSendAndReceive($buffer, stdClass $context) { $client = $this->client; $timeout = $context->timeout / 1000; $sec = floor($timeout); $usec = ($timeout - $sec) * 1000; $trycount = 0; $errno = 0; $errstr = ''; while ($trycount <= 1) { if ($this->stream === null) { $scheme = parse_url($client->uri, PHP_URL_SCHEME); if ($scheme == 'unix') { $this->stream = @pfsockopen('unix://' . parse_url($client->uri, PHP_URL_PATH)); } else { $this->stream = @stream_socket_client($client->uri, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, stream_context_create($client->options)); } if ($this->stream === false) { $this->stream = null; throw new Exception($errstr, $errno); } } $stream = $this->stream; @stream_set_read_buffer($stream, $client->readBuffer); @stream_set_write_buffer($stream, $client->writeBuffer); if (function_exists('socket_import_stream')) { if ($scheme === 'tcp' || $scheme === 'unix') { $socket = socket_import_stream($stream); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, (int) $client->keepAlive); if ($scheme === 'tcp') { socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $client->noDelay); } } } if (@stream_set_timeout($stream, $sec, $usec) == false) { if ($trycount > 0) { throw $this->getLastError("unknown error"); } $trycount++; } else { break; } } if ($this->write($stream, $buffer) === false) { throw $this->getLastError("request write error"); } $response = $this->read($stream, $buffer); if ($response === false) { throw $this->getLastError("response read error"); } return $response; }
/** * 监听端口 * * @throws Exception */ public function listen() { if (!$this->_socketName) { Base::getLog()->error(__METHOD__ . ' missing socket name'); return; } // 获得应用层通讯协议以及监听的地址 $temp = explode(':', $this->_socketName, 2); $scheme = Arr::get($temp, 0); $address = Arr::get($temp, 1); Base::getLog()->debug(__METHOD__ . ' fetch socket info', ['scheme' => $scheme, 'address' => $address]); // 如果有指定应用层协议,则检查对应的协议类是否存在 if ($scheme != 'tcp' && $scheme != 'udp') { // 判断是否有自定义协议 if (isset(self::$protocolMapping[$scheme]) && class_exists(self::$protocolMapping[$scheme])) { $this->_protocol = self::$protocolMapping[$scheme]; } elseif ($this->protocolClass && class_exists($this->protocolClass)) { $this->_protocol = $this->protocolClass; } else { // 没有的话,就按照workerman那套来走 $scheme = ucfirst($scheme); $this->_protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->_protocol)) { $this->_protocol = "\\Workerman\\Protocols\\{$scheme}"; if (!class_exists($this->_protocol)) { throw new Exception("class \\Protocols\\{$scheme} not exist"); } } } } elseif ($scheme === 'udp') { $this->transport = 'udp'; } Base::getLog()->debug(__METHOD__ . ' set protocol', ['class' => $this->_protocol]); // flag $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $errNo = 0; $errmsg = ''; $this->_mainSocket = stream_socket_server($this->transport . ":" . $address, $errNo, $errmsg, $flags, $this->_context); if (!$this->_mainSocket) { throw new Exception($errmsg); } // 尝试打开tcp的keepalive,关闭TCP Nagle算法 if (function_exists('socket_import_stream')) { $socket = socket_import_stream($this->_mainSocket); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_SOCKET, TCP_NODELAY, 1); } // 设置非阻塞 stream_set_blocking($this->_mainSocket, 0); // 放到全局事件轮询中监听_mainSocket可读事件(客户端连接事件) if (self::$globalEvent) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, [$this, 'acceptConnection']); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, [$this, 'acceptUdpConnection']); } } }
/** * Import a stream * * @param resource $stream The stream resource to import. * * @return resource */ public function socketImportStream($stream) { return socket_import_stream($stream); }
/** * 连接服务器 * @throws Exception */ public function connect() { // 获得应用层通讯协议以及目标服务器的地址 $url = parse_url($this->_socketName); if (false === $url) { throw new Exception("invalid socketName"); } // 如果有指定应用层协议,则检查对应的协议类是否存在 $scheme = @$url['scheme']; if ($scheme !== 'tcp') { $scheme = ucfirst($scheme); $this->_protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->_protocol)) { $this->_protocol = "\\WorkerClient\\Protocols\\{$scheme}"; if (!class_exists($this->_protocol)) { throw new Exception("class \\Protocols\\{$scheme} not exist"); } } } // 创建异步连接 $address = @$url['host'] . ':' . @$url['port']; $socket = @stream_socket_client("tcp://{$address}", $errno, $errstr); if (!$socket) { sleep(1); //避免不间断重练 throw new Exception("connect to server failed"); } // 尝试打开tcp的keepalive,关闭TCP Nagle算法 if (function_exists('socket_import_stream')) { $_socket = socket_import_stream($socket); @socket_set_option($_socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($_socket, SOL_SOCKET, TCP_NODELAY, 1); } // 设置非阻塞 stream_set_blocking($socket, 0); $connection = new TcpConnection($socket, $address); $this->connection = $connection; $connection->worker = $this; $connection->protocol = $this->_protocol; $connection->onMessage = $this->onMessage; $connection->onClose = $this->onClose; $connection->onError = $this->onError; $connection->onBufferDrain = $this->onBufferDrain; $connection->onBufferFull = $this->onBufferFull; // 如果有设置连接回调,则执行 if ($this->onConnect) { try { call_user_func($this->onConnect, $connection); } catch (Exception $e) { ConnectionInterface::$statistics['throw_exception']++; self::log($e); } } }
/** * Check connection is successfully established or faild. * * @param resource $socket * @return void */ public function checkConnection($socket) { // Check socket state. if (stream_socket_get_name($socket, true)) { // Remove write listener. Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. stream_set_blocking($socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream')) { $raw_socket = socket_import_stream($socket); socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } // Register a listener waiting read event. Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); // There are some data waiting to send. if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } $this->_status = self::STATUS_ESTABLISH; $this->_remoteAddress = stream_socket_get_name($socket, true); // Try to emit onConnect callback. if ($this->onConnect) { try { call_user_func($this->onConnect, $this); } catch (\Exception $e) { echo $e; exit(250); } } } else { // Connection failed. $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect fail'); $this->destroy(); $this->onConnect = null; } }
/** * @throws \PhpAmqpLib\Exception\AMQPIOException */ protected function enable_keepalive() { if (!function_exists('socket_import_stream')) { throw new AMQPIOException('Can not enable keepalive: function socket_import_stream does not exist'); } if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) { throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined'); } $socket = socket_import_stream($this->sock); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); }
/** * Creates a connected stream socket resource. * * @param ParametersInterface $parameters Connection parameters. * @param string $address Address for stream_socket_client(). * @param int $flags Flags for stream_socket_client(). * * @return resource */ protected function createStreamSocket(ParametersInterface $parameters, $address, $flags) { $timeout = isset($parameters->timeout) ? (double) $parameters->timeout : 5.0; if (!($resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags))) { $this->onConnectionError(trim($errstr), $errno); } if (isset($parameters->read_write_timeout)) { $rwtimeout = (double) $parameters->read_write_timeout; $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1; $timeoutSeconds = floor($rwtimeout); $timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000; stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds); } if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) { $socket = socket_import_stream($resource); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay); } return $resource; }
/** * Imports a stream. * * <p>Imports a stream that encapsulates a socket into a socket extension resource.</p> * * @param resource $stream The stream resource to import. * * @throws Exception\SocketException If the import of the stream is not successful. * * @return Socket Returns a Socket object based on the stream. */ public static function importStream($stream) { $return = @socket_import_stream($stream); if ($return === false || is_null($return)) { throw new SocketException($stream); } return new self($return); }
/** * Listen port. * @throws Exception */ public function listen() { if (!$this->_socketName || $this->_mainSocket) { return; } // Autoload. Autoloader::setRootPath($this->_autoloadRootPath); $local_socket = $this->_socketName; // Get the application layer communication protocol and listening address. list($scheme, $address) = explode(':', $this->_socketName, 2); // Check application layer protocol class. if (!isset(self::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\{$scheme}"; if (!class_exists($this->protocol)) { throw new Exception("class \\Protocols\\{$scheme} not exist"); } } $local_socket = $this->transport . ":" . $address; } else { $this->transport = self::$_builtinTransports[$scheme]; } // Flag. $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $errno = 0; $errmsg = ''; // SO_REUSEPORT. if ($this->reusePort) { stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); } if ($this->transport === 'unix') { umask(0); list($scheme, $address) = explode(':', $this->_socketName, 2); if (!is_file($address)) { register_shutdown_function(function () use($address) { @unlink($address); }); } } // Create an Internet or Unix domain server socket. $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); if (!$this->_mainSocket) { throw new Exception($errmsg); } // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $socket = socket_import_stream($this->_mainSocket); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_SOCKET, TCP_NODELAY, 1); } // Non blocking. stream_set_blocking($this->_mainSocket, 0); // Register a listener to be notified when server socket is ready to read. if (self::$globalEvent) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } }
private function createPool($client, $o) { $n = min(count($o->results), $client->maxPoolSize); $pool = array(); $errno = 0; $errstr = ''; $context = @stream_context_create($client->options); for ($i = 0; $i < $n; $i++) { $scheme = parse_url($client->uri, PHP_URL_SCHEME); if ($scheme == 'unix') { $stream = @fsockopen('unix://' . parse_url($client->uri, PHP_URL_PATH)); } else { $stream = @stream_socket_client($client->uri . '/' . $i, $errno, $errstr, max(0, $o->deadlines[$i] - microtime(true)), STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $context); } if ($stream !== false && @stream_set_blocking($stream, false) !== false) { @stream_set_read_buffer($stream, $client->readBuffer); @stream_set_write_buffer($stream, $client->writeBuffer); if (function_exists('socket_import_stream')) { if ($scheme === 'tcp' || $scheme === 'unix') { $socket = socket_import_stream($stream); socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, (int) $client->keepAlive); if ($scheme === 'tcp') { socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $client->noDelay); } } } $pool[] = $stream; } } if (empty($pool)) { $e = new Exception($errstr, $errno); $results = $o->results; $o->buffers = array(); $o->deadlines = array(); $o->results = array(); foreach ($results as $result) { $result->reject($e); } return false; } return $pool; }
public function yaf_pool_serverAction() { $context_option['socket']['backlog'] = 1024; $context = stream_context_create($context_option); $socket = stream_socket_server('tcp://192.168.80.140:9021', $errno = 0, $errmsg = '', STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context); // 尝试打开tcp的keepalive,关闭TCP Nagle算法 if (function_exists('socket_import_stream')) { $s = socket_import_stream($socket); @socket_set_option($s, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($s, SOL_SOCKET, TCP_NODELAY, 1); } stream_set_blocking($socket, 0); $server = Core_Processpool::create($socket, 4); $server->read = function ($fd) { $recv_buf = ''; while (1) { $buffer = fread($fd, 8192); #echo "123\n"; if ($buffer === '' || $buffer === false) { break; } $recv_buf .= $buffer; } }; $server->write = function ($fd) { $len = fwrite($fd, "ok\n"); }; $server->run(); }
/** * 监听端口 * @throws Exception */ public function listen() { if (!$this->_socketName || $this->_mainSocket) { return; } // 设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); $local_socket = $this->_socketName; // 获得应用层通讯协议以及监听的地址 list($scheme, $address) = explode(':', $this->_socketName, 2); // 如果有指定应用层协议,则检查对应的协议类是否存在 if (!isset(self::$_builtinTransports[$scheme])) { $scheme = ucfirst($scheme); $this->protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->protocol)) { $this->protocol = "\\Workerman\\Protocols\\{$scheme}"; if (!class_exists($this->protocol)) { throw new Exception("class \\Protocols\\{$scheme} not exist"); } } $local_socket = $this->transport . ":" . $address; } else { $this->transport = self::$_builtinTransports[$scheme]; } // flag $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $errno = 0; $errmsg = ''; // 如果设置了端口复用,则设置SO_REUSEPORT选项为1 if ($this->reusePort) { stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1); } if ($this->transport === 'unix') { umask(0); list($scheme, $address) = explode(':', $this->_socketName, 2); if (!is_file($address)) { register_shutdown_function(function () use($address) { @unlink($address); }); } } // 创建监听 $this->_mainSocket = stream_socket_server($local_socket, $errno, $errmsg, $flags, $this->_context); if (!$this->_mainSocket) { throw new Exception($errmsg); } // 尝试打开tcp的keepalive,关闭TCP Nagle算法 if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $socket = socket_import_stream($this->_mainSocket); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_SOCKET, TCP_NODELAY, 1); } // 设置非阻塞 stream_set_blocking($this->_mainSocket, 0); // 放到全局事件轮询中监听_mainSocket可读事件(客户端连接事件) if (self::$globalEvent) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } }
/** * @param $stream * * @return Socket * @throws Exception\Exception_Socket */ public static function importStream($stream) { $return = @socket_import_stream($stream); if ($return === false) { throw new Exception_Socket($stream); } return new self($return); }
/** * Execute the server process * @return object **/ function run() { $fw = \Base::instance(); // Assign signal handlers declare (ticks=1); pcntl_signal(SIGINT, [$this, 'kill']); pcntl_signal(SIGTERM, [$this, 'kill']); gc_enable(); // Activate WebSocket listener $listen = stream_socket_server($this->addr, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $this->ctx); $socket = socket_import_stream($listen); register_shutdown_function(function () use($listen) { foreach ($this->sockets as $socket) { if ($socket != $listen) { $this->free($socket); } } $this->close($listen); if (isset($this->events['stop']) && is_callable($func = $this->events['stop'])) { $func($this); } }); if ($errstr) { user_error($errstr, E_USER_ERROR); } if (isset($this->events['start']) && is_callable($func = $this->events['start'])) { $func($this); } $this->sockets = [$listen]; $empty = []; $wait = $this->wait; while (TRUE) { $active = $this->sockets; $mark = microtime(TRUE); $count = @stream_select($active, $empty, $empty, (int) $wait, round(1000000.0 * ($wait - (int) $wait))); if (is_bool($count) && $wait) { if (isset($this->events['error']) && is_callable($func = $this->events['error'])) { $func($this); } die; } if ($count) { // Process active connections foreach ($active as $socket) { if (!is_resource($socket)) { continue; } if ($socket == $listen) { if ($socket = @stream_socket_accept($listen, 0)) { $this->alloc($socket); } else { if (isset($this->events['error']) && is_callable($func = $this->events['error'])) { $func($this); } } } else { $id = (int) $socket; if (isset($this->agents[$id]) && ($raw = $this->agents[$id]->fetch())) { list($op, $data) = $raw; // Dispatch switch ($op & self::OpCode) { case self::Ping: $this->agents[$id]->send(self::Pong); break; case self::Close: $this->free($socket); break; case self::Text: $data = trim($data); case self::Binary: if (isset($this->events['receive']) && is_callable($func = $this->events['receive'])) { $func($this->agents[$id], $op, $data); } break; } } } } $wait -= microtime(TRUE) - $mark; while ($wait < 1.0E-6) { $wait += $this->wait; $count = 0; } } if (!$count) { $mark = microtime(TRUE); foreach ($this->sockets as $socket) { if (!is_resource($socket)) { continue; } $id = (int) $socket; if ($socket != $listen && isset($this->agents[$id]) && isset($this->events['idle']) && is_callable($func = $this->events['idle'])) { $func($this->agents[$id]); } } $wait = $this->wait - microtime(TRUE) + $mark; } gc_collect_cycles(); } }
/** * 监听端口 * @throws Exception */ public function listen() { // 设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); if (!$this->_socketName) { return; } // 获得应用层通讯协议以及监听的地址 list($scheme, $address) = explode(':', $this->_socketName, 2); // 如果有指定应用层协议,则检查对应的协议类是否存在 if ($scheme != 'tcp' && $scheme != 'udp') { $scheme = ucfirst($scheme); $this->_protocol = '\\Protocols\\' . $scheme; if (!class_exists($this->_protocol)) { $this->_protocol = "\\Workerman\\Protocols\\{$scheme}"; if (!class_exists($this->_protocol)) { throw new Exception("class \\Protocols\\{$scheme} not exist"); } } } elseif ($scheme === 'udp') { $this->transport = 'udp'; } // flag $flags = $this->transport === 'udp' ? STREAM_SERVER_BIND : STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; $this->_mainSocket = stream_socket_server($this->transport . ":" . $address, $errno, $errmsg, $flags, $this->_context); if (!$this->_mainSocket) { throw new Exception($errmsg); } // 尝试打开tcp的keepalive,关闭TCP Nagle算法 if (function_exists('socket_import_stream')) { $socket = socket_import_stream($this->_mainSocket); @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1); @socket_set_option($socket, SOL_SOCKET, TCP_NODELAY, 1); } // 设置非阻塞 stream_set_blocking($this->_mainSocket, 0); // 放到全局事件轮询中监听_mainSocket可读事件(客户端连接事件) if (self::$globalEvent) { if ($this->transport !== 'udp') { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection')); } else { self::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection')); } } }
echo "socket_get_option "; print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE)); echo "\n"; } echo "\n"; } echo "normal\n"; $stream0 = stream_socket_server("udp://0.0.0.0:58380", $errno, $errstr, STREAM_SERVER_BIND); $sock0 = socket_import_stream($stream0); test($stream0, $sock0); echo "\nunset stream\n"; $stream1 = stream_socket_server("udp://0.0.0.0:58381", $errno, $errstr, STREAM_SERVER_BIND); $sock1 = socket_import_stream($stream1); unset($stream1); test(null, $sock1); echo "\nunset socket\n"; $stream2 = stream_socket_server("udp://0.0.0.0:58382", $errno, $errstr, STREAM_SERVER_BIND); $sock2 = socket_import_stream($stream2); unset($sock2); test($stream2, null); echo "\nclose stream\n"; $stream3 = stream_socket_server("udp://0.0.0.0:58383", $errno, $errstr, STREAM_SERVER_BIND); $sock3 = socket_import_stream($stream3); fclose($stream3); test($stream3, $sock3); echo "\nclose socket\n"; $stream4 = stream_socket_server("udp://0.0.0.0:58384", $errno, $errstr, STREAM_SERVER_BIND); $sock4 = socket_import_stream($stream4); socket_close($sock4); test($stream4, $sock4); echo "Done.\n";