.net core高效能通訊開源元件BeetleX
BeetleX
beetleX是基於dotnet core實現的輕量級高效能的TCP通訊元件,使用方便、效能高效和安全可靠是元件設計的出發點!開發人員可以在Beetlx元件的支援下快帶地構建高效能的TCP通訊服務程式,在安全通訊方面只需要簡單地設定一下SSL資訊即可實現可靠安全的SSL服務。
專案地址: https://github.com/IKende/BeetleX 國內地址: https://gitee.com/ikende/BeetleX
使用方便性
beetleX網路流讀寫是基於Stream標準來構建,僅僅基於Stream的基礎讀寫對於應用者來說還是過於繁瑣;元件為了更方便進行網路資料處理在Stream的基礎之上擴充套件了一系列的讀寫規則:ReadLine、ReadInt、WriteLine、WriteInt等一系列簡便方法,在這些方法的支援下使用者就可以更輕鬆地處理資料;為了在網路通訊中更好的相容其他平臺協議以上方法都相容Big-Endian和Little-Endian不同方式。為了更好地利用現有序列化元件,元件通過IPacket介面規範訊息擴充套件,通過實現不同的Packet直譯器,即可以實現基於Protobuf,json和Msgpack等方式的物件資料傳輸。
高效能特性
beetleX的高效能是建立在內部一個數據流處理物件PipeStream,它是構建在Stream標準之上;它和.NET內建的NetworkStream最大的差別是PipeStream的讀寫基於SocketAsyncEventArgs實現,這正是在編寫高效能網路資料處理所提倡的模式。PipeStream不僅在網路資料處理模式上有著效能的優勢,在記憶體讀寫上和MemoryStream也有著很大的區別;由於PipeStream的記憶體塊是以一個基於連結串列的SocketAsyncEventArgs Buffer 組成,因此PipeStream在寫入大資料的情況並不存在記憶體擴容和複製的問題;基於SocketAsyncEventArgs Buffer作為基礎記憶體塊還有一個好處是在協議資料和網路快取讀寫並不存在記憶體塊複製。如果在應用中中使用PipeStream相應的BinaryReader和IBinaryWriter讀寫規範,那大部分資料處理基本不存在記憶體複製過程,從而讓資料處理效能更高效。
以下是PipeStream的結構:
效能
beetleX的效能到底怎樣呢,以下簡單和DotNetty進行一個網路資料交換的效能測試,分別是1K,5K和10K連線數下資料請求併發測試
DotNetty測試程式碼
public override void ChannelRead(IChannelHandlerContext context, object message) { var buffer = message as IByteBuffer; context.WriteAsync(message); }
Beetlex 測試程式碼
public override void SessionReceive(IServer server, SessionReceiveEventArgs e) { server.Send(e.Stream.ToPipeStream().GetReadBuffers(), e.Session); base.SessionReceive(server, e); }
測試結果
1K connections
5K connections
10K connections
構建TCP Server
class Program : ServerHandlerBase { private static IServer server; public static void Main(string[] args) { NetConfig config = new NetConfig(); //ssl //config.SSL = true; //config.CertificateFile = @"c:\ssltest.pfx"; //config.CertificatePassword = "123456"; server = SocketFactory.CreateTcpServer<Program>(config); server.Open(); Console.Write(server); Console.Read(); } public override void SessionReceive(IServer server, SessionReceiveEventArgs e) { string name = e.Stream.ToPipeStream().ReadLine(); Console.WriteLine(name); e.Session.Stream.ToPipeStream().WriteLine("hello " + name); e.Session.Stream.Flush(); base.SessionReceive(server, e); } }
構建TCP Client
class Program { static void Main(string[] args) { TcpClient client = SocketFactory.CreateClient<TcpClient>("127.0.0.1", 9090); //ssl //TcpClient client = SocketFactory.CreateSslClient<TcpClient>("127.0.0.1", 9090, "localhost"); while (true) { Console.Write("Enter Name:"); var line = Console.ReadLine(); client.Stream.ToPipeStream().WriteLine(line); client.Stream.Flush(); var reader = client.Read(); line = reader.ToPipeStream().ReadLine(); Console.WriteLine(line); } Console.WriteLine("Hello World!"); } }
非同步Client
class Program { static void Main(string[] args) { AsyncTcpClient client = SocketFactory.CreateClient<AsyncTcpClient>("127.0.0.1", 9090); //SSL //AsyncTcpClient client = SocketFactory.CreateSslClient<AsyncTcpClient>("127.0.0.1", 9090, "serviceName"); client.ClientError = (o, e) => { Console.WriteLine("client error {0}@{1}", e.Message, e.Error); }; client.Receive = (o, e) => { Console.WriteLine(e.Stream.ToPipeStream().ReadLine()); }; var pipestream = client.Stream.ToPipeStream(); pipestream.WriteLine("hello henry"); client.Stream.Flush(); Console.Read(); } }
實現一個Protobuf物件直譯器
public class Packet : FixedHeaderPacket { public Packet() { TypeHeader = new TypeHandler(); } private PacketDecodeCompletedEventArgs mCompletedEventArgs = new PacketDecodeCompletedEventArgs(); public void Register(params Assembly[] assemblies) { TypeHeader.Register(assemblies); } public IMessageTypeHeader TypeHeader { get; set; } public override IPacket Clone() { Packet result = new Packet(); result.TypeHeader = TypeHeader; return result; } protected override object OnReader(ISession session, PipeStream reader) { Type type = TypeHeader.ReadType(reader); int bodySize = reader.ReadInt32(); return reader.Stream.Deserialize(bodySize, type); } protected override void OnWrite(ISession session, object data, PipeStream writer) { TypeHeader.WriteType(data, writer); MemoryBlockCollection bodysize = writer.Allocate(4); int bodyStartlegnth = (int)writer.CacheLength; ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(writer.Stream, data); bodysize.Full((int)writer.CacheLength - bodyStartlegnth); } }
BeetleX的介紹暫時到這裡,如果需要了解專案的情況可以到Github下載相關程式碼和Samples,如果有疑問可以在Gibhub上提相關issue。