C # multiple implementation methods of high-performance TCP services,

Source: Internet
Author: User
Tags apm

C # multiple implementation methods of high-performance TCP services,

Ah ~~ I think most garden friends should be more interested in the words "High Performance". To attract attention, the title must be highlighted. In fact, my favorite title isMonkey sai lei, C # Write the pattern posture of TCP Service!.

The purpose of this article is to use. NET/C # To implement TCP high-performance services in different ways, including but not limited to the following:

  • APM method, that is, Asynchronous Programming Model
  • The TAP mode is Task-based Asynchronous Pattern.
  • SAEA method, that is, SocketAsyncEventArgs
  • RIO method, that is, Registered I/O

In. NET/C # supports Socket encapsulation based on Windows I/O Completion Ports. Different Non-Blocking encapsulation structures are used to meet different programming requirements. The above methods have been fully implemented in Cowboy. Sockets, And the APM and TAP methods have been applied in actual projects. Cowboy. Sockets is still evolving and improving. please correct me if you have any questions.

Although there are many implementation methods, they are the same in abstraction. We can use two loops to describe them:Accept LoopAndRead Loop, As shown in. "Loop"IndicatesLoop ModeRather than keywords such as while/.)

Event EventHandler <TcpClientConnectedEventArgs> ClientConnected; event EventHandler <TcpClientDisconnectedEventArgs> ClientDisconnected; event EventHandler <listener> ClientDataReceived;

It is easy to use and subscribe to Event Notifications directly.

  private static void StartServer()  {      _server = new TcpSocketServer(22222);      _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));      Console.WriteLine(string.Format("{0}", text));      _server.Broadcast(Encoding.UTF8.GetBytes(text));  }
TAP mode: AsyncTcpSocketServer

The implementation of AsyncTcpSocketServer is based on the further encapsulation of TcpListener and TcpClient provided by. NET Framework. It is implemented using the XXXAsync interface of async/await Based on TAP.

However, in fact, XXXAsync has not created any magical effect, and its internal implementation only converts the APM method into the TAP call method.

  //************* Task-based async public methods *************************  [HostProtection(ExternalThreading = true)]  public Task<Socket> AcceptSocketAsync()  {      return Task<Socket>.Factory.FromAsync(BeginAcceptSocket, EndAcceptSocket, null);  }    [HostProtection(ExternalThreading = true)]  public Task<TcpClient> AcceptTcpClientAsync()  {      return Task<TcpClient>.Factory.FromAsync(BeginAcceptTcpClient, EndAcceptTcpClient, null);  }

The Accept Loop in AsyncTcpSocketServer refers,

  while (IsListening)  {      var tcpClient = await _listener.AcceptTcpClientAsync();  }

Each established Connection is handled by AsyncTcpSocketSession. Therefore, AsyncTcpSocketSession contains the Read Loop,

  while (State == TcpSocketConnectionState.Connected)  {      int receiveCount = await _stream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length);  }

To asynchronous async/await to the end, the interfaces exposed by AsyncTcpSocketServer are also Awaitable.

  public interface IAsyncTcpSocketServerMessageDispatcher  {      Task OnSessionStarted(AsyncTcpSocketSession session);      Task OnSessionDataReceived(AsyncTcpSocketSession session, byte[] data, int offset, int count);      Task OnSessionClosed(AsyncTcpSocketSession session);  }

You only need to inject an object that implements this interface into the constructor of AsyncTcpSocketServer.

  public class SimpleMessageDispatcher : IAsyncTcpSocketServerMessageDispatcher  {      public async Task OnSessionStarted(AsyncTcpSocketSession session)      {          Console.WriteLine(string.Format("TCP session {0} has connected {1}.", session.RemoteEndPoint, session));          await Task.CompletedTask;      }        public async Task OnSessionDataReceived(AsyncTcpSocketSession session, byte[] data, int offset, int count)      {          var text = Encoding.UTF8.GetString(data, offset, count);          Console.Write(string.Format("Client : {0} --> ", session.RemoteEndPoint));          Console.WriteLine(string.Format("{0}", text));            await session.SendAsync(Encoding.UTF8.GetBytes(text));      }        public async Task OnSessionClosed(AsyncTcpSocketSession session)      {          Console.WriteLine(string.Format("TCP session {0} has disconnected.", session));          await Task.CompletedTask;      }  }

