c linux unix operating-system event-driven

Modelo impulsado por eventos en C



linux unix (5)

"¿Cuál es la filosofía detrás de este modelo?"

Impulsado por evento significa que no hay "monitoreo", pero que el evento en sí inicia la acción.

Por lo general, esto se inicia mediante una interrupción, que es una señal al sistema desde un dispositivo externo, o (en el caso de una interrupción de software) un proceso asíncrono.

https://en.wikipedia.org/wiki/Interrupt

Más lectura parece estar aquí:

https://docs.oracle.com/cd/E19455-01/806-1017/6jab5di2m/index.html#sockets-40 - "E / S de zócalo controlado por interrupción"

También http://cs.baylor.edu/~donahoo/practical/CSockets/textcode.html tiene algunos ejemplos de sockets controlados por interrupciones, así como otros ejemplos de programación de socket.

Estoy realmente interesado en la programación dirigida por eventos en C, especialmente con sockets, así que voy a dedicar algo de tiempo a hacer mis investigaciones.

Supongamos que quiero crear un programa con mucha E / S de archivos y redes como una aplicación cliente / servidor, básicamente la primera pregunta es cuál es la filosofía detrás de este modelo. Mientras que en la programación normal generaría nuevos procesos, ¿por qué un solo proceso puede atender muchas otras solicitudes? Por ejemplo, hay algunos servidores web que pueden manejar conexiones sin crear subprocesos u otros procesos, solo un proceso principal.

Sé que esto es complicado pero siempre es bueno saber al menos cómo es la infraestructura de este tipo de programación.


Definitivamente debe leer lo siguiente: http://www.kegel.com/c10k.html . Esa página es la descripción perfecta de las técnicas controladas por eventos y asíncronas.

Sin embargo, una respuesta rápida y sucia : dirigida por eventos no es sin bloqueo ni asíncrona.

Medios controlados por eventos, que el proceso monitoreará sus descriptores de archivos (y sockets), y actuará solo cuando ocurra algún evento en algún descriptor (los eventos son: datos recibidos, errores, se pueden escribir, ...).

Los sockets BSD tienen la función "seleccionar ()". Cuando se llama, el sistema operativo monitoreará los descriptores y regresará al proceso tan pronto como ocurra algún evento en uno de los descriptores.

Sin embargo, el sitio web anterior tiene descripciones mucho mejores (y detalles sobre las diferentes API).


En realidad es muy específico de la plataforma en cuanto a cómo funciona eso.

Si su ejecución en un sistema Linux realmente no es difícil, simplemente necesita generar una copia de su proceso usando ''fork'', algo como lo siguiente haría el truco:

#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet.h> #include <signal.h> #include <unistd.h> int main() { int server_sockfd, client_sockfd; int server_len, client_len; struct sockaddr_in server_address; struct sockaddr_in client_address; server_sockfd = socket(AF_INET, SOCK_STREAM, 0); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_Address.sin_port = htons(1234); server_len = sizeof(server_address); bind(server_sockfd, (struct sockaddr *)&server_address, server_len); listen(server_sockfd, 5); signal(SIGCHLD, SIG_IGN); while(1) { char ch; printf("Server Waiting/n"); client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len) // Here''s where we do the forking, if you''ve forked already then this will be the child running, if not then your still the parent task. if(fork() == 0) { // Do what ever the child needs to do with the connected client read(client_sockfd, &ch, 1); sleep(5); // just for show :-) ch++; write(client_sockfd, &ch, 1); close(client_sockfd); exit(0); } else { // Parent code here, close and loop for next connection close(client_sockfd); } } }

Puede que tenga que jugar un poco con ese código. No estoy cerca de una caja de Linux en este momento para hacer una compilación de prueba, y casi lo escribí de memoria.

Sin embargo, usar fork es la forma estándar de hacer esto en C bajo un sistema basado en Linux / Unix.

Debajo de Windows es una historia muy diferente, y una que no puedo recordar del todo el código necesario (estoy acostumbrado a codificar en C # en estos días) pero configurar el socket es casi lo mismo, excepto que necesitas usar La API ''Winsock'' para una mejor compatibilidad.

Puedes (creo que de todos modos) aún puedes usar enchufes berkley estándar debajo de las ventanas, pero está lleno de escollos y agujeros, para windows winsock este es un buen lugar para comenzar:

http://tangentsoft.net/wskfaq/

Por lo que yo sé también, si usas Winsock, tiene cosas para ayudar con el desove y el cliente múltiple, personalmente, sin embargo, por lo general, solo apago un hilo separado y copio la conexión del zócalo, luego vuelvo a El bucle escuchando a mi servidor.


La programación dirigida por eventos se basa en un bucle de eventos. El bucle simplemente espera un nuevo evento, envía un código para manejar el evento y luego retrocede para esperar el próximo evento. En el caso de sockets, estamos hablando de "programación de red asíncrona". Esto implica select () o alguna otra opción como Kqueue () para esperar los eventos en el bucle de eventos. Los sockets deberían configurarse para que no se bloqueen , de modo que cuando lea () o escriba () su código no espere a que se complete la E / S.

La programación de red asíncrona puede ser muy compleja y difícil de hacer bien. Echa un vistazo a un par de presentaciones here y here . Recomiendo encarecidamente usar una biblioteca como libevent o liboop para hacer esto bien.


Ese tipo de servidores / clientes TCP se puede implementar utilizando select(2) sockets de llamada y no bloqueantes.

Es más difícil usar sockets no bloqueantes que bloquear sockets.

Ejemplo:

normalmente, la llamada de connect devuelve -1 inmediatamente y establece errno EINPROGRESS cuando se utilizan zócalos sin bloqueo. En este caso, debe usar select para esperar cuando se abre o falla la conexión. connect también puede devolver 0. Esto puede suceder si crea una conexión con el host local. De esta manera puede servir a otros sockets, mientras que un socket está abriendo una conexión TCP.