IOCP, kqueue, epoll ... ¿Qué tan importante es?

  

Al diseñar el servidor mmo, he escuchado muchos clichés acerca de cuán ineficiente es la selección cuando se trata de muchas conexiones. Debemos cambiar a iocp (windows), kqueue (freebsd) o epoll (linux). De hecho, al seleccionar una gran cantidad de conexiones para leer y escribir, la selección es ineficiente. Debido a que el kernel tiene que sondear el conjunto de números de socket pasados ​​por selecto cada vez, luego en Shanghai, en el caso de Chen Yu, esto se llama la estrategia del diablo. Preguntado una y otra vez "¿Demonios en la aldea? ", " ¿Demonios en el pueblo? " ... Se ha gastado mucho tiempo de CPU.
(Además, en Windows, hay un límite siniestro de 64).

Usando kqueue, estas personas se convierten en personas para ir a la publicación, los demonios pueden recibir notificaciones, la eficiencia es naturalmente alta Muchos Pero recientemente estuve reconsiderando. ¿Realmente necesitas construir un servidor basado en estos?

Una de las ideas que se acaba de formar es la siguiente:

Distribuimos el procesamiento de las conexiones externas y el procesamiento de la lógica del juego a dos servidores para su procesamiento, para una descripción fácil más adelante, temporalmente no muy riguroso El primero se llama un servidor de conexión, y el segundo se llama un servidor lógico.

El servidor de conexión puede hacer cosas muy simples, simplemente juntar los datos en múltiples conexiones. Suponiendo que el número total de conexiones simultáneas no exceda de 65,536, solo necesitamos agregar un encabezado de dos bytes al paquete de datos en cada conexión. Este servidor de conexión es suficiente para comunicarse con el servidor lógico a través de una única conexión.

Hay un servidor de conexión que maneja los datos de la manera más eficiente. Su lógica es simple y la cantidad de código es muy pequeña. El servidor lógico solo tiene una conexión externa, no importa cómo se maneje, no será lento.

Además, podemos extender este método. Supongamos que nuestra lógica procesa la lógica a una frecuencia de 10 Hz. Permitimos que el servidor de conexión envíe los datos agregados periódicamente con un pulso de 10Hz, primero enviamos un mensaje de longitud y luego enviamos el paquete de datos. Incluso si un pulso no tiene datos externos, está estrictamente garantizado enviar al menos una información de longitud 0. Además, el servidor de conexión también necesita controlar el flujo total de datos de cada pulso, para no enviar datos más que la capacidad del procesamiento del servidor lógico.

Por lo tanto, el servidor lógico puede incluso llamar a recv para bloquear los datos, incluso la selección se guarda. En cuanto a si los datos están realmente bloqueados por el receptor, están garantizados por la lógica del servidor de conexión.

Cuando se trata de bloquear la recepción, cuando hablé con un colega, él estaba muy preocupado por la confiabilidad de esto. No quería poner accidentalmente el servidor lógico en una llamada al sistema. Citó muchos accidentes posibles, pero personalmente no me preocupo demasiado, y no quiero explicar más aquí. Por supuesto, diseñé esto, principalmente no para guardar una llamada seleccionada, sino para facilitar la depuración.
(Por supuesto, si resulta que esto no es factible, es fácil modificar el esquema.)

Debido a que el bloqueo de recepción puede garantizar la sincronización estricta del servidor lógico, cuando grabamos la comunicación en los dos servidores, podemos usar esto más adelante. El proceso de recrear completamente la lógica del juego, sin importar cómo se depure y ejecute, puede asegurar que el comportamiento del servidor lógico se pueda reproducir completamente. Es decir, los paquetes conocidos se aceptan cada 0.1s y luego se procesan.

Al hacerlo, la necesidad del servidor lógico de la cantidad de código en la capa de red se reduce considerablemente, y la lógica se puede construir de forma más concéntrica.

Copyright © Conocimiento de Windows All Rights Reserved