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

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

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

【问题讨论】:

    标签: php sockets scripting asynchronous webserver


    【解决方案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 想要的方式进行了更新/改进?
      • 有人可以发布无限非阻塞接收数据的示例代码吗?请问?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多