如何加密非阻塞PHP socket流?(How to encrypt non-blocking PH

2019-06-25 06:33发布

我试图使用PHP的stream_socket_client()函数在非阻塞(异步)方式。 在PHP网站的文档表明STREAM_CLIENT_ASYNC_CONNECT选项标志应该启用这个功能。 但是,下面的代码...

$start_time = microtime(true);
$sockets[$i] = stream_socket_client('ssl://74.125.47.109:993', $errint, $errstr, 1, STREAM_CLIENT_ASYNC_CONNECT);
$end_time = microtime(true);
echo "Total time taken: " . ($end_time-$start_time) . " secs.";

输出以下内容:

Total time taken: 0.76204109191895 secs.

显然,该函数阻止(也被事实STREAM_CLIENT_ASYC_CONNECT标志都这么不有意义改变脚本输出“拍摄总时间”的支持。

为什么这可能发生的任何想法,以及如何执行非阻塞的连接尝试?

Answer 1:

为什么SSL://封装方法行不通...

这是不可能的使用SSL://家庭流包装的建立,此时无阻塞PHP连接,原因很简单:

要建立SSL / TLS握手,你必须同时发送和接收数据。

你根本无法进行双面打印这样的信息的单一操作中(例如什么流包装做)不阻塞脚本执行。 而且因为PHP最初被设计为功能的严格同步环境(即阻止Web SAPIs每个请求都具有其自己的进程),这阻塞行为是应该做的自然的事情。

其结果是,在SSL://流包装将不能工作你想怎么即使你设置STREAM_CLIENT_ASYNC_CONNECT标志它。 然而,它仍然有可能在你的非阻塞套接字操作使用PHP的流加密功能。

如何使你的非阻塞socket流加密...

在SSL / TLS协议对底层数据传输协议之上执行。 这意味着,我们只启用了TCP / UDP /等之后的加密协议。 建立连接。 其结果是,我们能够首先使用STREAM_CLIENT_ASYC_CONNECT异步标志连接到远程方,并随后使加密的(已连接)使用套接字stream_socket_enable_crypto()

简单的例子SANS错误处理

这个例子假设您了解如何使用stream_select()或同等描述符通知LIB在非阻塞的方式与插座工作)。 没有处理潜在的套接字错误。

<?php // connect + encrypt a socket asynchronously

$uri = 'tcp://www.google.com:443';
$timeout = 42;
$flags = STREAM_CLIENT_ASYNC_CONNECT;
$socket = stream_socket_client($uri, $errno, $errstr, $timeout, $flags);
stream_set_blocking($socket, false);

// Once the async connection is actually established it will be "writable."
// Here we use stream_select to find out when the socket becomes writable.
while (1) {
    $w = [$socket];
    $r = $e = [];
    if (stream_select($r, $w, $e, 30, 0)) {
        break; // the async connect is finished
    }
}

// Now that our socket is connected lets enable crypto
$crypto = STREAM_CRYPTO_METHOD_TLS_CLIENT;
while (1) {
    $w = [$socket];
    $r = $e = [];
    if (stream_select($r, $w, $e, 30, 0)) {
        break; // the async connect is finished
        $result = stream_socket_enable_crypto($socket, $enable=true, $crypto);
        if ($result === true) {
            // Crypto enabled, we're finished!
            break;
        } elseif ($result === false) {
            die("crypto failed :(");
        } else {
            // handshake isn't finished yet. Do another trip around the loop.
        }
    }
}

// Send/receive encrypted data on $socket here

注意在返回值

这是非常重要的使用===检查从我们的加密使通话时的结果平等。 正如有关手工录入提到:

如果协商不成或者0,如果没有足够的数据,你应该再试一次(仅适用于非阻塞套接字)返回TRUE成功,FALSE。

如果我们不使用===我们不能区分false0



文章来源: How to encrypt non-blocking PHP socket streams?
标签: php sockets ssl