Carambolas是一个不断发展的通用支持库,由多个.NET标准2.0组件组成。尤其,它具有定制的多通道可靠的UDP协议实现,用于低延迟/低带宽 - 延迟产品网络应用程序,具有软实时约束。
第一个版本是具有功能齐全的网络模块的最小核心。该存储库是围绕单个解决方案构建的,因为我计划将来通过添加新模块来扩展。
测试覆盖范围仍然很小,因此如果不对源代码进行仔细检查,则不应暗示任何正确性。这是一个最早阶段的持续项目。
二进制文件即将在存档部分或Nuget软件包的形式中提供。
本地主机由carambolas.net.host的实例表示。它必须用于连接到远程主机或接受传入的连接。
每个远程主机都由Carambolas.net.peer的实例表示。
连接,断开连接和数据等事件是通过主机对象接收的,而PEER对象可用于发送数据或主动断开连接。
在这一点上,连接,断开,发送和接收操作是无障碍的;开放和关闭正在阻止(出于明显的原因)。
请注意,同一主机对象可用于主动请求连接并接受传入的连接,从而使其在P2P拓扑中可用。客户/服务器角色不会仅通过如何配置主机来执行和出现。主机甚至可以同时向多个远程主机发送连接请求。
示例:
主机对象实例化以连接到远程对等。内部循环负责确保事件不会加入下一次迭代。
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 ) ;
}
}主机对象实例化,最多等待10个传入连接。内部循环负责确保事件不会加入下一次迭代。
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 ) ;
}
} 该项目可以追溯到2015年,当时我来加拿大学习多伦多电影学校的视频游戏设计和开发。最初的动机是创建可以在多个Unity3D项目中重复使用的配件类的汇编。一段时间后,我开始研究前景多人游戏的网络解决方案,重点转向设计可重复使用的网络模块。最初,我将问题作为一个简单的问题,即集成了我当时可以找到的任何其他合适的第三方库。不久之后,我开始遇到各种各样的问题,从破裂的假设到隐藏的实施权衡。发现膨胀(几乎具有误导性)功能列表,设计不兼容或纯粹的破坏实现并不少见。特别是,最困扰我的是,解决方案的许多方面似乎是随机任意的,几乎没有解释为什么这种方法是首选的或施加的一定限制。我会花几个小时检查一个项目的来源记录,以弄清楚为什么只有后来才意识到代码的另一部分是直接矛盾的。
所有这些都促使我从事更多工作,最终我决定自己建立一个可以实现和验证的合理功能列表的轻量级网络库。没有匆忙,没有截止日期。只是一个真正的尝试,试图实施我可以设计的最佳技术解决方案。
同时,我毕业了,回到了一份全职工作,不得不将这个项目搁置一旁。一年前,在找到了一些旧的笔记后,我恢复了原型档案,并决定将我收集的所有信息汇总在一起,以便不仅其他人可以尝试它,而且还了解它的工作方式和原因。
可以在任何平台中使用支持C#7.3或更高版本的编译器构建托管组件。测试和附件应用需要NetCore 2.2。
可以使用GCC或Visual Studio的CMAKE构建本地库。
支持的OS版本:
对于任何其他平台,或在没有必需的本地库的情况下,后备代码一般而言,虽然效率可能较低,必须具有完全功能性和透明性。
所有C#项目和构建脚本均配置为将中间文件和二进制文件存储在位于项目根部的构建文件夹下,因此可以轻松地检查,验证和清洁构建。
该代码使用dllimport绑定本机库。 Dllimport可能始终使用Windows库名称,并根据需要自动添加其他平台的前缀/后缀。例如,carambolas.net.native.dll,Windows上的Net Native Library的名称,变成Linux上的Libcarambolas.net.native.dll。构建脚本已经以专有名称创建库。
为了方便起见,包括视觉工作室解决方案,因此Windows不需要其他构建步骤。仅确保选择与主机操作系统相对应的平台(X86或X64)。构建测试应用程序和单位测试是必需的。所有.NET组件都是为AnyCPU构建的,无论选择的解决方案平台如何,但是Visual Studio必须知道要构建哪些本机库进行测试,因为预计它们会与相关的组件并排部署。
使用nugetpack.bat来编译本机库和便携式组件,并在单个操作中创建Nuget软件包。
使用build.bat在不使用Visual Studio的情况下构建所有项目供发布。
Mac的Visual Studio尚未进行测试,也不支持,因此不要指望它可以正常工作。
确保具有CMAKE(> = 2.8)和GCC,以便能够编译本机库。需要DOTNET CORE SDK 2.1来编译组件并生成Nuget软件包。
使用nugetpack.sh来编译本机库和便携式组件,并在单个操作中创建Nuget软件包。
使用build.sh在不使用Visual Studio的情况下构建所有项目供发布。
确保安装了CMAKE(> = 2.8),Build-Endenteal和GCC-Multilib,以便能够为X86和X64编译本机库。
在Ubuntu Run:$ sudo apt-get install build-extent build-extential gcc-multilib g ++ -multilib cmake
需要编译组件并生成Nuget软件包需要Dotnet Core SDK 2.1。
在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
使用nugetpack.sh来编译本机库和便携式组件,并在单个操作中创建Nuget软件包。
使用build.sh在不使用Visual Studio的情况下构建所有项目供发布。
使用Xunit项目围绕关键功能实施了最小的单元测试集。
Carambolas.net.tests.host是一种简单的控制台应用程序,用于手动验证基本网络功能。当与Wireshark和笨拙的一侧时,这特别有用
Carambolas.net.tests.Integration是Carambolas.net的一组集成测试,也与Xunit实施。测试依次运行,每个测试启动两个单独的线程(服务器和客户端),这些线程在特定的时间内通过环回接口进行通信。回环代表了一个理想的网络,其中往返时间最少,数据包永远不会过时,除非有淡淡的溢出,否则不会丢失。这些特征对于验证正常的执行路径很有用。
Wireshark是一种宝贵的调试工具,可用于监视网络活动和检查数据包。此外,Wireshark还支持一类称为解剖器的特殊类别的插件,该插件可用于分析自定义协议。
该项目包括Carambolas的基本Wireshark解剖器。为了使用它,请确保已经安装了Wireshark。
Clumsy是一个网络数据包捕获程序,它以用户模式运行,能够拦截数据包实时模拟退化的网络条件。
在config.txt文件中添加以下内容的预设过滤器行,以影响由环回接口连接的主机在集成测试中使用的同一端口上(1313):
carambolas: udp and outbound and loopback and (udp.DstPort == 1313 or udp.SrcPort == 1313)
请注意,在使用Loopback接口使用笨拙时,有一些警告。从笨拙的用户手册中:
- 环回入口数据包无法捕获或重新注射。当您考虑一下时,当您将数据包从计算机发送到本身时,很难说它是一个入站或出站数据包。实际上,底层Windows过滤平台似乎将所有环回包数据包分类为出站。要记住的事情是,当您在环回包数据包上处理时,您的过滤器中不能有“入站”。重要的是要知道您的计算机可能具有127.0.0.1以外的IP,就像路由器分配的Intranet IP一样。这些也被视为回环数据包。
- 回环包被捕获两次。由于我们没有入站环回数据包,因此所有回环数据包都被视为出站。因此,笨拙的过程将两次处理:第一次是发送时,第二次接收时。一个简单的例子是,当过滤器简单地“出站”并应用500ms时。当您ping localhost时,它将是1000ms的滞后。您可以通过指定目标端口以及类似的内容来解决它。但是,在设置参数时,请记住这一点会更容易。
- 入站数据包捕获一直无法运行。如前所述,环回入口数据包无法重新注射。问题是,即使目标IP不在您的计算机中,有时某些数据包也可能被归类为入站数据包。这仅影响非环回包。如果您仅在Local主持那里工作,那就可以了。未来发布的目的是诊断导致此问题的原因并提供解决方案。
- 无法基于过程系统宽网络捕获的过滤被列为一项功能。但这确实是因为没有简单的方法可以提供强大的解决方案。
我总是以错误报告的形式,错误修复(甚至更好!)或改进的测试覆盖范围供应。
欢迎功能请求,但可以将其保存在积压中,具体取决于它们的广泛,可行或可取的程度。如果功能请求太复杂,则可能取决于赞助,因为我的资源(时间和金钱)有限。
如果您想支持这个项目,我可能有兴趣收到您的来信,请伸出援手!
在葡萄牙语中,卡兰博拉斯是卡兰博拉(= starfruit)的复数形式。该术语在巴西的某些地区也被通俗地使用,以表达惊讶或不耐烦。
在Carambolas之前,我至少做了六次尝试在一个可用项目中组织我的想法。使用Carambolas,我决定构建一系列原型,以了解设计问题并测试不同的方法。每个原型都有一个由字母形成的代码名称,从A1开始的数字。最初在此存储库中导入的源代码是第9个原型的第75次迭代,因此A9。
本地图书馆主要出于绩效原因提供,因此它们是完全可选的。尝试为每个可能的平台提供一个本机实现是不合理的(考虑所有台式机,移动,控制台,嵌入式...),并且仅依靠本机库将使目标平台仅将目标平台减少到仅少数台式机(Windows,Linux和MacOS)。因此,作为经验法则,托管代码中必须始终为本机库实现的任何功能实现后退实现。
由于本机库是可选的,因此该程序无法判断是否应该存在一个丢失的文件,因此为什么没有出现错误或记录的丢失本机库的错误。根据定义,缺失的本机库绝不是错误。
通常,你不能。至少您不应该从API的角度来看。对于用户(或应用程序编程器),在这种情况下,在这种情况下,carambolas采用了什么基本实施策略。但是,此信息可能与部署有关,因此,每当创建一个具有自动后备的Interop对象时,代码都会产生指示性日志信息。例如,Carambolas.net.socket将产生类似于“使用carambolas.net.sockets.native.socket”的日志信息,当时找到了用于基础插座实现的本地库。这样,如果您要考虑到本机库,则可以确定它们是否实际使用。
这意味着您正在部署一个本地库,该库是损坏或为错误的CPU体系结构编译的本地库。
本地库必须与相应的互动组件并排进行,尽管可以为任何CPU架构编译一次组件,但本机库不能。它们必须匹配运行操作系统的CPU体系结构,否则将它们视为损坏的文件,并且.NET抛出系统。BADIMAGEFORMATEXCEPTION。请注意,这与试图加载未找到的库,而不是错误。
带宽 - 延迟产品(BDP)是网络链路的传输容量(以每秒位数为单位)及其往返延迟时间(以秒为单位)的产物。它代表网络可以保留的最大数据,然后才能到达任何确认。
BDP可用于根据网络对网络进行分类,是高于或低于特定阈值。 BDP较大的网络称为长脂肪网络(LFN)。 LFN可以是具有非常大的平均往返时间(如卫星链路中的带宽)的网络,也可以是一个宽的(高带宽)网络,它显示出相当小的往返时间(如Gigabit以太网链路中)。
检查Wikipedia以获取有关它的更多信息。
carammbolas.net.socket对象是本机套接字实现或依赖System.net.sockets.socket的后备实现的立面。它有助于将主机和同伴对象的复杂性解矛和降低。有关更多信息,请参阅DOC/README-CARAMBOLAS.NET。
system.net.ipaddress和system.net.ipendpoint是可变的对象,在.NET CORE和.NET框架的所有当前构建中促进许多不必要的分配。 carambolas.net.ipaddress和carambolas.net.ipendpoint是有助于降低GC压力的不可变值类型。有关更多信息,请参阅DOC/README-CARAMBOLAS.NET。
与Chacha20和Poly1305的AEAD在开箱即用。可以通过向主机提供Carambolas.net.icipher和carambolas.net.icipherfactarfactractory接口来实现自定义策略。唯一的要求是:
用户应用程序可以在发送之前自由压缩数据,但是目前没有提供自动压缩/解压缩的单个消息或完整数据包的机制。
所有与用户应用程序一起部署的源代码和所有生产的二进制文件均根据MIT许可获得许可。
Carambolas.commandlinearguments基于Griffonrl的一篇文章,其源代码在MIT许可下发布,并在Jake Ginnivan的另一篇文章中提供了其他想法,该文章扩展了原始资料。
Carambolas.security.criptography.crc32c以武力为基于MIT许可证的CRC32.NET。
carambolas.security.criptography.nacl在MIT许可下由David de Smet的NACl.Core扩展。
在LUA中为Wireshark编写的协议解剖器可根据GPLV3许可证获得。它仅被用作Wireshark的输入文件,以扩展其功能,并允许它显示有关Carambolas Network Network协议格式化的UDP数据包的更多信息。因此,它是完全分开的,并且不相互作用,取决于或以任何方式贡献任何源文件,汇编或本机库。