我们在工作中肯定会遇到网络通信方便的软件需要维护和开发,不管是C++,C#,java中原生的Socket我们可以写过。我们都知道定义一套完整的Socket通讯服务端和客户端以及网络通讯的协议是一件很麻烦的事情,而今天要介绍的Cowboy.Sockets开源框架帮助我们搭建好了通讯的服务端和客户端,同时网络通讯中所使用的数据协议Cowboy.Sockets也帮我们制定好了一个框架,方便了我们后续开发,提高了程序员们的开发效率。
github地址:https://github.com/ninenines/cowboy
1.CowBoy源码介绍
本篇我们主要介绍CowBoy.Sockets的源码结构,及搭建一个简单的网络服务器的过程。可以看到搭建Tcp的网络服务主要用到源码Tcp目录下的Framing 和 Server部分,这里我们采用APM方式。
APM 方式:TcpSocketServer
TcpSocketServer 的实现是基于 .NET Framework 自带的 TcpListener 和 TcpClient 的更进一步的封装,采用基于 APM 的 BeginXXX 和 EndXXX 接口实现。
TcpSocketServer 中的 Accept Loop 指的就是,
- BeginAccept -> EndAccept-> BeginAccept -> EndAccept -> BeginAccept -> ...
每一个建立成功的 Connection 由 TcpSocketSession 来处理,所以 TcpSocketSession 中会包含 Read Loop,
- BeginRead -> EndRead -> BeginRead -> EndRead -> BeginRead -> ...
而Framing文件夹中的内容是来定义我们在通讯过程中所发送的消息结构的定义组包,解包等,以及过滤。
2.新建CowBoyDemo服务端工程
2.1新建.net解决方案,新建类库项目Cowboy.Socket,将源码中Buffer,Tcp中的源码拷贝到项目如下:
2.2新建test控制台项目,用于测试,代码非常简单
a)new TcpSocketServer(5555, config);
b)监听TcpSocketServer类暴露的ClientConnected,ClientDisconnected,ClientDataReceived三个事件
class Program
{
static TcpSocketServer _server;
static void Main(string[] args)
{
StartServer();
Console.WriteLine("TCP server has been started.");
while (true)
{
try
{
string text = Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
_server.Shutdown();
Console.WriteLine("TCP server has been stopped on [{0}].", _server.ListenedEndPoint);
Console.ReadKey();
}
}
}
private static void StartServer()
{
var config = new TcpSocketServerConfiguration();
//config.UseSsl = true;
//config.SslServerCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(@"D:\\Cowboy.pfx", "Cowboy");
//config.SslPolicyErrorsBypassed = false;
//config.FrameBuilder = new FixedLengthFrameBuilder(20000);
config.FrameBuilder = new RawBufferFrameBuilder();
//config.FrameBuilder = new LineBasedFrameBuilder();
//config.FrameBuilder = new LengthPrefixedFrameBuilder();
//config.FrameBuilder = new LengthFieldBasedFrameBuilder();
_server = new TcpSocketServer(5555, config);
_server.ClientConnected += server_ClientConnected;
_server.ClientDisconnected += server_ClientDisconnected;
_server.ClientDataReceived += server_ClientDataReceived;
_server.Listen();
}
static void server_ClientConnected(object sender, TcpClientConnectedEventArgs e)
{
Console.WriteLine(string.Format("TCP client {0} has connected {1}.", e.Session.RemoteEndPoint, e.Session));
}
static void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
{
Console.WriteLine(string.Format("TCP client {0} has disconnected.", e.Session));
}
static void server_ClientDataReceived(object sender, TcpClientDataReceivedEventArgs e)
{
var text = Encoding.UTF8.GetString(e.Data, e.DataOffset, e.DataLength);
Console.Write(string.Format("Client : {0} {1} --> ", e.Session.RemoteEndPoint, e.Session));
if (e.DataLength < 1024 * 1024 * 1)
{
Console.WriteLine(text);
}
else
{
Console.WriteLine("{0} Bytes", e.DataLength);
}
_server.SendTo(e.Session, Encoding.UTF8.GetBytes(text));
}