Of course, the implementation of the interface is not mandatory, or you can directly inject the implementation of the method in the constructor.

  public AsyncTcpSocketServer(      IPEndPoint listenedEndPoint,      Func<AsyncTcpSocketSession, byte[], int, int, Task> onSessionDataReceived = null,      Func<AsyncTcpSocketSession, Task> onSessionStarted = null,      Func<AsyncTcpSocketSession, Task> onSessionClosed = null,      AsyncTcpSocketServerConfiguration configuration = null)  {}
SAEA method: TcpSocketSaeaServer

SAEA is short for SocketAsyncEventArgs. SocketAsyncEventArgs is a high-performance Socket communication implementation supported by. NET Framework 3.5. Compared with APM, SocketAsyncEventArgs has the following advantages:

The main feature of these enhancements is the avoidance of the repeated allocation and synchronization of objects during high-volume asynchronous socket I/O. The Begin/End design pattern currently implemented by the Socket class for asynchronous socket I/O requires a System.IAsyncResult object be allocated for each asynchronous socket operation.

That is to say, the advantage is that you do not need to generate IAsyncResult and other objects for each call, so it is closer to the native Socket.

The recommended steps for using SocketAsyncEventArgs are as follows:

The focus is on Pooling, which aims to reuse and reduce the pressure on allocation during runtime and garbage collection.

TcpSocketSaeaServer is the application and encapsulation of SocketAsyncEventArgs and implements the Pooling technology. The focus of TcpSocketSaeaServer is the SaeaAwaitable class. SaeaAwaitable has a built-in SocketAsyncEventArgs, and GetAwaiter returns SaeaAwaiter to support async/await operations. At the same time, the Awaitable Implementation of SocketAsyncEventArgs is extended through the SaeaExtensions extension method.

  public static SaeaAwaitable AcceptAsync(this Socket socket, SaeaAwaitable awaitable)  public static SaeaAwaitable ConnectAsync(this Socket socket, SaeaAwaitable awaitable)  public static SaeaAwaitable DisonnectAsync(this Socket socket, SaeaAwaitable awaitable)  public static SaeaAwaitable ReceiveAsync(this Socket socket, SaeaAwaitable awaitable)  public static SaeaAwaitable SendAsync(this Socket socket, SaeaAwaitable awaitable)

SaeaPool is a derivative Implementation of QueuedObjectPool <SaeaAwaitable> and is used to pool SaeaAwaitable instances. To reduce the construction process of TcpSocketSaeaSession, SessionPool (QueuedObjectPool) is also implemented.

The Accept Loop in TcpSocketSaeaServer refers,

  while (IsListening)  {      var saea = _acceptSaeaPool.Take();        var socketError = await _listener.AcceptAsync(saea);      if (socketError == SocketError.Success)      {          var acceptedSocket = saea.Saea.AcceptSocket;      }        _acceptSaeaPool.Return(saea);  }

Each established Connection is handled by TcpSocketSaeaSession. Therefore, TcpSocketSaeaSession contains the Read Loop,

  var saea = _saeaPool.Take();  saea.Saea.SetBuffer(_receiveBuffer, 0, _receiveBuffer.Length);    while (State == TcpSocketConnectionState.Connected)  {      saea.Saea.SetBuffer(0, _receiveBuffer.Length);        var socketError = await _socket.ReceiveAsync(saea);      if (socketError != SocketError.Success)          break;        var receiveCount = saea.Saea.BytesTransferred;      if (receiveCount == 0)          break;  }

Similarly, the interfaces exposed by TcpSocketSaeaServer are also Awaitable.

  public interface ITcpSocketSaeaServerMessageDispatcher  {      Task OnSessionStarted(TcpSocketSaeaSession session);      Task OnSessionDataReceived(TcpSocketSaeaSession session, byte[] data, int offset, int count);      Task OnSessionClosed(TcpSocketSaeaSession session);  }

