说起TCP大家肯定都不陌生,传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793 定义。
TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。
那么
对于C#又应该怎么使用TCP呢,实际上微软已经设置了TCP协议的抽象模型类,也就是大家熟知的Socket,以及更高级的TcpClient等,诸如此类的使用,这里也不做多解释。但是对于高并发,高性能等问题,这些偏底层的类就需要自己开发了,所以这也是我自己开发RRQMSocket
的初衷,希望这个程序集能给你带来惊喜。
首先我们先来介绍一下该程序集的一些功能
RRQMSocket
RRQMBox
安装RRQMSocket
即可,具体步骤详看链接博客。
VS、Unity安装和使用Nuget包
TcpService是TCP服务器基类,但是不参与实际的数据交互,实际的数据交互由SocketClient完成,所以TcpService的功能只是配置、激活、管理、注销SocketClient类实例,此二者均为抽象类,不可直接创建其实例。
在SocketClient中,必须实现HandleReceivedData方法,该方法指示如何处理已接收数据或经过适配器转换的对象。所以具体创建过程如下。
通过继承的方式,可以重载OnConnecting方法,用于初始化设置(例如:适配器、属性赋值、分包策略等)。
public class MyTcpService : TcpService<MySocketClient>
{
protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e)
{
//socketClient.SetDataHandlingAdapter(new NormalDataHandlingAdapter());//普通TCP报文处理器
//或
e.DataHandlingAdapter = new NormalDataHandlingAdapter();
e.IsPermitOperation = true;//决定允不允许连接
base.OnConnecting(socketClient, e);
}
}
继承实现HandleReceivedData方法,才能具体的处理数据。当前的对象实例(this),即对应TCP信道通信。
public class MySocketClient : SocketClient
{
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
{
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, (int)byteBlock.Length);
Console.WriteLine($"已从{
this.Name}接收到信息:{
mes}");//Name即IP+Port
}
}
MyTcpService service = new MyTcpService();
service.Connected += (client, e) =>
{
//有客户端连接
};
service.Disconnected += (client, e) =>
{
//有客户端断开连接
};
//声明配置
var config = new TcpServiceConfig();
config.ListenIPHosts = new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) };//同时监听两个地址
config.BufferLength = 1024 * 64;//缓存池容量
config.BytePoolMaxSize = 512 * 1024 * 1024;//单个线程内存池容量
config.BytePoolMaxBlockSize = 20 * 1024 * 1024;//单个线程内存块限制
config.Logger = new Log();//日志记录器,可以自行实现ILog接口。
config.ServerName = "RRQMService";//服务名称
config.SeparateThreadReceive = false;//独立线程接收,当为true时可能会发生内存池暴涨的情况
config.ThreadCount = 5;//多线程数量,当SeparateThreadReceive为false时,该值只决定BytePool的数量。
config.Backlog = 30;
config.ClearInterval = 60 * 1000;//60秒无数据交互会清理客户端
config.ClearType = ClearType.Receive | ClearType.Send;//清理统计
config.MaxCount = 10000;//最大连接数
//载入配置
service.Setup(config);
//启动
try
{
service.Start();
Console.WriteLine("启动成功");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
普通模式的创建,很大程度的可以灵活使用,但是有时候,我们只想搭建一个简单的服务器,那么这时候,直接创建SimpleTcpService即可。
SimpleTcpService service = new SimpleTcpService();
service.Connected += (client, e) =>
{
//有客户端连接
};
service.Disconnected += (client, e) =>
{
//有客户端断开连接
};
service.Connecting += (client, e) =>
{
client.SetDataHandlingAdapter(new NormalDataHandlingAdapter());
//e.IsPermitOperation = false;//是否允许连接
};
service.Received += (client, byteBlock ,obj) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, (int)byteBlock.Length);
Console.WriteLine($"已从{
client.Name}接收到信息:{
mes}");//Name即IP+Port
};
//声明配置
var config = new TcpServiceConfig();
config.ListenIPHosts = new IPHost[] {
new IPHost("127.0.0.1:7789"), new IPHost(7790) };//同时监听两个地址
config.BufferLength = 1024 * 64;//缓存池容量
config.BytePoolMaxSize = 512 * 1024 * 1024;//单个线程内存池容量
config.BytePoolMaxBlockSize = 20 * 1024 * 1024;//单个线程内存块限制
config.Logger = new Log();//日志记录器,可以自行实现ILog接口。
config.ServerName = "RRQMService";//服务名称
config.SeparateThreadReceive = false;//独立线程接收,当为true时可能会发生内存池暴涨的情况
config.ThreadCount = 5;//多线程数量,当SeparateThreadReceive为false时,该值只决定BytePool的数量。
config.Backlog = 30;
config.ClearInterval = 60 * 1000;//60秒无数据交互会清理客户端
config.ClearType = ClearType.Receive | ClearType.Send;//清理统计
config.MaxCount = 10000;//最大连接数
//载入配置
service.Setup(config);
//启动
try
{
service.Start();
Console.WriteLine("简单服务器启动成功");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
完成以上步骤后,就可以拥有一个高性能的TCP服务器,此时可以用NetAssist进行测试。
完成了接收,那如何回复消息呢?
在RRQMSocket中,以
SocketClient
结尾的类,则表明该类是服务器辅助类,其功能就是与客户端一一对应,且负责通信。
在普通TcpService模式中,MySocketClient
的类会在每个客户端连接后创建实例,那么该实例就会与客户端一一对应,所以调用this
中所包含的方法,即可回复消息。
在简单TcpService模式中,SimpleSocketClient
的类会在每个客户端连接后创建实例,那么该实例就会与客户端一一对应,所以调用触发事件的client
即可回复消息。