. NET open-source high-performance Socket communication middleware Helios introduction and demonstration, middleware helios
I. What is Helios?
Helios is a high-performance Socket communication middleware written in C. The development of Helios is inspired by Netty and uses a non-blocking event-driven model architecture to achieve high concurrency and high throughput. Helios greatly simplifies Socket programming for us. It has already handled unwrapped, stuck, and buffer management for us in the case of high concurrency.
GitHub: https://github.com/helios-io/helios/
To avoid misunderstanding, note: helios is not my work, and the younger brother is still working hard.
Ii. Features of Helios 1. Powerful APIs
Takes the complexity out of socket programming with intelligent I/O, concurrency, buffer management, and pipelining APIs.
Socket programming is no longer complicated. Provides intelligent APIs in the form of I/O, concurrency, buffer management, and pipelines.
2. Event-Driven
Helios is Reactive-it uses a event-driven architecture to simplify development and build responsive systems that scale.
Helios is reactive. It uses an event-driven architecture to simplify development and build a scalable system.
3. snapshot t
Performance is a cross-cutting concern we factor in at every level in the design of the framework in order to eliminate overhead for your apps and clients.
This system fully considers performance during development and design. When building your app and client, eliminate this concern.
4. Battle-Tested
Helios powers the clustering and remoting capbilities built into Akka. NET and more.
The remote function of Akka.net cluster is built on Helios.
3. A Helios-based chat room example
The best example to demonstrate Socket communication is nothing more than a chat program.
The entire solution contains three projects:
1. HeliosChat. Common
This project contains some common types. After the new project is created, use nuget to add the helios library.
Message class: All sent messages are packaged by Message. Each Message is composed of a Command and Content.
public class Message { public Command Command { get; set; } public string Content { get; set; } }
Command enumeration: a Command used to describe a message
public enum Command { Join, Send, }
MessageConverter static class: this class is used to convert a Message object to Byte [], or to convert a Byte [] to a Message object. When the Message object is transmitted through Helios, it needs to be converted to Byte [] First, so we need to define the package format ourselves. We use the first four digits of Byte [] to store the Command. After the Content is converted to a Byte, it starts to store the Command at the first 5th bits.
public class MessageConverter { public static Message ToMessage(NetworkData data) { try { var commandData = data.Buffer.Take(4).ToArray(); var contentData = data.Buffer.Skip(4).Take(data.Buffer.Length - 4).ToArray(); var command = BitConverter.ToInt32(commandData,0); var content = Encoding.UTF8.GetString(contentData); return new Message() { Command = (Command)command, Content = content }; } catch (Exception exc) { Console.WriteLine("Cant convert NetworkData to Message : {0}", exc.Message); } return null; } public static byte[] ToBytes(Message message) { try { var commandBytes = BitConverter.GetBytes((int)message.Command); var messageBytes = Encoding.UTF8.GetBytes(message.Content); var bytes = new byte[commandBytes.Length + messageBytes.Length]; commandBytes.CopyTo(bytes, 0); messageBytes.CopyTo(bytes, commandBytes.Length); return bytes; } catch (Exception exc) { Console.WriteLine("Cant convert message to bytes : {0}", exc.Message); } return null; } }
2. HeliosChat. Server
Needless to say, this is the server of the chat room, which is responsible for connecting users and forwarding messages.
Internal class Program {private static readonly ConcurrentDictionary <string, IConnection> Clients = new ConcurrentDictionary <string, IConnection> (); private static void Main (string [] args) {var host = IPAddress. any; var port = 9991; Console. title = "Server"; Console. writeLine ("Starting server on {0 }:{ 1}", host, port); var serverFactory = new ServerBootstrap (). setTransport (TransportType. tcp ). bui Ld (); var server = serverFactory. newReactor (NodeBuilder. buildNode (). host (host ). withPort (port); server. onConnection + = (address, connection) => {Console. writeLine ("Connected: {0}", address); connection. beginReceive (Receive) ;}; server. onDisconnection + = (reason, address) => Console. writeLine ("Disconnected: {0}; Reason: {1}", address. remoteHost, reason. type); server. start (); Console. writeLine ("Run Ning, press any key to exit "); Console. readKey ();} /// <summary> /// process the received message // </summary> /// <param name = "data"> </param> // <param name = "channel"> </param> public static void Receive (NetworkData data, IConnection channel) {var message = MessageConverter. toMessage (data); switch (message. command) {case Command. join: JoinGroup (message. content, channel); break; case Command. send: Broadcast (mess Age. content); break;} public static void JoinGroup (string clientName, IConnection channel) {if (Clients. tryAdd (clientName, channel) {Broadcast (string. format ("{0} join group successful. ", clientName);} else {var errMsg = new Message () {Command = Command. send, Content = "client name is used. "}; SendMessage (channel, errMsg) ;}/// <summary> // broadcast message /// </summary> /< param name =" clien TMessage "> </param> public static void Broadcast (string clientMessage) {Console. writeLine (clientMessage); var clientName = clientMessage. split (':') [0]; var message = new Message {Command = Command. send, Content = clientMessage}; foreach (var client in Clients) {if (client. key! = ClientName) {SendMessage (client. value, message) ;}} public static void SendMessage (IConnection connection, Message message) {var messageBytes = MessageConverter. toBytes (message); connection. send (new NetworkData {Buffer = messageBytes, Length = messageBytes. length });}}
3. HeliosChat. Client
Chat client
Internal class Program {public static IConnection Client; public static string ClientName; private static void Main (string [] args) {var host = IPAddress. loopback; var port = 9991; var connectionFactory = new ClientBootstrap (). setTransport (TransportType. tcp ). build (); // a New Client = connectionFactory. newConnection (Node. empty (), NodeBuilder. buildNode (). host (host ). withPort (port); Client. onC Onnection + = (address, connection) => {Console. writeLine ("Connect server successful. "); connection. beginReceive (Received) ;}; Client. onDisconnection + = (address, reason) => Console. writeLine ("Disconnected. "); Console. writeLine ("Input ClientName"); ClientName = Console. readLine (); Console. title = string. format ("Client {0}", ClientName); // establish a connection to the Client. open (); // Join the chat group Join (); // wait for the input WaitInput ();} Public static void WaitInput () {while (true) {var input = Console. ReadLine (); if (! String. isNullOrEmpty (input) {var message = MakeSendMessage (input); SendMessage (Client, message );}}} /// <summary> /// Jion chat group /// </summary> public static void Join () {var message = MakeJoinMessage (); SendMessage (Client, message );} /// <summary> /// process the received message // </summary> /// <param name = "data"> </param> // <param name = "responseChannel"> </param> public static void Received (NetworkData data, IConnection responseChannel) {var message = MessageConverter. toMessage (data); if (message. command = Command. send) {Console. writeLine (message. content );}} /// <summary> /// construct the chat message /// </summary> /// <param name = "input"> </param> /// <returns> </returns> public static Message MakeSendMessage (string input) {return new Message {Command = Command. send, Content = string. format ("{0 }:{ 1}", ClientName, input )};} /// <summary> /// construct the Message to join the group /// </summary> /// <returns> </returns> public static Message MakeJoinMessage () {var message = new Message (); message. command = Command. join; message. content = ClientName; return message;} public static void SendMessage (IConnection connection, Message message) {var messageBytes = MessageConverter. toBytes (message); connection. send (new NetworkData {Buffer = messageBytes, Length = messageBytes. length });}}
4. Running result
Such a simple chat room program is complete.
Iv. Helios 2.0
The asynchronous programming model of helios 1.0 is based on APM. From helios 2.0, it will be changed to SocketAsyncEventArgs to implement Asynchronization. SocketAsyncEventArgs encapsulates IOCP at the underlying layer. IOCP is the technology with the highest Socket communication performance on Windows server. helios 2.0 with IOCP is bound to have higher performance. Therefore, helios 2.0 is very promising.
Example download: http://files.cnblogs.com/files/kklldog/HeliosChat.7z