如果您正在阅读本文,您可能已经在CodeProject上看到了无数的.NET TCP套接字服务器文章。我还没有找到一个快速高效,易于扩展的开源解决方案,包括安全性,特别是TLS 1.2支持,并包含适用于Android,iOS,Windows Phone,Windows,Mac和Java客户端的API。
本文展示了我创建的一个名为DotNetOpenServer SDK的开源项目。SDK提供了一个客户端/服务器应用程序框架,它实现了一个可扩展的二进制协议栈,支持SSL / TLS 1.2连接,包括一个可扩展的安全框架,包括一个keep-alive / heartbeat协议,包括一个用于Windows和Windows Mobile的C#API,适用于Android和Unix / Linux版本的Java API以及适用于iOS和Mac的Objective-C API。
CodeProject上已有很多文章向开发人员展示如何创建同步和异步TCP客户端/服务器应用程序。本文不会尝试重新创建已经完成的工作。相反,本文提供了框架的高级概述,详细介绍了框架的二进制协议栈,总结了如何使用协议实现扩展框架,总结了如何创建自己的身份验证协议,并提供了创建自己的客户端/服务器的详细教程应用。
本文的完整源代码可以在上面找到,但也位于GitHub上:
https://github.com/UpperSetting/DotNetOpenServerSDK可以选择从NuGet下载Windows二进制文件。有关更多信息,请参阅位于GitHub上的README.md:
https://github.com/UpperSetting/DotNetOpenServerSDK/blob/master/README.md可以从GitHub下载文档和最新的客户端Java JAR文件:
https://github.com/UpperSetting/DotNetOpenServerSDK/releasesWindows服务器和客户端可选地支持通过log4Net进行日志记录,可以从NuGet下载:
https://www.nuget.org/packages/log4net/为了最小化代码库,我使用位于以下位置的J2ObjC开源项目从我的Java源代码自动生成了Objective-C API:
http://j2objc.org/
DotNetOpenServer
在Windows上使用.NET Framework 4.5.2实现。服务器实现为异步TCP套接字服务器。.NET组件用于协商SSL / TLS 1.2。协议在独立程序集中实现,当客户端请求时,它们使用Reflection加载。服务器加载程序集所需的信息包含在app.config文件中,也可以选择以编程方式设置。
当我构建这个API时,我的目标是尽可能减少重复的代码。我最终得到的是几个解决方案甚至更多项目。最低级别是一个Portable
名为OpenServerShared
的服务器,Windows客户端和Windows Mobile客户端共享的项目。接下来是一个名为的Windows项目OpenServerWindowsShared
,它在服务器和Windows客户端之间共享。最后,有一个服务器,Windows客户端和Windows Mobile客户端的项目。
由于Android应用程序是用Java编写的,我想支持Unix和Linux版本,因此我能够进一步减少代码重复。使用Eclipse,我能够创建一个单独的Java项目,负责生成可供Android和Unix / Linux应用程序使用的JAR文件。
对于那些不熟悉Apple操作系统编程的人来说,iOS(iPhone和iPad)和OS X(Mac)应用程序是用Objective-C或Swift编写的。当我开始这个项目时,我不知道Objective-C或Swift语言,所以我研究了自动生成选项。我很惊喜地了解了J2ObjC项目,现在更令人惊讶地发现所有的代码不仅没有问题移植,而且似乎完美无缺地执行。再次,我能够最小化代码重复。展望未来,一旦有一个优秀的Java to Swift转换器可用,我计划包括一个Swift API。
由于这个项目的核心要求是创建一个快速有效执行的协议栈,我将开始详细介绍协议栈。如果您对字节流不感兴趣,请继续并跳过本节。
会话层协议(SLP)是堆栈中的第一个协议。SLP是一种非常简单的协议,可传输6个字节的数据。第一个字段包含一个2字节的标识号。虽然识别号在技术上不是必需的,但我觉得这是一个很好的补充,用于嗅探包含多个DotNetOpenServer
数据包的TCP数据包。下一个字段包含一个4字节Uint32
,指定有效负载的长度(以字节为单位)。最后一个字段包含一个2字节Uint16
,用于指定下一层的唯一协议标识符。最后一个字段包含在有效负载长度中。此外值得注意的是,所有整数数据类型都以小端(首先是最低有效位)传输。
为了便于说明,这里的数据包看起来像是为一个协议传输3个字节的数据,该协议将自身标识为0x0B0A并且具有一个字节的有效负载,其值为0xFF:
53 55 03 00 00 00 0A 0B FF
DotNetOpenServer
包括一个内部功能协议(CAP),使客户端应用程序可以向服务器查询支持的协议列表。另外值得注意的是,如果客户端尝试初始化不受支持的协议,则服务器通过CAP返回错误。CAP的唯一协议标识符是0x0000。协议标识符后面的第一个字节包含命令值。
命令 | 值 | 类型 | 描述 |
GET_PROTOCOL_IDS |
0X01 |
请求 | 由客户端发送以获取服务器支持的协议ID列表 |
PROTOCOL_IDS |
0X02 |
响应 | 由服务器发送以响应GET_PROTOCOL_ID命令 |
ERROR |
0xFF |
响应 | 当客户端请求服务器不支持的协议时由服务器发送 |
这是GET_PROTOCOL_IDS
命令的样子:
53 55 03 00 00 00 00 00 01
以下是示例响应的样子:
53 55 0D 00 00 00 00 00 02 03 00 00 00 01 00 02 00 0A 00
响应有效负载包含一个Uint32
包含每个协议标识符所支持的协议数量的协议。在这种情况下,支持3种协议:1,2和10.在Hex中,它是0x0001,0x0002和0x000A。
DotNetOpenServer
包括可以选择启用或禁用的保持活动协议(KAP)。该协议的目的是三重的。首先,实现服务器以丢弃非活动连接。KAP通过来回发送非常小的数据包来保持连接的活跃性。其次,由于KAP正在发送和接收数据包,因此能够识别空闲或断开的连接,从而使两端能够关闭断开的连接,释放资源并在发生网络故障时通知客户端应用程序。最后,KAP包括一个QUIT
命令,使得两端能够在终止会话之前通知另一方,从而能够及时释放资源。如果启用,KAP是自动的,不需要也不提供任何外部方法。KAP的唯一协议标识符是0x0001
。协议标识符后面的第一个字节包含命令值。
命令 | 值 | 描述 |
KEEP_ALIVE |
0X01 |
由客户端和服务器发送以保持空闲会话打开。 |
QUIT |
0xFF |
由客户端和服务器发送,以向会话结束的终点提供通知。 |
这是KEEP-ALIVE
命令的样子:
53 55 03 00 00 00 01 00 01
我设计的DotNetOpenServer
是,开发人员可以在将来的任何时候轻松添加协议,而无需重新编译或重新部署服务器。这是使用Reflection完成的。换句话说,开发人员可以创建和安装他们的协议到服务器的预先存在的部署。通过简单地创建包含从ProtocolBase
类派生的类的.NET程序集或JAR文件来实现协议。通常,您为服务器端创建一个类,为客户端创建另一个类。实现后,您可以将服务器配置为使用app.config文件加载协议,也可以以编程方式配置服务器。最后,更新您的客户端应用程序以使用您的协议。
SDK包含的教程将指导您完成为每个支持的平台创建服务器端协议以及客户端协议的过程。
没有安全性,客户端/服务器框架就不完整。然而,SDK中包含Windows身份验证协议; 您可以根据需要创建和添加任意数量的身份验证协议。例如,服务器可以托管通过Facebook对用户进行身份验证的协议,以及通过专有企业数据库对用户进行身份验证的协议。如上所述,CAP使客户端用户可以选择认证协议。
通过简单地创建包含从AuthenticationProtocolBase
类派生的类的.NET程序集或JAR文件来实现身份验证协议。为服务器端创建一个类,然后实现您的身份验证方法。接下来,创建远程调用身份验证方法的.NET和/或Java类。如果您的身份验证方法支持角色和/或组,并且您想要检查其他协议的角色成员身份,请覆盖IsInRole
服务器端实现中的方法。如果您打算创建自己的身份验证方法,作为一个起点,我建议您查看位于附加源和GitHub中的Windows身份验证协议或数据库身份验证协议源代码。
您创建的任何协议都可以通过包含自己的授权功能构建在安全模型之上。协议实现可以通过ProtocolBase.Session.AuthenticationProtocol
属性访问调用客户端的用户名。返回的对象是一个实例AuthenticationProtocolBase
,它提供了一个UserName
属性,如上所述,它提供了一个IsInRole(string role)
方法。
创建示例服务器应用程序非常简单。
首先,创建一个.NET 4.5.2控制台应用程序。
接下来,添加DotNetOpenServer
程序集。要添加程序集,请打开NuGet程序包管理器控制台,然后键入以下命令:
PM> Install-Package UpperSetting.OpenServer
PM> Install-Package UpperSetting.OpenServer.Protocols.KeepAlive
PM> Install-Package UpperSetting.OpenServer.Protocols.WinAuth.Server
PM> Install-Package UpperSetting.OpenServer.Protocols.Hello.Server
PM> Install-Package log4net
包 | 描述 |
UpperSetting.OpenServer |
包含服务器 |
UpperSetting.OpenServer.Protocols.KeepAlive |
包含服务器和客户端Keep-Alive协议实现 |
UpperSetting.OpenServer.Protocols.WinAuth.Server |
包含服务器端Windows身份验证协议实现 |
UpperSetting.OpenServer.Protocols.Hello.Server |
包含一个示例协议,只需将hello消息回送给客户端即可 |
log4net |
包含Apache log4net程序集,使您可以使用log4net记录消息 |
如前所述,可以使用app.conifg文件或以编程方式配置服务器。两种方法都相当简单。
首先,添加代码以创建服务器。使用app.config配置服务器时,启动服务器所需的应用程序代码非常简单。只需创建一个实例US.OpenServer.Server
。当您的应用程序准备好关闭时,请调用该Server.Close
方法。例如:
using System;
using US.OpenServer;
namespace HelloServer
{
class Program
{
static void Main(string[] args)
{
Server server = new Server();
server.Logger.Log(Level.Info, "Press any key to quit.");
Console.ReadKey();
server.Close();
}
}
}
接下来,将配置添加到app.config文件中。需要3个部分:log4net,服务器和协议。一旦添加到' configSections
'元素,就必须实现每个部分。
log4net部分非常广泛,超出了本文的范围。有关更多信息,请参阅Apache log4net网站。
' server
'部分包含以下元素:
元素/属性 | 描述 |
host |
绑定TCP套接字服务器的IP地址。默认为0.0.0.0(所有IP地址)。 |
port |
用于运行服务器的TCP端口。默认为21843。 |
tls |
如果为True,则启用SSL / TLS 1.2,否则为False。默认为False。 |
tls/certificate |
X509Certificate用于验证。 |
tls/requireRemoteCertificate |
如果为True,则要求端点为身份验证提供证书,否则为False。 |
tls/allowSelfSignedCertificate |
如果为True,则启用自签名证书,否则为False。 |
tls/checkCertificateRevocation |
如果为True,则在身份验证期间检查证书吊销列表,否则为False。 |
tls/allowCertificateChainErrors |
如果为True,则在身份验证期间检查证书链,否则为False。 |
idleTimeout |
连接自动关闭之前连接可以保持空闲的秒数。默认为300秒。 |
receiveTimeout |
接收操作阻止等待数据的秒数。默认为120秒。 |
sendTimeout |
发送操作阻止等待数据的秒数。默认为120秒。 |
例如:
<server>
<host value="0.0.0.0" />
<port value="21843" />
<tls value="true"
certificate="UpperSetting.com"
requireRemoteCertificate="false"
allowSelfSignedCertificate="false"
checkCertificateRevocation="true"
allowCertificateChainErrors="false"/>
<idleTimeout value="300" />
<receiveTimeout value="120" />
<sendTimeout value="120" />
</server>
' protocols
'部分包含' item
'元素数组。每个' item
'元素包含4个属性,我在下表中定义了这些属性:
属性 | 描述 |
id |
A Uint16 指定唯一协议标识符。 |
assembly |
一个String 指定协议实现的程序集。 |
classPath |
一个String 指定实现协议的类的类路径。 |
configClassPath |
一个String 指定协议配置阅读器实现的类的类路径。 |
例如:
<protocols>
<item id="1"
assembly="US.OpenServer.Protocols.KeepAlive.dll"
classPath="US.OpenServer.Protocols.KeepAlive.KeepAliveProtocol" />
<item id="2"
assembly="US.OpenServer.Protocols.WinAuth.Server.dll"
classPath="US.OpenServer.Protocols.WinAuth.WinAuthProtocolServer"
configClassPath="US.OpenServer.Protocols.WinAuth.WinAuthProtocolConfigurationServer">
<permissions>
<roles>
<role value="Administrators" />
</roles>
<users>
<user value="TestUser" />
</users>
</permissions>
</item>
<item id="10"
assembly="US.OpenServer.Protocols.Hello.Server.dll"
classPath="US.OpenServer.Protocols.Hello.HelloProtocolServer" />
</protocols>
可以在SDK文档中找到完整的app.config示例。
最后,编译并运行。
首先,添加代码以创建服务器。从该Main
函数中创建一个US.OpenServer.Configuration.ServerConfiguration
对象,然后设置要覆盖的任何属性,包括SSL / TLS属性。
ServerConfiguration cfg = new ServerConfiguration();
cfg.TlsConfiguration.Enabled = true;
cfg.TlsConfiguration.Certificate = "UpperSetting.com";
接下来,创建一个US.OpenServer.Protocols.WinAuth.WinAuthProtocolConfigurationServer
对象,然后添加要授权访问的组和用户。
WinAuthProtocolConfigurationServer winAuthCfg = new WinAuthProtocolConfigurationServer();
winAuthCfg.AddRole("Administrators");
winAuthCfg.AddUser("TestUser");
接下来,创建一个由唯一协议标识符键入Dictionary
的US.OpenServer.Protocols.ProtocolConfiguration
对象,该标识符包含以下三个协议:
US.OpenServer.Protocols.WinAuth.WinAuthProtocolServer
US.OpenServer.Protocols.KeepAlive.KeepAliveProtocol
US.OpenServer.Protocols.Hello.HelloProtocol
Dictionary<ushort, ProtocolConfiguration> protocolConfigurations =
new Dictionary<ushort, ProtocolConfiguration>();
protocolConfigurations.Add(WinAuthProtocol.PROTOCOL_IDENTIFIER, winAuthCfg);
protocolConfigurations.Add(KeepAliveProtocol.PROTOCOL_IDENTIFIER,
new ProtocolConfiguration
(KeepAliveProtocol.PROTOCOL_IDENTIFIER, typeof(KeepAliveProtocol)));
protocolConfigurations.Add(HelloProtocol.PROTOCOL_IDENTIFIER,
new ProtocolConfiguration
(HelloProtocol.PROTOCOL_IDENTIFIER, typeof(HelloProtocolServer)));
接下来,创建US.OpenServer.Server
在传球ServerConfiguration
和Dictionary
的ProtocolConfiguration
对象。
Server server = new Server(cfg, protocolConfigurations);
最后,当您的应用程序准备好关闭时,请致电Server.Close()
。
server.Close();
此服务器示例应用程序的完整源代码可以在附加的源代码和GitHub中找到。
正如我在介绍中提到的,我想要包含适用于Android,iOS,Windows Phone,Windows,Mac和Java客户端的API。为了尽可能缩短本文,我将只向您展示如何创建Windows客户端; 该DotNetOpenServer
SDK包括每个支持的平台教程。
创建示例客户端应用程序非常简单。
创建.NET 4.5.2控制台应用程序。
添加DotNetOpenServer
程序集。要添加程序集,请打开NuGet程序包管理器控制台,然后键入以下命令:
PM> Install-Package UpperSetting.OpenServer.Windows.Client
PM> Install-Package UpperSetting.OpenServer.Protocols.KeepAlive
PM> Install-Package UpperSetting.OpenServer.Protocols.WinAuth.Client
PM> Install-Package UpperSetting.OpenServer.Protocols.Hello.Client
包 | 描述 |
UpperSetting.OpenServer.Windows.Client |
包含客户端 |
UpperSetting.OpenServer.Protocols.KeepAlive |
包含服务器和客户端Keep-Alive协议实现 |
UpperSetting.OpenServer.Protocols.WinAuth.Client |
包含客户端Windows身份验证协议实现 |
UpperSetting.OpenServer.Protocols.Hello.Client |
包含一个示例协议,它只是向服务器发送消息并接收回应响应 |
从该Main
函数中创建一个US.OpenServer.Configuration.ServerConfiguration
对象,然后设置要覆盖的任何属性,包括SSL / TLS属性。如果复制下面的代码,请将ServerConfiguration.Host
值替换为运行服务器的主机名。
ServerConfiguration cfg = new ServerConfiguration();
cfg.Host = "UpperSetting.com";
cfg.TlsConfiguration.Enabled = true;
创建一个由唯一协议标识符键入Dictionary
的US.OpenServer.Protocols.ProtocolConfiguration
对象,该标识符包含以下三个协议:
US.OpenServer.Protocols.WinAuth.WinAuthProtocolClient
US.OpenServer.Protocols.KeepAlive.KeepAliveProtocol
US.OpenServer.Protocols.Hello.HelloProtocolClient
Dictionary<ushort, ProtocolConfiguration> protocolConfigurations =
new Dictionary<ushort, ProtocolConfiguration>();
protocolConfigurations.Add(WinAuthProtocol.PROTOCOL_IDENTIFIER,
new ProtocolConfiguration
(WinAuthProtocol.PROTOCOL_IDENTIFIER, typeof(WinAuthProtocolClient)));
protocolConfigurations.Add(KeepAliveProtocol.PROTOCOL_IDENTIFIER,
new ProtocolConfiguration
(KeepAliveProtocol.PROTOCOL_IDENTIFIER, typeof(KeepAliveProtocol)));
protocolConfigurations.Add(HelloProtocol.PROTOCOL_IDENTIFIER,
new ProtocolConfiguration
(HelloProtocol.PROTOCOL_IDENTIFIER, typeof(HelloProtocolClient)));
创建US.OpenServer.Client
于传球ServerConfiguration
和Dictionary
的ProtocolConfiguration
对象。
client = new Client(cfg, protocolConfigurations);
呼叫Client.Connect
连接到服务器。
client.Connect();
要获取服务器上运行的协议列表,请致电Client.GetServerSupportedProtocolIds
。例如:
ushort[] protocolIds = client.GetServerSupportedProtocolIds();
foreach (int protocolId in protocolIds)
client.Logger.Log(Level.Info, "Server Supports Protocol ID: " + protocolId);
初始化WinAuthProtocolClient
协议,然后调用WinAuthProtocolClient.Authenticate
以验证连接。如果您复制下面的代码,请用您的用户名/密码替换下面的用户名/密码。
string userName = "TestUser";
string password = "T3stus3r";
string domain = null;
WinAuthProtocolClient wap =
client.Initialize(WinAuthProtocol.PROTOCOL_IDENTIFIER) as WinAuthProtocolClient;
if (!wap.Authenticate(userName, password, domain))
throw new Exception("Access denied.");
初始化KeepAliveProtocol
以启用客户端/服务器Keep-Alive(aka Heartbeat
)协议。
client.Initialize(KeepAliveProtocol.PROTOCOL_IDENTIFIER);
初始化HelloProtocolClient
,然后调用HelloProtocolClient.Hello
。例如:
HelloProtocolClient hpc = (HelloProtocolClient)client.Initialize
(HelloProtocol.PROTOCOL_IDENTIFIER);
string serverReponse = hpc.Hello(userName);
client.Logger.Log(Level.Info, serverReponse);
可以将每个Client构造函数参数设置为null
。如果参数设置为null
,则构造函数将使用默认属性值创建配置对象的实例,然后尝试从app.config文件加载属性。
编译并运行。客户端/服务器应用程序应显示以下输出。
Info Execution Mode: Debug
Info Press any key to quit.
Info Listening on 0.0.0.0:21843...
Info Session [1 127.0.0.1] - Connected.
Debug Session [1 127.0.0.1] - [Capabilities] Sent Protocol IDs: 1, 2, 10
Debug Session [1 127.0.0.1] - Initializing protocol 2...
Info Session [1 127.0.0.1] - [WinAuth] Authenticated \TestUser.
Debug Session [1 127.0.0.1] - Initializing protocol 10...
Info Session [1 127.0.0.1] - [Hello] Client says: TestUser
Info Session [1 127.0.0.1] - [Hello] Server responded: Hello TestUser
Debug Session [1 127.0.0.1] - Initializing protocol 1...
Debug Session [1 127.0.0.1] - [Keep-Alive] Received.
Debug Session [1 127.0.0.1] - [Keep-Alive] Received.
Debug Session [1 127.0.0.1] - [Keep-Alive] Sent.
Info Session [1 127.0.0.1] - [Keep-Alive] Quit received.
Info Session [1 127.0.0.1] - Disposed.
Info Execution Mode: Debug
Info Connecting to localhost:21843...
Info Connected to localhost:21843.
Debug Session [1 127.0.0.1] - [Capabilities] Received Protocol IDs: 1, 2, 10
Info Server Supports Protocol ID: 1
Info Server Supports Protocol ID: 2
Info Server Supports Protocol ID: 10
Debug Session [1 127.0.0.1] - Initializing protocol 2...
Info Session [1 127.0.0.1] - [WinAuth] Authenticated.
Debug Session [1 127.0.0.1] - Initializing protocol 1...
Debug Session [1 127.0.0.1] - Initializing protocol 10...
Info Session [1 127.0.0.1] - [Hello] Client says: TestUser
Info Session [1 127.0.0.1] - [Hello] Server responded: Hello TestUser
Info Hello TestUser
Info Press any key to quit.
Debug Session [1 127.0.0.1] - [Keep-Alive] Sent.
Debug Session [1 127.0.0.1] - [Keep-Alive] Sent.
Debug Session [1 127.0.0.1] - [Keep-Alive] Received.
Debug Session [1 127.0.0.1] - [Keep-Alive] Quit sent.
Info Session [1 127.0.0.1] - Closed.
此示例应用程序的完整源代码可以在附加的源代码和GitHub中找到。
我已经向您展示了如何使用开源DotNetOpenServer
SDK创建智能移动设备应用程序,以安全地访问在云中运行的数据和/或业务逻辑。我提供了几个链接,向您展示如何创建自己的协议,包括如何实现自己的身份验证模型。我详细介绍了如何使用SDK创建Windows客户端/服务器应用程序,并提供了创建Android,iOS,Windows Phone,Mac和Java客户端的链接。
我希望这个开源项目对社区有益,我欢迎你的所有评论。非常感谢您阅读本文。
可扩展的TCP客户端/服务器应用程序框架 转载https://www.codesocang.com/appboke/40317.html
热门源码