/**
  * 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;
 }
Exemple #2
0
 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;
 }
Exemple #3
0
 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);
 }
Exemple #4
0
 /**
  * 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;
 }
Exemple #5
0
 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;
 }
Exemple #6
0
 /**
  * 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";
Exemple #10
0
 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";
Exemple #15
0
 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;
 }
Exemple #16
0
 /**
  * 监听端口
  *
  * @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);
 }
Exemple #18
0
 /**
  * 连接服务器
  * @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;
     }
 }
Exemple #20
0
 /**
  * @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);
 }
Exemple #21
0
 /**
  * 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;
 }
Exemple #22
0
 /**
  * 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);
 }
Exemple #23
0
 /**
  * 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'));
         }
     }
 }
Exemple #24
0
 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;
 }
Exemple #25
0
 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();
 }
Exemple #26
0
 /**
  * 监听端口
  * @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'));
         }
     }
 }
Exemple #27
0
 /**
  * @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);
 }
Exemple #28
0
 /**
  *	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();
     }
 }
Exemple #29
0
 /**
  * 监听端口
  * @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";