PHP 可以异步使用套接字吗?

Posted

技术标签:

【中文标题】PHP 可以异步使用套接字吗?【英文标题】:Can PHP asynchronously use sockets? 【发布时间】:2010-11-28 18:47:21 【问题描述】:

典型的 php 套接字功能是同步的,并在等待传入连接和数据时暂停线程。 (例如socket_readsocket_listen

我如何异步执行相同的操作?所以我可以在数据接收事件中响应数据,而不是轮询数据等。

【问题讨论】:

【参考方案1】:

“异步”一词在网络编程中经常被误用。对于 I/O,异步通常只是用作非阻塞的另一个词。这意味着该过程能够在网络 api 上的调用完成传输之前继续。

对于一般的流程执行,异步意味着能够一次(同时)计算多条指令。

换句话说,异步 I/O 不是真正的异步,除非使用多个线程来允许同时发生多个读/写/接受 - 如果有数据,所有套接字都必须等待同步非阻塞调用被读/写或不会阻塞,如果不中断,读/写一个大文件仍然需要几秒钟甚至几分钟。请注意,这将需要客户端和服务器之间的完美流,否则 TCP 本身会中断传输。例如,服务器发送速度快于客户端下载速度会导致写入阻塞。

所以从严格的角度来看,PHP 不能执行异步网络,只能执行非阻塞。简而言之,当网络调用能够有效地读/写等时,进程的进程将停止。但是,当调用无法有效地读/写或以其他方式阻塞时,进程将继续。在真正的异步系统中,进程将继续进行,并且读/写将在不同的线程中完成。请注意,如果在不同的线程中完成,阻塞 I/O 仍然可以异步完成。

此外,如果没有安装支持它的扩展,PHP 无法进行事件驱动 I/O。否则,您将需要进行某种形式的轮询,以便在 PHP 中进行非阻塞 I/O。如果使用 socket_select,来自 Chaos 的代码将是一个功能性非阻塞读取示例。

话虽如此,select 函数仍将允许 PHP 中的真正非阻塞行为。在 C 语言中,轮询服务比事件驱动有性能损失,所以我相信 PHP 也是如此。但是这种损失在纳秒到微秒内,具体取决于套接字的数量,其中从非阻塞调用节省的时间通常是毫秒,如果调用等待则甚至是几秒。

【讨论】:

【参考方案2】:

我如何异步执行相同的操作? 所以我可以响应数据中的数据 收到事件,而不是轮询 数据等

您需要执行脚本并发出 stream_select 以检查是否有任何数据要接收。处理并发送回数据。

【讨论】:

stream_select 与 ops 问题关系不大。流(即底层套接字)需要设置为非阻塞,并且需要保留适当的缓冲区(如果在阻塞事件之前只接收到 1,456 中的 192 个字节会怎样……如果这 192 个字节没有被缓冲以继续在下一次阅读时,它们会丢失)。即使那样它也不是异步的,只是非阻塞的。【参考方案3】:

AFAIK PHP 是严格单线程的,这意味着您不能异步执行此操作,因为脚本执行始终是线性的。

我已经有一段时间没有这样做了,但据我记得,您只能打开套接字,并让脚本在接收到数据后继续执行。

【讨论】:

PHP 为异步套接字操作提供 stream_select,类似于 posix select()。 select() 是同步的:它只是让您知道套接字是否准备好进行读/写。您仍然从单个线程调用它,并阻塞 select() 调用而不是 read() 或 write()。【参考方案4】:

是的,这就是socket_set_nonblock() 的用途。考虑到错误代码 11、EWOULDBLOCK 和 115、EINPROGRESS 所假定的特殊含义,您的套接字交互代码需要以不同方式编写。

根据要求,这是来自 PHP 同步套接字轮询循环的一些虚构的示例代码:

$buf = '';
$done = false;
do 
    $chunk = socket_read($sock, 4096);
    if($chunk === false) 
        $error = socket_last_error($sock);
        if($error != 11 && $error != 115) 
            my_error_handler(socket_strerror($error), $error);
            $done = true;
        
        break;
     elseif($chunk == '') 
        $done = true;
        break;
     else  
        $buf .= $chunk;
    
 while(true);

【讨论】:

你所说的不同是什么意思?你能告诉我任何异步数据接收事件的代码示例吗? 所以这是同步的,但非阻塞的?那么非阻塞到底是什么意思呢? 不,它是异步的,基于轮询的。该代码来自更大的轮询机制。据我所知,PHP 不支持您要求的中断/信号驱动的套接字 I/O 事件。您可以通过使用不等待完成但立即返回的操作来实现异步通信,如果操作未准备好,则带有指示性错误代码。就像在非阻塞套接字上读取一样。有很多关于 C 中异步套接字使用的教程,其中将详细介绍这一点; PHP 的支持只是标准 C 语言的一层。 2012 年 8 月。您认为该方法是否按照 OP 想要的方式进行了更新/改进? 有人可以发布无限非阻塞接收数据的示例代码吗?请问?

以上是关于PHP 可以异步使用套接字吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在连接异步套接字时发送字符串(或特定数字)吗

在 PHP 中打开异步套接字

套接字异步操作会同步完成吗?

C++ winsock服务器中非阻塞模式与异步套接字的区别

异步服务器套接字多个客户端

彗星与 php 套接字服务器?