spatie guzzlehttp await async php sockets scripting asynchronous webserver

guzzlehttp - ¿PHP puede usar sockets asincrónicamente?



php rest client (4)

La funcionalidad típica de socket PHP es sincrónica y detiene el hilo cuando espera las conexiones y datos entrantes. (por ejemplo, socket_read y socket_listen )

¿Cómo hago lo mismo de forma asíncrona? así que puedo responder a los datos en un evento de datos recibidos, en lugar de sondear los datos, etc.


¿Cómo hago lo mismo de forma asíncrona? así que puedo responder a los datos en un evento de datos recibidos, en lugar de sondear los datos, etc.

Deberá ejecutar su secuencia de comandos y emitir stream_select para verificar si hay datos para recibir. Procesar y enviar datos de vuelta.


AFAIK PHP es estrictamente simple, lo que significa que no puede hacer esto de forma asíncrona, porque la ejecución del Script es siempre lineal.

Ha pasado un tiempo desde que hice esto, pero que yo recuerde, solo puede abrir el socket y hacer que el script continúe la ejecución al recibir los datos.


El término "asíncrono" a menudo se usa incorrectamente en la programación de red. Para E / S, asíncrono a menudo se usa como otra palabra para no bloquear. Esto significa que el proceso puede continuar antes de que una llamada en la api de la red haya completado la transmisión.

Para la ejecución del proceso en general, asíncrono significa que se pueden calcular varias instrucciones a la vez (simultáneamente).

En otras palabras, la E / S asíncrona no es realmente asíncrona a menos que se utilicen múltiples subprocesos para permitir que se realicen múltiples lecturas / grabaciones / aceptaciones al mismo tiempo. / escrito o no bloqueará, y leer / escribir un archivo grande aún puede tomar segundos o incluso minutos si no se interrumpe. Tenga en cuenta que esto requeriría un flujo perfecto entre el cliente y el servidor o el propio TCP interrumpirá la transmisión. Por ejemplo, un servidor que envía más rápido de lo que un cliente puede descargar causaría un bloqueo en una escritura.

Por lo tanto, desde un punto de vista estricto, PHP no puede realizar redes asíncronas, solo no bloquear. En resumen, la progresión del proceso se detendrá mientras la llamada de la red pueda leer / escribir, etc. Sin embargo, el proceso continuará cuando la llamada no pueda leer / escribir o se bloquee de otro modo. En un sistema verdaderamente asíncrono, el proceso continuará independientemente, y la lectura / escritura se realizará en un hilo diferente. Tenga en cuenta que el bloqueo de E / S todavía se puede realizar de forma asíncrona si se realiza en un subproceso diferente.

Además, PHP no puede hacer E / S controladas por eventos sin instalar una extensión que lo admita. De lo contrario, tendrá que realizar algún tipo de sondeo para realizar E / S sin bloqueo en PHP. El código de Chaos sería un ejemplo de lectura funcional no bloqueante si usara socket_select.

Dicho esto, la función de selección seguirá permitiendo un verdadero comportamiento de no bloqueo en PHP. En C, los servicios de sondeo tienen una pérdida de rendimiento en función de los eventos, por lo que estoy seguro de que sería lo mismo para PHP. Pero esta pérdida está en los microsegundos de nanosegundos, dependiendo de la cantidad de sockets, donde el tiempo ahorrado de una llamada no bloqueada es generalmente de milisegundos, o incluso de segundos, si se realiza la llamada para esperar.


Sí, para eso está socket_set_nonblock() . El código de interacción del zócalo deberá escribirse de manera diferente, teniendo en cuenta los significados especiales que los códigos de error 11, EWOULDBLOCK y 115, EINPROGRESS , asumen.

Aquí hay un código de ejemplo un tanto ficticio de un bucle de sondeo de socket de sincronización de PHP, según se solicita:

$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);