BeetleX之TCP服务应用详解
BeetleX是.net core平台下的一个开源TCP 通讯组件,它不仅使用简便还提供了出色性能的支持,可以轻易让你实现上百万级别RPS吞吐的服务应用。组件所提供的基础功能也非常完善,可以让你轻易扩展自己的服务应用,以下提组件集成的功能:
完善的会话管理机制,可以根据连接状态和相关日志
专门针对内存池实现的异步流读写,支持标准Stream的同并提供高效的性能
消息IO合并,广播序列化合并等性能强化功能
提供简洁的协议扩展规范,轻易实现http,websocket,mqtt等应用通讯协议
支持TLS,让你构建的通讯服务更安全可靠
扩展的组件
以下是Beetlex扩展的一些功能组件
- https://github.com/IKende/FastHttpApi
- https://github.com/IKende/Bumblebee
- https://github.com/IKende/BeetleX.Redis
- https://github.com/IKende/XRPC
- https://github.com/IKende/HttpClients
性能
一开始说组可以让你现上百万级别RPS吞吐的服务应用其实一点不假,BeetleX的基础性能有这样的支撑能力;虽然组件不能说是.net core上性能最好的,但在功能和综合性能上绝对非常出色(详细可以https://tfb-status.techempower.com/ 查看测试结果,可惜这个网站提交的.net core组件比较少,大部都是基于aspcore的通讯模块扩展).以下是JSON serialization基础输出的一个测试结果(Plaintext在官方的测试环境一直没办法跑起来....)

在测试中组件只落后于aspcore-rhtx 这是红帽专门针对 .net core编写的linux网络驱动.
Single query

构建基础TCP应用
组件在构建TCP服务的时候非常简单,主要归功于它提供了完善的Stream读写功能,而这些功能让你完全不用关心bytes的读写。基于Stream的好处就是可以轻松和第三方序列化的组件进行整合。以下是简单地构建一个Hello服务。
class Program : ServerHandlerBase
{
private static IServer server;
public static void Main(string[] args)
{
server = SocketFactory.CreateTcpServer<Program>();
//server.Options.DefaultListen.Port =9090;
//server.Options.DefaultListen.Host = "127.0.0.1";
server.Open();
Console.Read();
}
public override void SessionReceive(IServer server, SessionReceiveEventArgs e)
{
var pipeStream = e.Stream.ToPipeStream();
if (pipeStream.TryReadLine(out string name))
{
Console.WriteLine(name);
pipeStream.WriteLine("hello " + name);
e.Session.Stream.Flush();
}
base.SessionReceive(server, e);
}
}
以上就是一个简单的TCP服务,让以代码正常运行需要引用Beetlex最新版的组件可以在Nuget上找到。以上服务的功能很简单当接收数据后尝试从流中读取一行字符,如果读取成功则把内容写入到流中提交返回。通过以上代码是不是感觉写个服务比较简单(但是PipeStream并不是线程安全的,所以不能涉及到多线程读写它)
协议处理规则
其实PipeStream处理数据已经非常方便了,那为什么还需要制定一个协议处理规范呢?前面已经说了PipeStream并不是线程安全的,很容易带来使用上的风险,所以引入协议处理规则来进行一个安全约束的同时可以实现多线程消息处理。组件提供了这样一个接口来规范消息的处理,接口如下:
public interface IPacket : IDisposable
{ EventHandler<EventArgs.PacketDecodeCompletedEventArgs> Completed
{
get; set;
} IPacket Clone(); void Decode(ISession session, System.IO.Stream stream); void Encode(object data, ISession session, System.IO.Stream stream); byte[] Encode(object data, IServer server); ArraySegment<byte> Encode(object data, IServer server, byte[] buffer);
}
如果你要处理消息对象,则需要实现以上接口(当然这个接口的实现不是必须的,只要把握好PipeStream安全上的控制就好);但实现这接口来处理消息可以带很多好处,可以多消息合并IO,广播消息合并序列化等高效的功能。不过在不了解组件的情况实现这个接口的确也是有些难度的,所以组件提供了一个基础的类FixedHeaderPacket,它是一个抽像类用于描述有个消息头长的信息流处理。
字符消息分包
接下来通过FixedHeaderPacket来实现一个简单的字符分包协议消息;主要在发送消息的时候添加一个大小头用来描述消息的长度(这是在TCP中解决粘包的主要手段)。
public class StringPacket : BeetleX.Packets.FixedHeaderPacket
{
public override IPacket Clone()
{
return new StringPacket();
} protected override object OnReader(ISession session, PipeStream stream)
{
return stream.ReadString(CurrentSize);
}
protected override void OnWrite(ISession session, object data, PipeStream stream)
{
stream.Write((string)data);
}
}
通过FixedHeaderPacket制定一个分包规则是非常简单的,主要实现读写两个方法。下面即可在服务中引用这个包作为TCP数据流的分析规则:
class Program : ServerHandlerBase
{
private static IServer server;
public static void Main(string[] args)
{
server = SocketFactory.CreateTcpServer<Program,StringPacket>();
//server.Options.DefaultListen.Port =9090;
//server.Options.DefaultListen.Host = "127.0.0.1";
server.Open();
Console.Read();
}
protected override void OnReceiveMessage(IServer server, ISession session, object message)
{
Console.WriteLine(message);
server.Send($"hello {message}", session);
}
}
经过分析器包装后,就再也不用流来处理数据了,可以直接进行对像的发送处理。
集成Protobuf
处理String并不是友好的事情,毕竟没有对象来得直观和操作方便;以下是通过FixedHeaderPacket扩展Protobuf对象传输,以下是针对Protobuf的规则扩展:
public class ProtobufPacket : BeetleX.Packets.FixedHeaderPacket
{
static ProtobufPacket()
{
TypeHeader.Register(typeof(ProtobufClientPacket).Assembly);
}
public static BeetleX.Packets.CustomTypeHeader TypeHeader { get; set; } = new BeetleX.Packets.CustomTypeHeader(BeetleX.Packets.MessageIDType.INT); public override IPacket Clone()
{
return new ProtobufPacket();
} protected override object OnReader(ISession session, PipeStream stream)
{
Type type = TypeHeader.ReadType(stream);
var size = CurrentSize - ;
return ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(stream, null, type, size);
} protected override void OnWrite(ISession session, object data, PipeStream stream)
{
TypeHeader.WriteType(data, stream);
ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(stream, data);
}
}
使用规则分析器
class Program : ServerHandlerBase
{
private static IServer server;
public static void Main(string[] args)
{
server = SocketFactory.CreateTcpServer<Program, Messages.ProtobufPacket>();
//server.Options.DefaultListen.Port =9090;
//server.Options.DefaultListen.Host = "127.0.0.1";
server.Open();
Console.Read();
}
protected override void OnReceiveMessage(IServer server, ISession session, object message)
{
((Messages.Register)message).DateTime = DateTime.Now;
server.Send(message, session);
}
}
不同序列化的扩展
既然有了一个Protobuf作为样本,那针对其他序列化的实现就比较简单了
- json
public class JsonPacket : BeetleX.Packets.FixedHeaderPacket
{
static JsonPacket()
{
TypeHeader.Register(typeof(JsonClientPacket).Assembly);
}
public static BeetleX.Packets.CustomTypeHeader TypeHeader { get; set; } = new BeetleX.Packets.CustomTypeHeader(BeetleX.Packets.MessageIDType.INT); public override IPacket Clone()
{
return new JsonPacket();
} protected override object OnReader(ISession session, PipeStream stream)
{
Type type = TypeHeader.ReadType(stream);
var size = CurrentSize - ;
var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(size);
stream.Read(buffer, , size);
try
{
return SpanJson.JsonSerializer.NonGeneric.Utf8.Deserialize(new ReadOnlySpan<byte>(buffer, , size), type);
}
finally
{
System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
}
} protected override void OnWrite(ISession session, object data, PipeStream stream)
{
TypeHeader.WriteType(data, stream);
var buffer = SpanJson.JsonSerializer.NonGeneric.Utf8.SerializeToArrayPool(data);
try
{
stream.Write(buffer.Array, buffer.Offset, buffer.Count);
}
finally
{
System.Buffers.ArrayPool<byte>.Shared.Return(buffer.Array);
}
}
}
- messagepack
public class MsgpackPacket : BeetleX.Packets.FixedHeaderPacket
{
static MsgpackPacket()
{
TypeHeader.Register(typeof(MsgpackClientPacket).Assembly);
}
public static BeetleX.Packets.CustomTypeHeader TypeHeader { get; set; } = new BeetleX.Packets.CustomTypeHeader(BeetleX.Packets.MessageIDType.INT); public override IPacket Clone()
{
return new MsgpackPacket();
} protected override object OnReader(ISession session, PipeStream stream)
{
Type type = TypeHeader.ReadType(stream);
var size = CurrentSize - ;
return MessagePackSerializer.NonGeneric.Deserialize(type, stream, true);
} protected override void OnWrite(ISession session, object data, PipeStream stream)
{
TypeHeader.WriteType(data, stream);
MessagePackSerializer.NonGeneric.Serialize(data.GetType(), stream, data);
}
}
更多示例
https://github.com/IKende/BeetleX-Samples
BeetleX之TCP服务应用详解的更多相关文章
- BeetleX之FastHttpApi服务使用详解
BeetleX是开个轻量级高性能的开源TCP通讯应用框架,通过BeetleX可以轻松扩展不同场的TCP应用服务和客户端组件.框架开源地址:https://github.com/IKende/Beetl ...
- TCP/IP协议详解概述
TCP/IP协议详解卷1--第一章概述--读书笔记 作者:vpoet 日期:2015/06/25 注:本系列的文章只是作者对TCP/IP协议的理解,难免会出现纰漏或者不完整,当然也有可能很肤浅,希望大 ...
- 【转载】TCP /IP协议详解
首先,TCP/IP不是一个协议,而是一个协议族的统称. 里面包括了IP协议,IMCP协议,TCP协议,以及http.ftp.pop3协议等等. TCP/IP协议分层 提到协议分层,我们很容易联想到IS ...
- TCP、UDP详解与抓包工具使用
参考:https://www.cnblogs.com/HPAHPA/p/7737641.html TCP.UDP详解 1.传输层存在的必要性 由于网络层的分组传输是不可靠的,无法了解数据到达终点的时间 ...
- 2-4、nginx特性及基础概念-nginx web服务配置详解
Nginx Nginx:engine X 调用了libevent:高性能的网络库 epoll():基于事件驱动event的网络库文件 Nginx的特性: 模块化设计.较好扩展性(不支持模块动态装卸载, ...
- TCP/IP协议详解---概述
工作之后,才发现以前在学校里学的东西忘得太快太干净了,现在需要一点点地捡起来了,要不然写几行程序会闹很多笑话会出现很多bug的.从今天开始,翻一翻<TCP/IP协议详解 卷1>这本 ...
- TCP /IP协议详解【转】
转自:https://www.jianshu.com/p/0cf648510bce?utm_campaign=maleskine&utm_content=note&utm_medium ...
- [转]TCP滑动窗口详解
TCP滑动窗口详解 http://lyjdamzwf.blog.163.com/blog/static/75206837201193373226/ TCP滑动窗口(Sliding Window) ...
- Linux:SSH服务配置文件详解
SSH服务配置文件详解 SSH客户端配置文件 /etc/ssh/ssh——config 配置文件概要 Host * #选项“Host”只对能够匹配后面字串的计算机有效.“*”表示所有的计算机. For ...
随机推荐
- HTML的条件注释和hack技术
在很多时候,前端的兼容性问题,都很让人头痛!幸运的是,微软从去年声明:从2016年1月12日起,微软将停止为IE8(包括IE8)提供技术支持和安全更新.整个前端圈子都沸腾起来,和今年七月份Adobe宣 ...
- Java流程控制之(四)中断
目录 break continue return 标签 在程序设计时,循环直接的跳转显得十分重要,虽然Java没有提供goto语句去控制程序的跳转,但为了控制循环,Java提供了continue,br ...
- 2019-10-8:渗透测试,基础学习,php基础,会话,文件包含,笔记
php面向对象基础->调用符号构造函数construct,主要用来创建对象时初始化对象,为成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 析构函数destructor,与构造函数相 ...
- find_all的用法 Python(bs4,BeautifulSoup)
find_all()简单说明: find_all() find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件 用法一: rs=soup.find_all('a') 将返 ...
- 【设计模式大法】Iterator模式
Iterator模式 --一个一个遍历 在Java中的for语句中 i++的作用是让 i 的值在每次循环后自增1,这样就可以访问数组中的下一个元素.下下一个元素.再下下一个元素,也就实现了从头至尾逐一 ...
- 网络层 IP
网络层 -- 数据包 网络层作用 解决什么问题? 在讲网络层之前,其实基于广播的这种通信就可以实现全世界通信了,你吼一声,如果全世界是一个局域网,全世界的计算机肯定可以听得见,从理论上似乎行得通,如果 ...
- TensorFlow2.0
安装开发环境 1.首先安装 anaconda(https://www.anaconda.com/) 2.修改anaconda的镜像源 conda config --add channels https ...
- 神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(一)
开心一刻 我:嗨,老板娘,有冰红茶没 老板娘:有 我:多少钱一瓶 老板娘:3块 我:给我来一瓶,给,3块 老板娘:来,你的冰红茶 我:玩呐,我要冰红茶,你给我个瓶盖干哈? 老板娘:这是再来一瓶,我家卖 ...
- 关于javascript中=的返回值
今天看了一段代码,大概是这样的: function test(){ a=4; b=5; return b=a; } test();//返回? 返回值是多少呢?运行结果是4 这可以理解为将a的值赋给b以 ...
- CSRF的原理与防御 | 你想不想来一次CSRF攻击?
CSRF是Cross Site Request Forgery的缩写,中文翻译过来是跨站请求伪造.这个漏洞往往能给用户带来巨大的损失,CSRF在等保安全检测中,也是一个非常重要的检测项.但是在我们的网 ...