典型的PHP套接字功能是同步的,并在等待传入连接和数据时停止线程。 (例如socket_read
和socket_listen
)
如何异步执行相同的操作?所以我可以响应数据接收事件中的数据,而不是轮询数据等。
答案 0 :(得分:18)
是的,这就是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);
答案 1 :(得分:4)
如何异步执行相同的操作? 所以我可以回复数据中的数据 收到的事件,而不是轮询 数据等
您需要执行脚本并发出stream_select以检查是否有任何数据要接收。处理并发回数据。
答案 2 :(得分:4)
术语“异步”经常在网络编程中被滥用。对于I / O,异步通常仅用作非阻塞的另一个单词。这意味着该过程能够在网络api上的呼叫完成传输之前继续。
对于一般的流程执行,异步意味着可以一次计算多个指令(同时执行。)
换句话说,异步I / O并非真正异步,除非使用多个线程允许多个读/写/接受同时发生 - 如果有数据,所有套接字必须等待同步非阻塞调用要读/写或不会阻塞,如果没有中断,读/写大文件仍然需要几秒甚至几分钟。请注意,这将需要客户端和服务器之间的完美流程,否则TCP本身将中断传输。例如,发送速度超过客户端可以下载的服务器会导致写入时阻塞。
因此从严格的角度来看,PHP无法执行异步网络,只能进行非阻塞。简而言之,当网络调用能够有效地读/写等时,过程的进展将停止。但是,当调用无法有效地读/写或以其他方式阻塞时,该过程将继续。在一个真正的异步系统中,该过程将继续,并且读/写将在不同的线程中完成。请注意,如果在不同的线程中完成,阻塞I / O仍然可以异步完成。
此外,如果不安装支持它的扩展,PHP无法执行事件驱动的I / O.否则,您需要进行某种形式的轮询才能在PHP中执行非阻塞I / O.如果使用socket_select,Chaos中的代码将是一个功能性非阻塞读取示例。
话虽如此,select函数仍然允许在PHP中实现真正的非阻塞行为。在C中,轮询服务在事件驱动下会有性能损失,因此我确信它对PHP来说是相同的。但是这个损失是纳秒 - 微秒,具体取决于套接字的数量,其中从非阻塞呼叫节省的时间通常是毫秒,或者如果呼叫等待,则甚至是秒。
答案 3 :(得分:0)
AFAIK PHP是严格单线程的,这意味着您无法异步执行此操作,因为脚本执行始终是线性的。
我已经做了一段时间了,但据我记得,你只能打开套接字,让脚本在接收数据时继续执行。