¡Entran amigos que tengan experiencia en programación de sockets o que entiendan el hardware de tarjetas de red! ! !
Winpcap (libpcap para Windows) puede manejar el segundo piso y superiores.
Sobre el buffer, ¿crees que es el algoritmo de Nagle?
La eficiencia de TCP en la transmisión de pequeños paquetes de datos (traducido de MSDN)
El nivel es limitado y los errores son inevitables - constructor
Resumen: use TCP para transmitir datos pequeños Al empaquetar, el diseño del programa es muy importante. Si no presta atención a la respuesta retardada de los paquetes TCP, el algoritmo de Nagle y el búfer Winsock en el diseño, afectará seriamente el rendimiento del programa. Este artículo analiza estos problemas, enumera dos situaciones y brinda algunas soluciones de diseño optimizadas para transmitir pequeños paquetes de datos.
Antecedentes: cuando la pila TCP de Microsoft recibe un paquete, inicia un temporizador de 200 milisegundos. Cuando se envía un paquete de confirmación ACK, el temporizador se restablecerá y cuando se reciba el siguiente paquete, el temporizador de 200 ms se iniciará nuevamente. Para mejorar el rendimiento de la transmisión de aplicaciones a través de intranets e Internet, la pila TCP de Microsoft utiliza la siguiente estrategia para decidir cuándo enviar un paquete de confirmación después de recibir el paquete:
Si el temporizador de 200 milisegundos Cuándo. El siguiente paquete se recibe antes de que expire, se enviará inmediatamente un paquete de confirmación ACK.
2. Si hay un paquete de datos que debe enviarse al destinatario de la información de confirmación ACK, la información de confirmación ACK se agregará al paquete de datos y se enviará inmediatamente.
3. Cuando el temporizador expira, el mensaje de confirmación ACK se envía inmediatamente.
Para evitar la congestión de la red causada por pequeños paquetes de datos, la pila TCP de Microsoft activa el algoritmo Nagle de forma predeterminada, que puede unir los datos enviados por aplicaciones que llaman a Enviar varias veces y después de recibir el reconocimiento. confirmación del paquete de datos anterior enviado junto con el mensaje. Las siguientes son excepciones al algoritmo de Nagle:
1. Si el paquete de datos empalmado por la pila TCP de Microsoft excede el valor de MTU, los datos se enviarán inmediatamente sin esperar los datos anteriores.
Información de confirmación ACK del paquete de datos. En Ethernet, el valor MTU (Unidad de transmisión máxima) de TCP es 1460 bytes.
2. Si se configura la opción TCP_NODELAY, el algoritmo de Nagle se desactivará y el paquete de datos enviado por la aplicación que llama a Enviar se entregará a la red inmediatamente y sin demora.
Para optimizar el rendimiento de la capa de aplicación, Winsock copia los datos enviados por la aplicación que llama a Enviar desde el búfer de la aplicación al búfer del kernel de Winsock. La pila TCP de Microsoft utiliza un método similar al algoritmo de Nagle para decidir cuándo enviar datos a la red.
El tamaño predeterminado del búfer del kernel es 8K. Puede utilizar la opción SO_SNDBUF para cambiar el tamaño del búfer del kernel de Winsock. Winsock puede almacenar en búfer datos mayores que el tamaño del búfer SO_SNDBUF si es necesario. En la mayoría de los casos, la finalización de la llamada de envío por parte de la aplicación solo indica que los datos se copiaron en el búfer del kernel de Winsock, pero no significa que los datos realmente se pasaron a la red. La única excepción es:
Deshabilite el búfer del kernel de Winsock estableciendo SO_SNDBUT en 0.
Winsock utiliza las siguientes reglas para indicar que se ha completado una llamada de envío a una aplicación:
1 Si el socket todavía está dentro de los límites de SO_SNDBUF, Winsock enviará los datos. se copia en el búfer del kernel para completar la llamada de envío.
2. Si el socket excede el límite SO_SNDBUF y solo hay un dato de envío almacenado en el búfer del kernel, Winsock copiará los datos que se enviarán al búfer del kernel para completar la llamada de envío.
3. Si el socket excede el límite SO_SNDBUF y hay varios datos almacenados en el búfer para enviar en el búfer del kernel, Winsock copiará los datos que se enviarán al búfer del kernel y luego los transferirá a la red. hasta que el socket esté dentro del límite SO_SNDBUF o solo le quede un dato para enviar, y luego se completa la llamada de envío.
Caso 1
El cliente Winsock TCP necesita enviar 10.000 registros al servidor Winsock TCP y guardarlos en la base de datos. Los tamaños de registro varían de 20 bytes a 100 bytes. Para una lógica de aplicación simple, las posibles soluciones de diseño son las siguientes:
1. El cliente envía en modo de bloqueo y el servidor recibe en modo de bloqueo.
2. El cliente establece SO_SNDBUF en 0, desactiva el algoritmo Nagle y permite que cada paquete se envíe individualmente.
3. El servidor llama a Recv para recibir paquetes de datos en un bucle. Pase un búfer de 200 bytes a Recv para que cada registro pueda recuperarse en una única llamada a Recv.
Rendimiento:
En la prueba, se descubrió que el cliente solo puede enviar 5 datos al segmento de servicio por segundo, un total de 10,000 registros, aproximadamente 976 KB. y se necesita la mitad del tiempo para transmitirlos todos al servidor, más que horas.
Análisis:
Debido a que el cliente no configura la opción TCP_NODELAY, el algoritmo de Nagle obliga a la pila TCP a esperar la información de confirmación del paquete anterior antes de enviarlo. Sin embargo, el cliente establece SO_SNDBUF en 0 y desactiva el búfer del kernel. Por lo tanto, la llamada de envío 10000 solo puede enviar y reconocer un paquete a la vez, y cada mensaje de confirmación de confirmación se retrasará 200 milisegundos por las siguientes razones:
1. un temporizador de 200 A milisegundos.
2. El servidor no necesita enviar ningún dato al cliente, por lo que la información de confirmación ACK no puede ser transportada por el paquete de datos enviado.
3. El cliente no puede enviar el paquete de datos antes de recibir la información de confirmación del paquete de datos anterior.
4. Después de que expira el temporizador del servidor, el mensaje de confirmación ACK se envía al cliente.
Cómo mejorar el rendimiento:
Hay dos problemas con este diseño.
En primer lugar, hay un problema de latencia. El cliente debe poder enviar dos paquetes al servidor en 200 milisegundos. Debido a que el cliente usa el algoritmo Nagle de forma predeterminada, se debe usar el búfer del kernel predeterminado y SO_SNDBUF no debe establecerse en 0. Una vez que la pila TCP empalma un paquete que excede el valor de MTU, el paquete se enviará inmediatamente sin esperar el acuse de recibo anterior.
En segundo lugar, este diseño llama Enviar una vez por cada paquete pequeño. Enviar paquetes tan pequeños no es muy eficiente. En este caso, debe rellenar cada registro con 100 bytes y enviar 80 registros cada vez que llame a Enviar. Para que el servidor sepa cuántos registros se envían a la vez, el cliente puede agregar un mensaje de encabezado delante del registro.
Caso 2:
El programa cliente Winsock TCP abre dos conexiones y se comunica con el servidor Winsock TCP que proporciona servicios de cotización de acciones. La primera conexión se utiliza como canal de comando para transferir el número de stock al servidor. La segunda conexión se utiliza como canal de datos para recibir cotizaciones de acciones. Una vez establecidas las dos conexiones, el cliente envía el número de cotización de acciones al servidor a través del canal de comando y luego espera la información de cotización de acciones devuelta en el canal de datos. Después de recibir la primera información de cotización de acciones, el cliente envía la siguiente solicitud de número de acciones al servidor. Ni el cliente ni el servidor tienen configuradas las opciones SO_SNDBUF y TCP_NODELAY.
Rendimiento:
En las pruebas, se descubrió que el cliente solo podía recibir 5 mensajes de cotización por segundo.
Análisis:
Este diseño permite obtener sólo una información bursátil a la vez.
Envíe la información del primer número de acciones al servidor a través del canal de comando y reciba inmediatamente la información de cotización de acciones devuelta por el servidor a través del canal de datos. Luego, el cliente envía inmediatamente un segundo mensaje de solicitud, la llamada de envío regresa inmediatamente y los datos enviados se copian en el búfer del núcleo. Sin embargo, la pila TCP no puede entregar este paquete a la red inmediatamente porque no recibió el acuse de recibo del paquete anterior. Después de 200 milisegundos, el temporizador del servidor expira, la información de confirmación ACK del primer paquete de solicitud se envía de regreso al cliente y el segundo paquete de solicitud del cliente se entrega a la red. La información de cotización de la segunda solicitud se devuelve inmediatamente al cliente desde el canal de datos, porque el temporizador del cliente ha expirado en este momento y la información de confirmación ACK de la primera información de cotización se ha enviado al servidor. Este proceso ocurre en ciclos.
Cómo mejorar el rendimiento:
Aquí, el diseño de dos conexiones es innecesario. Si se utiliza una solicitud de conexión y se recibe información de cotización, la información de cotización devuelta recuperará inmediatamente la información de confirmación ACK de la solicitud de stock. Para mejorar aún más el rendimiento, el cliente debe llamar a Enviar para enviar varias solicitudes de acciones a la vez y el servidor debe devolver información de cotizaciones múltiples a la vez. Si se deben utilizar dos conexiones unidireccionales por alguna razón especial, tanto el cliente como el servidor deben configurar la opción TCP_NODELAY para que los paquetes pequeños puedan enviarse inmediatamente sin esperar la confirmación ACK del paquete anterior.
Sugerencias para mejorar el rendimiento:
Los dos casos anteriores ilustran algunos de los peores escenarios. Al diseñar una solución al problema de enviar y recibir una gran cantidad de paquetes pequeños, se deben seguir las siguientes recomendaciones:
1 Si los fragmentos de datos no requieren una transmisión urgente, la aplicación debe unirlos en otros más grandes. bloques de datos, luego llame a Enviar. Debido a que es probable que el búfer de envío se copie al búfer del kernel, el búfer no debe ser demasiado grande, generalmente menor que 8K, lo cual es muy eficiente. Siempre que el búfer del kernel de Winsock obtenga un bloque de datos mayor que el valor de MTU, se enviarán varios paquetes, dejando el último paquete. Excepto por el último paquete, el remitente no será activado por el temporizador de 200 ms.
2. Si es posible, evite conexiones de flujo de datos de socket unidireccionales.
3. No establezca SO_SNDBUF en 0 a menos que desee asegurarse de que el paquete se entregue a la red inmediatamente después de llamar a Enviar. De hecho, un búfer de 8K es adecuado para la mayoría de situaciones y no es necesario cambiarlo nuevamente a menos que se pruebe que el búfer recién configurado es más eficiente que el tamaño predeterminado.
4. Si no se puede garantizar la confiabilidad de la transmisión de datos, utilice UDP.