C#異步Socket通信庫:FastSocket

jopen 11年前發布 | 70K 次閱讀 網絡工具包 Fastsocket

FastSocket是一個輕量級易擴展的c#異步socket通信庫,項目開始于2011年,經過近3年不斷調整與改進,目前在功能和性能上均有不錯的表現。

項目地址:https://github.com/devhong/FastSocket.Net 

在Nuget官方源中搜索fastsocket可快速安裝引用

QQ群:257612438

FastSocket內置了命令行、二進制、thrift協議,基于此開發了Zookeeper, Redis, Thrift等c#異步客戶端,接下來將會一一公開。

Requirements

.Net 4.0 or Mono 2.6

Projects using FastSocket.Net

  • Redis.Driver

    </li>

  • Zookeeper.Net

    </li>

  • Thrift.Net

    </li> </ul>

    Example Usage

    1: 簡單的命令行服務

    新建控制臺項目,添加FastSocket.SocketBase,FastSocket.Server引用

    自定義服務實現MyService

    /// <summary>/// 實現自定義服務/// </summary>public class MyService : CommandSocketService<StringCommandInfo>{
        /// <summary>
        /// 當連接時會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        public override void OnConnected(IConnection connection)
        {
            base.OnConnected(connection);
            Console.WriteLine(connection.RemoteEndPoint.ToString() + " connected");
            connection.BeginSend(PacketBuilder.ToCommandLine("welcome"));
        }
        /// <summary>
        /// 當連接斷開時會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="ex"></param>
        public override void OnDisconnected(IConnection connection, Exception ex)
        {
            base.OnDisconnected(connection, ex);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(connection.RemoteEndPoint.ToString() + " disconnected");
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        /// <summary>
        /// 當發生錯誤時會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="ex"></param>
        public override void OnException(IConnection connection, Exception ex)
        {
            base.OnException(connection, ex);
            Console.WriteLine("error: " + ex.ToString());
        }
        /// <summary>
        /// 處理未知命令
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="commandInfo"></param>
        protected override void HandleUnKnowCommand(IConnection connection, StringCommandInfo commandInfo)
        {
            commandInfo.Reply(connection, "unknow command:" + commandInfo.CmdName);
        }}

    Exit命令

    /// <summary>/// 退出命令/// </summary>public sealed class ExitCommand : ICommand<StringCommandInfo>{
        /// <summary>
        /// 返回命令名稱
        /// </summary>
        public string Name
        {
            get { return "exit"; }
        }
        /// <summary>
        /// 執行命令
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="commandInfo"></param>
        public void ExecuteCommand(IConnection connection, StringCommandInfo commandInfo)
        {
            connection.BeginDisconnect();//斷開連接
        }}

    App.config配置

    <?xml version="1.0"?><configuration>
    
      <configSections>
        <section name="socketServer"
                 type="Sodao.FastSocket.Server.Config.SocketServerConfig, FastSocket.Server"/>
      </configSections>
    
      <socketServer>
        <servers>
          <server name="cmdline"
                  port="8400"
                  socketBufferSize="8192"
                  messageBufferSize="8192"
                  maxMessageSize="102400"
                  maxConnections="20000"
                  serviceType="CommandLine.MyService, CommandLine"
                  protocol="commandLine"/>
        </servers>
      </socketServer></configuration>

    初始化及啟動服務

    static void Main(string[] args){
        SocketServerManager.Init();
        SocketServerManager.Start();
    
        Console.ReadLine();}

    啟動服務,然后在cmd中運行telnet 127.0.0.1 8400, 運行截圖如下:

    c#異步socket通信庫:FastSocket

    c#異步socket通信庫:FastSocket

    其中welcome中當連接建立時服務端發送到終端的。

    connection.BeginSend(PacketBuilder.ToCommandLine("welcome"));

    unknow command:Hello是因為沒有對應的"Hello"命令實現由HandleUnKnowCommand輸出的

    protected override void HandleUnKnowCommand(IConnection connection, StringCommandInfo commandInfo){
        commandInfo.Reply(connection, "unknow command:" + commandInfo.CmdName);}

    當在終端中鍵入exit時,觸發了ExitCommand.ExecuteCommand方法,服務端主動斷開連接,終端退出。

    2: 在服務中使用自定義二進制協議

    新建控制臺項目,命名為Server

    添加FastSocket.SocketBase,FastSocket.Server引用

    Socket命令服務類: Sodao.FastSocket.Server.CommandSocketService泛型類

    其中需要實現Socket連接,斷開,異常,發送完回調及處理未知命令的方法

    內置的二進制命令對象: Sodao.FatSocket.Server.Command.AsyncBinaryCommandInfo

    由一個command name,一個唯一標識SeqId和主題內容buffer構建。

    定義服務類MyService繼承CommandSocketService類,

    泛型類型為上述的AsyncBinanryCommandInfo

    /// <summary>/// 實現自定義服務/// </summary>public class MyService : CommandSocketService<AsyncBinaryCommandInfo>{
        /// <summary>
        /// 當連接時會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        public override void OnConnected(IConnection connection)
        {
            base.OnConnected(connection);
            Console.WriteLine(connection.RemoteEndPoint.ToString() + " connected");
        }
        /// <summary>
        /// 當連接斷開時會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="ex"></param>
        public override void OnDisconnected(IConnection connection, Exception ex)
        {
            base.OnDisconnected(connection, ex);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(connection.RemoteEndPoint.ToString() + " disconnected");
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        /// <summary>
        /// 當發生錯誤時會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="ex"></param>
        public override void OnException(IConnection connection, Exception ex)
        {
            base.OnException(connection, ex);
            Console.WriteLine("error: " + ex.ToString());
        }
        /// <summary>
        /// 當服務端發送Packet完畢會調用此方法
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="e"></param>
        public override void OnSendCallback(IConnection connection, SendCallbackEventArgs e)
        {
            base.OnSendCallback(connection, e);
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("send " + e.Status.ToString());
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        /// <summary>
        /// 處理未知的命令
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="commandInfo"></param>
        protected override void HandleUnKnowCommand(IConnection connection, AsyncBinaryCommandInfo commandInfo)
        {
            Console.WriteLine("unknow command: " + commandInfo.CmdName);
        }}

    實現一個命令如示例項目中的SumCommand類,命令類需要實現ICommand泛型接口

    即服務中可以進行處理的服務契約

    而泛型類型即上述的AsyncBinaryCommandInfo

    /// <summary>/// sum command/// 用于將一組int32數字求和并返回/// </summary>public sealed class SumCommand : ICommand<AsyncBinaryCommandInfo>{
        /// <summary>
        /// 返回服務名稱
        /// </summary>
        public string Name
        {
            get { return "sum"; }
        }
        /// <summary>
        /// 執行命令并返回結果
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="commandInfo"></param>
        public void ExecuteCommand(IConnection connection, AsyncBinaryCommandInfo commandInfo)
        {
            if (commandInfo.Buffer == null || commandInfo.Buffer.Length == 0)
            {
                Console.WriteLine("sum參數為空");
                connection.BeginDisconnect();
                return;
            }
            if (commandInfo.Buffer.Length % 4 != 0)
            {
                Console.WriteLine("sum參數錯誤");
                connection.BeginDisconnect();
                return;
            }
    
            int skip = 0;
            var arr = new int[commandInfo.Buffer.Length / 4];
            for (int i = 0, l = arr.Length; i < l; i++)
            {
                arr[i] = BitConverter.ToInt32(commandInfo.Buffer, skip);
                skip += 4;
            }
    
            commandInfo.Reply(connection, BitConverter.GetBytes(arr.Sum()));
        }}

    app.config

    <?xml version="1.0"?><configuration>
    
      <configSections>
        <section name="socketServer"
                 type="Sodao.FastSocket.Server.Config.SocketServerConfig, FastSocket.Server"/>
      </configSections>
    
      <socketServer>
        <servers>
          <server name="binary"
                  port="8401"
                  socketBufferSize="8192"
                  messageBufferSize="8192"
                  maxMessageSize="102400"
                  maxConnections="20000"
                  serviceType="Server.MyService, Server"
                  protocol="asyncBinary"/>
        </servers>
      </socketServer></configuration>

    其中section name="socketServer" 為服務端默認讀取的sectionName

    type為反射自FastSocket.Server中的config類型

    server配置中,name自定,serviceType為上述實現的服務類反射類型

    協議名為asyncBinary

    在Main函數中啟動服務

    static void Main(string[] args){
        SocketServerManager.Init();
        SocketServerManager.Start();
    
        Console.ReadLine();}

    新建控制臺應用程序,命名為Client

    添加FastSocket.Client,FastSocket.SocketBase引用

    客戶端的代碼為組織命令向服務端請求

    創建一個Sodao.FastSocket.Client.AsyncBinarySocketClient的實例

    并通過RegisterServerNode來注冊服務端節點,需要注意name必須唯一

    并且地址為我們服務端運行的地址,端口為服務端配置文件中配置的端口號

    static void Main(string[] args){
        var client = new Sodao.FastSocket.Client.AsyncBinarySocketClient(8192, 8192, 3000, 3000);
        //注冊服務器節點,這里可注冊多個(name不能重復)
        client.RegisterServerNode("127.0.0.1:8401", new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 8401));
        //client.RegisterServerNode("127.0.0.1:8402", new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.2"), 8401));
    
        //組織sum參數, 格式為<<i:32-limit-endian,....N>>
        //這里的參數其實也可以使用thrift, protobuf, bson, json等進行序列化,
        byte[] bytes = null;
        using (var ms = new System.IO.MemoryStream())
        {
            for (int i = 1; i <= 1000; i++) ms.Write(BitConverter.GetBytes(i), 0, 4);
            bytes = ms.ToArray();
        }
        //發送sum命令
        client.Send("sum", bytes, res => BitConverter.ToInt32(res.Buffer, 0)).ContinueWith(c =>
        {
            if (c.IsFaulted)
            {
                Console.WriteLine(c.Exception.ToString());
                return;
            }
            Console.WriteLine(c.Result);
        });
    
        Console.ReadLine();}
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!