Carambolas es una biblioteca de soporte de propósito general en constante evolución compuesta por múltiples ensamblados .NET Standard 2.0 . En particular, Cuenta con una implementación de protocolo UDP confiable multicanal personalizado destinada a aplicaciones de red de productos de baja latencia de baja latencia/bajo ancho de banda con restricciones suaves en tiempo real en tiempo real .
La primera liberación es un núcleo mínimo con un módulo de red completamente funcional. Este repositorio está estructurado en torno a una sola solución porque planeo expandirme agregando nuevos módulos en el futuro.
La cobertura de la prueba sigue siendo mínima, por lo que no se debe implicar un nivel de corrección sin una inspección cercana del código fuente. Este es un proyecto continuo en sus primeras etapas.
Los binarios pronto estarán disponibles en la sección Archivo o en forma de paquetes Nuget.
El host local está representado por una instancia de carambolas.net.host . Debe usarse para conectarse a un host remoto o aceptar conexiones entrantes.
Cada host remoto está representado por una instancia de carambolas.net.peer .
Eventos como la conexión, la desconexión y los datos se reciben a través del objeto de host, mientras que los objetos pares pueden usarse para enviar datos o desconectar activamente.
En este punto, conectar, desconectar, enviar y recibir operaciones no son bloqueantes; Abierto y cierre están bloqueando (por razones obvias).
Tenga en cuenta que el mismo objeto de host se puede usar para solicitar activamente conexiones y aceptar conexiones entrantes de todos modos, lo que lo hace utilizable en topologías P2P. Los roles de cliente/servidor no se aplican y emergen simplemente por cómo se configura un host. Un host puede incluso enviar solicitudes de conexión a múltiples hosts remotos simultáneamente.
Ejemplos :
El objeto de host instanciado para conectarse a un par remoto. El bucle interno es responsable de garantizar que los eventos no se acumulen para la próxima iteración.
using ( var host = new Host ( "MyHost" )
{
host . Open ( IPEndPoint . Any , new Host . Settings ( 0 ) ) ;
host . Connect ( new IPEndPoint ( IPAddress . Loopback , 1313 ) , out Peer peer ) ;
.. .
while ( true )
{
while ( host . TryGetEvent ( out Event e ) )
{
if ( e . EventType == EventType . Data )
Console . WriteLine ( $ "DATA: { e . Peer } { e . Data } " ) ;
else if ( e . EventType == EventType . Connection )
Console . WriteLine ( $ "CONNECTED: { e . Peer } " ) ;
else if ( e . EventType == EventType . Disconnection )
{
Console . WriteLine ( $ "DISCONNECTED: { e . Peer } { e . Reason } " ) ;
return ;
}
}
Thread . Sleep ( 33 ) ;
}
}El objeto de host instanciado para esperar hasta 10 conexiones entrantes. El bucle interno es responsable de garantizar que los eventos no se acumulen para la próxima iteración.
using ( var host = new Host ( "MyHost" )
{
host . Open ( new IPEndPoint ( IPAddress . Loopback , 1313 ) , new Host . Settings ( 10 ) ) ;
.. .
while ( true )
{
while ( host . TryGetEvent ( out Event e ) )
{
if ( e . EventType == EventType . Data )
Console . WriteLine ( $ "DATA: { e . Peer } { e . Data } " ) ;
else if ( e . EventType == EventType . Connection )
Console . WriteLine ( $ "CONNECTED: { e . Peer } " ) ;
else if ( e . EventType == EventType . Disconnection )
{
Console . WriteLine ( $ "DISCONNECTED: { e . Peer } { e . Reason } " ) ;
return ;
}
}
Thread . Sleep ( 33 ) ;
}
} Este proyecto se remonta a 2015 cuando llegué a Canadá para estudiar el diseño y el desarrollo de los videojuegos en la Toronto Film School. La motivación original era crear una compilación de clases de accesorios que pudieran reutilizarse en múltiples proyectos Unity3D. Después de un tiempo, comencé a investigar soluciones de red para un juego multijugador Prospect y el enfoque cambió hacia el diseño de un módulo de red reutilizable. Inicialmente, abordé el problema como una simple cuestión de integrar el UNSE o cualquier otra biblioteca de terceros adecuada que pude encontrar en ese momento. Poco después, comencé a toparme con todo tipo de problemas, desde supuestos rotos hasta compensaciones de implementación ocultas. No era raro encontrar listas de características infladas (casi engañosas), incompatibilidades de diseño o implementaciones simples. En particular, lo que más me molestó fue que muchos aspectos de las soluciones parecían aleatoriamente arbitrarios con poca o ninguna explicación de por qué se prefirió ese enfoque o se impuso un cierto límite. Pasaría horas inspectar la fuente de un proyecto tomando notas para descubrir por qué algo era la forma en que solo se dio cuenta de que otra parte del código estaba en contradicción directa.
Todo esto me llevó a más trabajo y finalmente decidí construir una biblioteca de red liviana con una lista de características razonable que podría implementar y verificar. Sin prisa, sin plazos. Solo un intento genuino de implementar la mejor solución técnica que pude diseñar.
Mientras tanto, me gradué, volví a un trabajo de tiempo completo y tuve que dejar a un lado este proyecto. Hace un año, después de encontrar algunas notas antiguas, restauré mi archivo de prototipos y decidí armar una construcción integral con toda la información que recopilé para que no solo otras personas pudieran experimentar con él, sino también entender la forma en que funcionó y por qué.
Los ensamblajes administrados se pueden construir en cualquier plataforma con un compilador que admita C# 7.3 o superior. Las pruebas y las aplicaciones accesorias requieren NetCore 2.2.
Las bibliotecas nativas se pueden construir usando CMake con GCC o Visual Studio.
Versiones del sistema operativo compatible:
Para cualquier otra plataforma, o en ausencia de una biblioteca nativa requerida, existe un código de respuesta que, aunque en general puede ser menos eficiente, debe ser completamente funcional y transparente.
Todos los proyectos de C# y los scripts de compilación están configurados para almacenar archivos y binarios intermedios en una carpeta de compilación ubicada en la raíz del proyecto para que las compilaciones se puedan inspeccionar, verificar y limpiar fácilmente.
El código utiliza DllImport para vincular bibliotecas nativas. DllImport siempre puede usar los nombres de la biblioteca de Windows y agregará automáticamente los prefijos/sufijos de otras plataformas según sea necesario. Por ejemplo, carambolas.net.native.dll, el nombre de la biblioteca nativa de la red en Windows, se convierte en libcarambolas.net.native.dll.so en Linux y libcarambolas.net.native.dll.dynlib en Macos. Construir scripts ya crea las bibliotecas bajo los nombres propios.
Se incluye una solución de Visual Studio para conveniencia, por lo que no se requieren pasos de compilación adicionales para Windows. Solo asegúrese de seleccionar la plataforma correspondiente a su sistema operativo host (X86 o X64). Esto se requiere para crear las aplicaciones de prueba y para las pruebas unitarias. Todos los conjuntos de .NET están construidos para AnyCPU , independientemente de la plataforma de solución seleccionada, pero Visual Studio debe saber qué bibliotecas nativas construir para las pruebas, ya que se espera que se implementen de lado a lado con sus conjuntos asociados.
Use nugetpack.bat para compilar la biblioteca nativa y los ensamblajes portátiles y crear paquetes Nuget, todo en una sola acción.
Use build.bat para crear todos los proyectos para su lanzamiento sin usar Visual Studio.
Visual Studio para Mac no se ha probado y no es compatible, así que no esperes que funcione.
Asegúrese de tener CMake (> = 2.8) y GCC para poder compilar la biblioteca nativa. Se requiere Dotnet Core SDK 2.1 para compilar los ensamblados y generar paquetes NUGET.
Use nugetpack.sh para compilar la biblioteca nativa y los ensamblajes portátiles y crear paquetes Nuget, todo en una sola acción.
Use Build.sh para crear todos los proyectos para su lanzamiento sin usar Visual Studio.
Asegúrese de tener CMake (> = 2.8), Build-Senence y GCC-Multilib instalado para poder compilar la biblioteca nativa para X86 y X64.
En Ubuntu Run: $ sudo apt-get instalar construye gcc-multilib g ++-multilib cmake
Se requiere Dotnet Core SDK 2.1 para compilar ensamblados y generar paquetes NUGET.
En Ubuntu Run:
$ wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
$ sudo dpkg -i packages-microsoft-prod.deb
$ sudo apt-get update;
sudo apt-get install -y apt-transport-https &&
sudo apt-get update &&
sudo apt-get install -y dotnet-sdk-2.1
Use nugetpack.sh para compilar la biblioteca nativa y los ensamblajes portátiles y crear paquetes Nuget, todo en una sola acción.
Use Build.sh para crear todos los proyectos para su lanzamiento sin usar Visual Studio.
Se implementa un conjunto mínimo de pruebas unitarias en torno a las características clave utilizando proyectos XUnit.
Carambolas.net.tests.host es una aplicación de consola simple utilizada para verificar manualmente la funcionalidad de red básica. Es particularmente útil cuando se puso del lado de Wireshark y torpe
Carambolas.net.tests.integration es un conjunto de pruebas de integración para carambolas.net también implementadas con XUnit. Las pruebas se ejecutan secuencialmente, cada uno inicia dos hilos separados (un servidor y un cliente), que se comunican a través de la interfaz de backback por un tiempo específico. El bucleback representa una red ideal donde el tiempo de ida y vuelta es mínimo, los paquetes nunca llegan fuera de servicio y nunca se pierden a menos que haya un desbordamiento de Bufffer. Estas características son útiles para validar las rutas de ejecución normales.
Wireshark es una herramienta de depuración invaluable que se puede utilizar para monitorear la actividad de la red e inspeccionar los paquetes. Además, Wireshark admite una clase especial de complementos llamado disectores que pueden usarse para analizar protocolos personalizados.
Este proyecto incluye un disector básico de Wireshark para Carambolas. Para usarlo, asegúrese de que Wireshark ya esté instalado.
Clumsy es un programa de captura de paquetes de red que se ejecuta en modo de usuario y es capaz de interceptar paquetes para simular condiciones de red degradadas en tiempo real.
Agregue una línea de filtro preestablecida como lo siguiente en el archivo config.txt para afectar los hosts conectados por la interfaz de bucleback en el mismo puerto utilizado en las pruebas de integración (1313):
carambolas: udp and outbound and loopback and (udp.DstPort == 1313 or udp.SrcPort == 1313)
Tenga en cuenta que hay algunas advertencias cuando se usa CLUMSY con la interfaz de loopback. Del manual del usuario torpe:
- Los paquetes entrantes de bucle de bucle no se pueden capturar ni reinyectarse. Cuando lo piensas, es realmente difícil decir que es un paquete entrante o saliente cuando envía paquetes desde la computadora a sí misma. De hecho, la plataforma de filtrado de Windows subyacente parece clasificar todos los paquetes de bucle de bucle como salida. Lo que hay que recordar es que cuando se procesa en paquetes de bucleback, no puede tener "entrantes" en su filtro. Es importante saber que su computadora puede tener IP que no sean 127.0.0.1, como una IP intranet asignada por su enrutador. Estos también se consideran paquetes de loopback.
- Los paquetes de backback se capturan dos veces. Dado que no tenemos paquetes de bucle de bucle de entrada, todos los paquetes de bucle de bucle se consideran salientes. Tan torpe los procesará dos veces: la primera vez es cuando se envía, y por segunda vez al recibir. Un ejemplo simple es que cuando el filtro es simplemente "saliente", y aplique un retraso de 500 ms. Cuando ping a localhost, sería un retraso de 1000 ms. Puede trabajar con él especificando el puerto de destino y cosas como esta. Pero sería más fácil tener esto en cuenta y tener cuidado al establecer los parámetros.
- La captura de paquetes entrantes no funciona todo el tiempo. Como se señaló anteriormente, los paquetes de entrada de bucle inbound no se pueden reinyectar. El problema es que en ocasiones algunos paquetes pueden clasificarse como paquetes entrantes, incluso si la IP de destino no es de su computadora. Esto solo afecta los paquetes no backback. Si solo estás trabajando en localhost, va a estar bien. El objetivo de la liberación futura es diagnosticar qué causó esto y proporcionar una solución.
- No se puede filtrar en función de la captura de red de amplio sistema de procesos se enumera como una característica. Pero realmente esto es ya que no hay una manera fácil de proporcionar una solución robusta.
Siempre estoy abierto a contribuciones, ya sea en forma de informes de errores, correcciones de errores (¡aún mejor!) O mejorada cobertura de prueba.
Las solicitudes de funciones son bienvenidas, pero pueden mantenerse en una cartera de pedidos dependiendo de cuán extensas, factibles o deseables sean. Si una solicitud de función es demasiado compleja, puede depender del patrocinio, ya que tengo recursos limitados (tiempo y dinero) para dedicar.
Si desea apoyar este proyecto, puedo estar interesado en tener noticias suyas, ¡así que comuníquese!
En portugués, Carambolas es la forma plural de Carambola (= fruta de las estrellas). El término también se usa coloquialmente en ciertas regiones de Brasil para expresar asombro o impaciencia.
Antes de Carambolas, hice al menos media docena de intentos de organizar mis ideas en un proyecto utilizable. Con Carambolas decidí construir una serie de prototipos para aprender sobre problemas de diseño y probar diferentes enfoques. Cada prototipo tenía un nombre de código formado por una letra y un número que comenzó en A1. El código fuente que se importó inicialmente en este repositorio fue la 75ª iteración del noveno prototipo, de ahí A9.
Las bibliotecas nativas se proporcionan principalmente por razones de rendimiento, por lo tanto, son totalmente opcionales. No hubiera sido razonable tratar de proporcionar una implementación nativa para cada plataforma posible (piense en todas las computadoras de escritorio, móviles, consolas, incrustadas ...) y confiar exclusivamente en bibliotecas nativas reduciría las plataformas objetivo a solo un puñado, posiblemente solo escritorio (Windows, Linux y Macos). Entonces, como regla general, siempre debe haber una implementación de respaldo en el código administrado para cualquier funcionalidad implementada por una biblioteca nativa.
Debido a que las bibliotecas nativas son opcionales, el programa no puede decir si se suponía que un archivo faltante debía estar allí o no, por lo tanto, por qué no se inicia ni registra una biblioteca nativa faltante. Por definición, una biblioteca nativa faltante nunca es un error.
En general, no puedes. Y no deberías, al menos no desde una perspectiva API. No debería importar al usuario (o programador de aplicaciones) qué estrategia de implementación subyacente es empleada por una dependencia, en este caso Carambolas. Sin embargo, esta información podría ser relevante para la implementación, por lo que cada vez que se crea un objeto interops que también tiene una ventana automática, el código produce una información de registro indicativa. Por ejemplo, carambolas.net.socket producirá una información de registro similar a "usando carambolas.net.sockets.native.socket" Cuando se encuentra una biblioteca nativa para la implementación de socket subyacente. De esta manera, si está implementando con bibliotecas nativas en mente, puede determinar si realmente se están utilizando.
Esto significa que está implementando una biblioteca nativa que es corrupta o compilada para la arquitectura de CPU incorrecta.
Las bibliotecas nativas deben ir de lado a lado con sus conjuntos de interoperabilidad correspondientes y, aunque los conjuntos pueden compilarse una vez para cualquier arquitectura de CPU, las bibliotecas nativas no pueden. Deben coincidir con la arquitectura de la CPU del sistema operativo en ejecución, de lo contrario se tratan como archivos corruptos y .NET lanza un sistema. BadImageFormateException. Tenga en cuenta que esto no es lo mismo que tratar de cargar una biblioteca que no se encuentra, que por definición no es un error.
El producto de retardo de ancho de banda (BDP) es el producto de la capacidad de transmisión de un enlace de red (en bits por segundo) y su tiempo de retraso de ida y vuelta (en segundos). Representa la cantidad máxima de datos que una red puede retener antes de que llegue cualquier reconocimiento.
El BDP se puede usar para clasificar las redes de acuerdo con si está por encima o por debajo de cierto umbral. Las redes con un BDP grande se llaman redes de grasa larga (LFN). Los LFN pueden ser redes con un tiempo de viaje de ida y vuelta muy grande (regadeo del ancho de banda, como en los enlaces satelitales) o una red amplia (ancho de banda) que muestra tiempos de ida y vuelta considerablemente pequeños (como en los enlaces Gigabit Ethernet).
Consulte la Wikipedia para obtener más información al respecto.
Un objeto carammbolas.net.socket sirve como una fachada para una implementación nativa de socket o una implementación de retroceso que se basa en system.net.sockets.socket. Ayuda a desacoplar y reducir la complejidad de los objetos huésped y pares. Consulte DOC/ReadMe-Carambolas.net para obtener más información.
System.net.ipaddress y system.net.ipendpoint son objetos mutables que promueven una serie de asignaciones inegojadas en todas las implementaciones actuales de .NET Core y .NET Framework. Carambolas.net.ipaddress y carambolas.net.ipendpoint son tipos de valor inmutables que contribuyen a reducir la presión de GC. Consulte DOC/ReadMe-Carambolas.net para obtener más información.
AEAD con Chacha20 y Poly1305 es compatible fuera de la caja. Las estrategias personalizadas se pueden implementar proporcionando al host implementaciones de carambolas.net.ipher y carambolas.net.pherherfactory interfaces. Los únicos requisitos son:
Una aplicación de usuario es gratuita para comprimir sus datos antes de enviar, pero actualmente no hay un mecanismo para proporcionar compresión/descompresión automática de mensajes individuales o paquetes completos.
Todo el código fuente y los binarios producidos para implementarse junto con una aplicación de usuario tienen licencia bajo una licencia MIT.
Carambolas.CommandlinearGuments se basó en un artículo de Griffonrl con el código fuente publicado bajo una licencia del MIT con ideas adicionales de otro artículo de Jake Ginnivan que se expandió en la fuente original.
Carambolas.security.criptography.crc32c se basó en CRC32.net por la fuerza bajo una licencia MIT.
Carambolas.security.criptography.NaCl fue basado y expandido en NaCl.core por David de Smet bajo una licencia MIT.
El disector de protocolo escrito en Lua para Wireshark está disponible bajo una licencia GPLV3. Se supone que solo se utiliza como un archivo de entrada para Wireshark para extender sus capacidades y permitirle mostrar más información sobre los paquetes UDP formateados de acuerdo con el Protocolo de la red Carambolas. Por lo tanto, está completamente separado y no interactúa, depende o contribuye de ninguna manera a cualquier archivo fuente, ensamblaje o bibliotecas nativas.