前言

socket是软件之间通讯最常用的一种方式。c#实现socket通讯有很多中方法,其中效率最高就是异步通讯。

异步通讯实际是利用windows完成端口(IOCP)来处理的,关于完成端口实现原理,大家可以参考网上文章。

我这里想强调的是采用完成端口机制的异步通讯是windows下效率最高的通讯方式,没有之一!

 

异步通讯比同步通讯处理要难很多,代码编写中会遇到许多“坑“。如果没有经验,很难完成。

我搜集了大量资料,完成了对异步socket的封装。此库已用稳定高效的运行几个月。

 

纵观网上的资料,我还没有遇到一个满意的封装库。许多文章把数据收发和协议处理杂糅在一块,代码非常难懂,也无法扩展。

在编写该库时,避免以上缺陷。将逻辑处理层次化,模块化!同时实现了高可用性与高性能。

 

为了使大家对通讯效率有初步了解,先看测试图。

一个高性能异步socket封装库的实现思路 (c#)

一个高性能异步socket封装库的实现思路 (c#)

客户端和服务端都是本机测试,最大连接数为64422,套接字已耗尽!

主机配置情况

一个高性能异步socket封装库的实现思路 (c#)

百兆带宽基本占满,cpu占用40%,我的电脑在空闲时,cpu占用大概20%,也就是说程序占用cpu 20%左右。

这个库是可扩展的,就是说即使10万个连接,收发同样的数据,cpu占用基本相同。

 

库的结构图 

一个高性能异步socket封装库的实现思路 (c#)

  1. 即可作为服务端(监听)也可以作为客户端(主动连接)使用。
  2. 可以适应任何网络协议。收发的数据针对字节流或一个完整的包。对协议内容不做处理。
  3. 高可用性。将复杂的底层处理封装,对外接口非常友好。
  4. 高性能。最大限度优化处理。单机可支持数万连接,收发速度可达几百兆bit。

实现思路

网络处理逻辑可以分为以下几个部分:

  1. 网络监听   可以在多个端口实现监听。负责生成socket,生成的socket供后续处理。监听模块功能比较单一,如有必要,可对监听模块做进一步优化。
  2. 主动连接  可以异步或同步的连接对方。连接成功后,对socket的后续处理,与监听得到的socket完全一样。注:无论是监听得到的socket,还是连接得到的socket,后续处理完全一样。
  3. Socket收发处理   每个socket对应一个收发实例,socket收发只针对字节流处理。收发时,做了优化。比如发送时,对数据做了粘包,提高发送性能;接收时,一次投递1K的数据。
  4. 组包处理   一般数据包都有包长度指示;比如 报头的前俩个字节表示长度,根据这个值就可以组成一个完整的包。

 NetListener 监听

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace IocpCore
{
    class NetListener
    {
        private Socket listenSocket;
        public ListenParam _listenParam { get; set; }
        public event Action<ListenParam, AsyncSocketClient> OnAcceptSocket;

        bool start;

        NetServer _netServer;
        public NetListener(NetServer netServer)
        {
            _netServer = netServer;
        }

        public int _acceptAsyncCount = 0;
        public bool StartListen()
        {
            try
            {
                start = true;
                IPEndPoint listenPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), _listenParam._port);
                listenSocket = new Socket(listenPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                listenSocket.Bind(listenPoint);
                listenSocket.Listen(200);

                Thread thread1 = new Thread(new ThreadStart(NetProcess));
                thread1.Start();
               
                StartAccept();
                return true;
            }
            catch (Exception ex)
            {
                NetLogger.Log(string.Format("**监听异常!{0}", ex.Message));
                return false;
            }
        }

        AutoResetEvent _acceptEvent = new AutoResetEvent(false);
        private void NetProcess()
        {
            while (start)
            {
                DealNewAccept();
                _acceptEvent.WaitOne(1000 * 10);
            }
        }

        private void DealNewAccept()
        {
            try
            {
                if(_acceptAsyncCount <= 10)
                {
                    StartAccept();
                }

                while (true)
                {
                    AsyncSocketClient client = _newSocketClientList.GetObj();
                    if (client == null)
                        break;

                    DealNewAccept(client);
                }
            }
            catch (Exception ex)
            {
                NetLogger.Log(string.Format("DealNewAccept 异常 {0}***{1}", ex.Message, ex.StackTrace));
            }
        }

        private void DealNewAccept(AsyncSocketClient client)
        {
            client.SendBufferByteCount = _netServer.SendBufferBytePerClient;
           OnAcceptSocket?.Invoke(_listenParam, client);
        }

        public bool StartAccept()
        {
           
            return true;
        }

        ObjectPool<AsyncSocketClient> _newSocketClientList = new ObjectPool<AsyncSocketClient>();
        private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs)
        {
            try
            {
                using (acceptEventArgs)
                {
                   
                }
            }
            catch (Exception ex)
            {
                NetLogger.Log(string.Format("ProcessAccept {0}***{1}", ex.Message, ex.StackTrace));
            }
        }
    }
}

  

NetConnectManage连接处理

一个高性能异步socket封装库的实现思路 (c#)
  1 using System;
  2 using System.Net;
  3 using System.Net.Sockets;
  4 
  5 namespace IocpCore
  6 {
  7     class NetConnectManage
  8     {
  9         public event Action<SocketEventParam, AsyncSocketClient> OnSocketConnectEvent;
 10 
 11         public bool ConnectAsyn(string peerIp, int peerPort, object tag)
 12         {
 13             try
 14             {
 15                 Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
 16                 SocketAsyncEventArgs socketEventArgs = new SocketAsyncEventArgs();
 17                 socketEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(peerIp), peerPort);
 18                 socketEventArgs.Completed += SocketConnect_Completed;
 19 
 20                 SocketClientInfo clientInfo = new SocketClientInfo();
 21                 socketEventArgs.UserToken = clientInfo;
 22                 clientInfo.PeerIp = peerIp;
 23                 clientInfo.PeerPort = peerPort;
 24                 clientInfo.Tag = tag;
 25 
 26                 bool willRaiseEvent = socket.ConnectAsync(socketEventArgs);
 27                 if (!willRaiseEvent)
 28                 {
 29                     ProcessConnect(socketEventArgs);
 30                     socketEventArgs.Completed -= SocketConnect_Completed;
 31                     socketEventArgs.Dispose();
 32                 }
 33                 return true;
 34             }
 35             catch (Exception ex)
 36             {
 37                 NetLogger.Log("ConnectAsyn",ex);
 38                 return false;
 39             }
 40         }
 41 
 42         private void SocketConnect_Completed(object sender, SocketAsyncEventArgs socketEventArgs)
 43         {
 44             ProcessConnect(socketEventArgs);
 45             socketEventArgs.Completed -= SocketConnect_Completed;
 46             socketEventArgs.Dispose();
 47         }
 48 
 49         private void ProcessConnect(SocketAsyncEventArgs socketEventArgs)
 50         {
 51             SocketClientInfo clientInfo = socketEventArgs.UserToken as SocketClientInfo;
 52             if (socketEventArgs.SocketError == SocketError.Success)
 53             {
 54                 DealConnectSocket(socketEventArgs.ConnectSocket, clientInfo);
 55             }
 56             else
 57             {
 58                 SocketEventParam socketParam = new SocketEventParam(EN_SocketEvent.connect, null);
 59                 socketParam.ClientInfo = clientInfo;
 60                 OnSocketConnectEvent?.Invoke(socketParam, null);
 61             }
 62         }
 63 
 64 
 65         void DealConnectSocket(Socket socket, SocketClientInfo clientInfo)
 66         {
 67             clientInfo.SetClientInfo(socket);
 68 
 69             AsyncSocketClient client = new AsyncSocketClient(socket);
 70             client.SetClientInfo(clientInfo);
 71 
 72             //触发事件
 73             SocketEventParam socketParam = new SocketEventParam(EN_SocketEvent.connect, socket);
 74             socketParam.ClientInfo = clientInfo;
 75             OnSocketConnectEvent?.Invoke(socketParam, client);
 76         }
 77 
 78         public bool Connect(string peerIp, int peerPort, object tag, out Socket socket)
 79         {
 80             socket = null;
 81             try
 82             {
 83                 Socket socketTmp = new Socket(SocketType.Stream, ProtocolType.Tcp);
 84 
 85                 SocketClientInfo clientInfo = new SocketClientInfo();
 86                 clientInfo.PeerIp = peerIp;
 87                 clientInfo.PeerPort = peerPort;
 88                 clientInfo.Tag = tag;
 89 
 90                 EndPoint remoteEP = new IPEndPoint(IPAddress.Parse(peerIp), peerPort);
 91                 socketTmp.Connect(remoteEP);
 92                 if (!socketTmp.Connected)
 93                     return false;
 94 
 95                 DealConnectSocket(socketTmp, clientInfo);
 96                 socket = socketTmp;
 97                 return true;
 98             }
 99             catch (Exception ex)
100             {
101                 NetLogger.Log(string.Format("连接对方:({0}:{1})出错!", peerIp, peerPort), ex);
102                 return false;
103             }
104         }
105     }
106 }
View Code

相关文章:

  • 2021-12-03
  • 2021-12-06
  • 2022-12-23
  • 2021-06-20
  • 2021-07-17
  • 2021-06-02
猜你喜欢
  • 2021-11-17
  • 2021-10-14
  • 2021-12-31
  • 2021-12-20
  • 2021-05-27
  • 2021-06-22
  • 2021-05-18
相关资源
相似解决方案