[Original] Introducción a varios modelos del lado del servidor: modelo de reactor (introducción a epoll)
En términos generales, para los descriptores, puede cambiarlos usted mismo a través de epoll_ctl. En términos generales, para un descriptor, puede utilizar la operación | para combinarlos. Agregue un descriptor y escuche para ver si se puede leer o escribir. EPOLLIN | EPOLLOUT Tenga en cuenta ptr o fd en epoll_data_t, no ptr y fd. La estructura solo puede contener uno de estos, por lo que al registrar un evento en el descriptor correspondiente, registre el descriptor correspondiente, fd, o registre el contenedor de eventos correspondiente. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); el primer parámetro es el descriptor de epoll y el segundo parámetro es un puntero a struct epoll_event, que debe pasarse en forma de matriz. , con tipo epoll_event. El tercer parámetro es el valor máximo de la matriz de eventos de escucha. El cuarto es el tiempo de espera. Para Nginx o muchas formas de administración de tiempo de espera, como libevent, se utilizan árboles rojo-negro y montón mínimo para administrar el tiempo de espera. Escribiré una publicación de blog para presentarlo en el futuro. Aquí solo necesita saber el tiempo de espera. Es el valor máximo del bloqueo epoll_wait. Si excede este valor independientemente de si se devuelve un evento, 0 significa regresar inmediatamente, es decir, no se devuelve ningún evento y -1 es permanente. . Evento o no, 0 significa retorno inmediato, es decir, retorno si hay evento o no, -1 significa bloqueo permanente.
Una estructura de demostración de epoll simple epoll_event ev, events[1024]; epfd=epoll_create(1024); for(;;) { nfds = epoll_wait(epfd, events, 1024, time_value); ) { if(events[i].data.fd==listenfd) /* Si hay eventos en el descriptor de escucha agregado*/ { connfd = aceptar(listenfd, (sockaddr *)amp; clientaddr, amp; clilen) /; * Acepte la conexión y obtenga el descriptor del enlace, agregue el descriptor a la cola de eventos de escucha de epoll */
setnonblocking(connfd); ev.data.fd=connfd ev.data.fd=EPOLLIN| }; ev.data.fd=EPOLLIN|EPOLLIN}; ev.data.fd=EPOLLIN|EPOLLIN}; ev.data.fd=EPOLLIN|EPOLLINEvents=EPOLLIN|EPOLLET /* Leer eventos**/ epoll_ctl (epfd, EPOLL_CTL_ADD; , connfd, amp; ev); /* Agregar nuevo fd a la cola de escucha de epoll */ } else if(events[i].eventsamp; EPOLLIN) //recibir datos, leer socket { n = read(sockfd, line, MAXLINE) ) lt; 0 ev.data.ptr = mi_ev; // ev.data.ptr = mi_ev; // ev.data.ptr = mi_ev; // ev.data.ptr = mi_ev; my_ev; // ev.data.ptr = my_ev; // ev.data.ptr = my_evptr = my_ev; //ev puede ser un contenedor de eventos personalizado o fd ev.events=EPOLLOUT|EPOLLET( epfd, EPOLL_CTL_MOD, sockfd , amp; ev); /*Modifica el identificador y espera el siguiente ciclo para enviar datos*/ } else if(events[i].eventsamp; EPOLLOUT) /* Se puede escribir el descriptor correspondiente, es decir, struct my_event* my_ev= (my_event*)eventos[i].data.ptr; sockfd = my_ev-gt; fd; enviar( sockfd, ev-gt; ptr, strlen((char*)my_ev-gt; ptr), 0) ; .data.fd=sockfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, amp; ev); else { // }.}} EPOLL aún no se ha aclarado, y hay muchos más Otro contenido. Solo quiero que los lectores que no conocen los eventos asincrónicos y el patrón del reactor comprendan este patrón.
Cabe señalar que en este modo, el descriptor de conexión debe configurarse en modo sin bloqueo y luego la función de operación de IO debe registrar el estado de cada lectura y escritura. Si el búfer está lleno, el estado debe ser. Cuando se registra y se devuelve a este descriptor la próxima vez, la transmisión o lectura continuará desde el estado anterior, porque el búfer del socket lee los datos de la capa de aplicación y, si los datos de la capa TCP son relativamente grandes, se producirá fragmentación. Si los datos de la capa TCP son grandes, la fragmentación hará que el búfer del socket no pueda leer o escribir todos los datos a la vez y el búfer del socket se llenará. El modo que debe seleccionar es el modo de disparo horizontal LT. Si es el modo de activación de borde ET, después de leer o escribir en el socket una vez, si el búfer está lleno y la escritura no puede continuar, epoll_wait ya no continuará regresando y no se requiere grabación de la máquina de estado. Resumen: lo anterior es solo una breve introducción a epoll. Si hay algún error, hágamelo saber. Espero que a los expertos no les importe. Después de comenzar, habrá una introducción al marco del reactor. Si se utiliza la encapsulación de eventos y la configuración de funciones de devolución de llamada, esto es solo una demostración, no escrita por mí. Eso es todo por hoy