It is also simple to use:

  public class SimpleMessageDispatcher : ITcpSocketSaeaServerMessageDispatcher  {      public async Task OnSessionStarted(TcpSocketSaeaSession session)      {          Console.WriteLine(string.Format("TCP session {0} has connected {1}.", session.RemoteEndPoint, session));          await Task.CompletedTask;      }        public async Task OnSessionDataReceived(TcpSocketSaeaSession session, byte[] data, int offset, int count)      {          var text = Encoding.UTF8.GetString(data, offset, count);          Console.Write(string.Format("Client : {0} --> ", session.RemoteEndPoint));          Console.WriteLine(string.Format("{0}", text));            await session.SendAsync(Encoding.UTF8.GetBytes(text));      }        public async Task OnSessionClosed(TcpSocketSaeaSession session)      {          Console.WriteLine(string.Format("TCP session {0} has disconnected.", session));          await Task.CompletedTask;      }  }
RIO: TcpSocketRioServer

Since Windows 8.1/Windows Server 2012 R2, Microsoft has launched Registered I/O Networking Extensions to support the implementation of high-performance Socket services, RIO for short.

The following functions are supported for Windows Store apps on Windows 8.1, Windows Server 2012 R2, and later. Microsoft Visual Studio 2013 Update 3 or later is required for Windows Store apps.

  • RIOCloseCompletionQueue
  • RIOCreateCompletionQueue
  • RIOCreateRequestQueue
  • RIODequeueCompletion
  • RIODeregisterBuffer
  • Rionoloud
  • RIOReceive
  • RIOReceiveEx
  • RIORegisterBuffer
  • RIOResizeCompletionQueue
  • RIOResizeRequestQueue
  • RIOSend
  • RIOSendEx

So far ,. NET Framework has not yet released support for RIO, so if you want to implement RIO in C #, you can only use the P/Invoke method. RioSharp is a complete implementation in open-source projects.

Cowboy. Sockets directly references the source code of RioSharp.Cowboy. Sockets. ExperimentalNamespace for lab and test.

Similarly, the Accept Loop is implemented through TcpSocketRioServer,

_listener.OnAccepted = (acceptedSocket) =>{    Task.Run(async () =>    {        await Process(acceptedSocket);    })    .Forget();};

Use TcpSocketRioSession to process Read Loop,

  while (State == TcpSocketConnectionState.Connected)  {      int receiveCount = await _stream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length);      if (receiveCount == 0)          break;  }

The test code is as follows:

  public class SimpleMessageDispatcher : ITcpSocketRioServerMessageDispatcher  {      public async Task OnSessionStarted(TcpSocketRioSession session)      {          //Console.WriteLine(string.Format("TCP session {0} has connected {1}.", session.RemoteEndPoint, session));          Console.WriteLine(string.Format("TCP session has connected {0}.", session));          await Task.CompletedTask;      }        public async Task OnSessionDataReceived(TcpSocketRioSession session, byte[] data, int offset, int count)      {          var text = Encoding.UTF8.GetString(data, offset, count);          //Console.Write(string.Format("Client : {0} --> ", session.RemoteEndPoint));          Console.Write(string.Format("Client : --> "));          Console.WriteLine(string.Format("{0}", text));            await session.SendAsync(Encoding.UTF8.GetBytes(text));      }        public async Task OnSessionClosed(TcpSocketRioSession session)      {          Console.WriteLine(string.Format("TCP session {0} has disconnected.", session));          await Task.CompletedTask;      }  }
References
  • Asynchronous Programming Model (APM)
  • Task-based Asynchronous Pattern (TAP)
  • Event-based Asynchronous Pattern (EAP)
  • SocketAsyncEventArgs
  • Registered I/O
  • Netty: Reference counted objects
  • Socket Performance Enhancements in Version 3.5
  • What's New for Windows Sockets for Windows 8.1 and Windows Server 2012 R2
  • RIO_EXTENSION_FUNCTION_TABLE structure
  • Windows 8 Registered I/O Networking Extensions

In this article, "C # High-Performance TCP Service implementation methods" is published by Dennis Gao on his blog in the blog Park. It cannot be reproduced in any form without the consent of the author, any automatic or manual crawler reprinting behavior is a rogue.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.