SuperSocket入門(二)- 探索AppServer、AppSession,Conmmand和App.config

来源:http://www.cnblogs.com/fly-bird/archive/2017/01/19/6308974.html
-Advertisement-
Play Games

在上一篇文章中,我們已經瞭解到瞭如何在SuperSocket處理客戶端請求。 同時我們可能會發現一個問題,如果我們的伺服器端包含有很多複雜的業務邏輯,這樣的switch/case代碼將會很長而且非常難看,並且沒有遵循面向對象設計的原則(OOD)。 在這種情況下,SuperSocket提供了一些讓我們 ...


      在上一篇文章中,我們已經瞭解到瞭如何在SuperSocket處理客戶端請求。 同時我們可能會發現一個問題,如果我們的伺服器端包含有很多複雜的業務邏輯,這樣的switch/case代碼將會很長而且非常難看,並且沒有遵循面向對象設計的原則(OOD)。 在這種情況下,SuperSocket提供了一些讓我們在多個獨立的類中處理各自不同的請求的命令框架,接下來我們一起來看一下怎麼使用     1、自定義AppSession      AppSession 代表一個和客戶端的邏輯連接,基於連接的操作應該放在該類之中。你可以用該類的實例發送數據到客戶端,接收客戶端發送的數據或者關閉連接。      使用方法:創建自定義類MySession,繼承AppSession類並重寫AppSession類的方法(註意:一個AppSession對象對應一個連接)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;

/****************************************************************
*   作者:黃昏前黎明後
*   CLR版本:4.0.30319.42000
*   創建時間:2017-01-19 00:02:17
*   2017
*   描述說明:自定義連接類MySession,繼承AppSession,並傳入到AppSession  
*
*   修改歷史:
*
*
*****************************************************************/
namespace SuperSocketDemo.Session
{
    
    /// <summary>  
    /// 自定義連接類MySession,繼承AppSession,並傳入到AppSession  
    /// </summary>  
    public class MySession : AppSession<MySession>
    {
        /// <summary>  
        /// 新連接  
        /// </summary>  
        protected override void OnSessionStarted()
        {
       //輸出客戶端IP地址  
            Console.WriteLine(this.LocalEndPoint.Address.ToString());  
            this.Send("Hello User,Welcome to SuperSocket Telnet Server!");
    }

    /// <summary>  
    /// 未知的Command  
    /// </summary>  
    /// <param name="requestInfo"></param>  
    protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
    {
        this.Send("unknow");
    }

    /// <summary>  
    /// 捕捉異常並輸出  
    /// </summary>  
    /// <param name="e"></param>  
    protected override void HandleException(Exception e)
    {
        this.Send("error: {0}", e.Message);
    }

    /// <summary>  
    /// 連接關閉  
    /// </summary>  
    /// <param name="reason"></param>  
    protected override void OnSessionClosed(CloseReason reason)
    {
        base.OnSessionClosed(reason);
    }
}  
}
MySession類     2、自定義AppServer      AppServer 代表了監聽客戶端連接,承載TCP連接的伺服器實例。理想情況下,我們可以通過AppServer實例獲取任何你想要的客戶端連接,伺服器級別的操作和邏輯應該定義在此類之中。     使用方法:創建自定義類MyServer,繼承AppServer類並重寫AppServer類的方法
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocketDemo.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/****************************************************************
*   作者:黃昏前黎明後
*   CLR版本:4.0.30319.42000
*   創建時間:2017-01-19 00:15:45
*   2017
*   描述說明:自定義伺服器類MyServer,繼承AppServer,並傳入自定義連接類MySession 
*
*   修改歷史:
*
*
*****************************************************************/
namespace SuperSocketDemo.Server
{
    /// <summary>  
    /// 自定義伺服器類MyServer,繼承AppServer,並傳入自定義連接類MySession  
    /// </summary>  
    public class MyServer : AppServer<MySession>
    {
        protected override void OnStartup()
        {
            base.OnStartup();
           // Console.WriteLine("伺服器啟動");
        }

        /// <summary>  
        /// 輸出新連接信息  
        /// </summary>  
        /// <param name="session"></param>  
        protected override void OnNewSessionConnected(MySession session)
        {
            base.OnNewSessionConnected(session);
         //輸出客戶端IP地址  
            Console.Write("\r\n" + session.LocalEndPoint.Address.ToString() + ":連接");  
        }

    /// <summary>  
    /// 輸出斷開連接信息  
    /// </summary>  
    /// <param name="session"></param>  
    /// <param name="reason"></param>  
    protected override void OnSessionClosed(MySession session, CloseReason reason)
    {
        base.OnSessionClosed(session, reason);
        Console.Write("\r\n" + session.LocalEndPoint.Address.ToString() + ":斷開連接");
    }

    protected override void OnStopped()
    {
        base.OnStopped();
        Console.WriteLine("服務已停止");
    }
}  
}
MyServer類     3、使用Command      在SuperSocket 中的Command讓我們進行擴展,使用方法也極其簡單。只需要繼承一個CommandBase<AppSession, StringRequestInfo>類(註意:如果使用了自定義的Session,需要修改此處,如add類下的Add:CommandBase<MySession, StringRequestInfo>)類),並override這個類ExecuteCommand方法。現在我們來處理上篇文章的示例,先取消Telnet示例中的 appServer.NewRequestReceived 事件處理。這樣我們就可以編寫大量的命令讓我們的Socket更靈活。     例如,我們可以定義一個名為"Hello "的類去處理Key為"Hello"的請求:
 public class Hello: CommandBase<MySession, StringRequestInfo>
    {
        /// <summary>  
        /// 自定義執行命令方法,註意傳入的變數session類型為MySession  
        /// </summary>  
        /// <param name="session">會話</param>  
        /// <param name="requestInfo">請求數據信息</param>  
        public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo)
        {
            session.Send(string.Format("Hello {0}:{1}   {2}", session.Config.Ip, session.Config.Port, requestInfo.Body));
        }
    }
Hello類

     定義一個名為"ADD"的類去處理Key為"ADD"的請求:

public class ADD : CommandBase<MySession, StringRequestInfo>
{
    public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo)
    {
        session.Send(requestInfo.Parameters.Select(p => Convert.ToInt32(p)).Sum().ToString());
    }
}
Add類

     定義一個名為"MULT"的類去處理Key為"MULT"的請求:

public class MULT : CommandBase<MySession, StringRequestInfo>
{
    public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo)
    {
        var result = 1;

        foreach (var factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p)))
        {
            result *= factor;
        }

        session.Send(result.ToString());
    }
}
Mult類     定義一個名為"Echo"的類去處理Key為"Echo"的請求:
public class Echo: CommandBase<MySession, StringRequestInfo>
    {
        public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo)
        {
            session.Send(requestInfo.Body);
        }
    }
Echo類

    同時我們要移除請求處理方法的註冊,因為它和命令不能同時被支持,註釋下麵代碼即可

    //appServer.NewRequestReceived += new RequestHandler<MySession, StringRequestInfo>(appServer_NewRequestReceived);

   4、配置App.config使用BootStrap啟動SuperSocket

   SuperSocket配置section SuperSocket使用.NET自帶的配置技術,SuperSocket有一個專門的配置Section.使用配置啟動SuperSocket可以靈活配置選項

     配置完成後,還需要修改program類。將原有在program中定義的埠信息以及方法註釋,只保留服務啟動和停止的代碼。引入using SuperSocket.SocketEngine;使用BootStrap啟動

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketEngine;
using SuperSocketDemo.Server;

/****************************************************************
*   作者:黃昏前黎明後
*   CLR版本:4.0.30319.42000
*   創建時間:2017-01-19 00:02:17
*   2017
*   描述說明:服務啟動和停止入口  
*
*   修改歷史: 2017 -01-19  調整自定義mysession和myserver
*
*
*****************************************************************/
namespace SuperSocketDemo
{
    class Program
    {
        /// <summary>
        /// SuperSocket服務啟動或停止
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Console.WriteLine("請按任何鍵進行啟動SuperSocket服務!");
            Console.ReadKey();
            Console.WriteLine();
            var bootstrap = BootstrapFactory.CreateBootstrap();

            if (!bootstrap.Initialize())
            {
                Console.WriteLine("初始化失敗!");
                Console.ReadKey();
                return;
            }


            //修改appserver為myserver
            //var appServer = new AppServer();
            // var appServer = new MyServer();
            //註冊事件
            // appServer.NewSessionConnected += new SessionHandler<AppSession>(appServer_NewSessionConnected);
            //appServer.NewRequestReceived += new RequestHandler<AppSession, StringRequestInfo>(appServer_NewRequestReceived);

            //設置埠號
            //int port = 2017;
            //啟動應用服務埠
            //if (!appServer.Setup(port)) //啟動時監聽埠2017
            //{
            //    Console.WriteLine("服務埠啟動失敗!");
            //    Console.ReadKey();
            //    return;
            //}

            //Console.WriteLine();

            ////嘗試啟動應用服務
            //if (!appServer.Start())
            //{
            //    Console.WriteLine("服務啟動失敗!");
            //    Console.ReadKey();
            //    return;
            //}
            var result = bootstrap.Start();

            Console.WriteLine("服務正在啟動: {0}!", result);

            if (result == StartResult.Failed)
            {
                Console.WriteLine("服務啟動失敗!");
                Console.ReadKey();
                return;
            }
            Console.WriteLine("服務啟動成功,請按'E'停止服務!");

            while (Console.ReadKey().KeyChar != 'E')
            {
                Console.WriteLine();
                continue;
            }

            //停止服務
            // appServer.Stop();
            bootstrap.Stop();
            Console.WriteLine("服務已停止!");
            Console.ReadKey();
        }
        /// <summary>
        /// 在事件處理代碼中發送歡迎信息給客戶端
        /// </summary>
        /// <param name="session"></param>
        //static void appServer_NewSessionConnected(AppSession session)
        //{
        //    session.Send("Welcome to SuperSocket Telnet Server!");
        //}
        /// <summary>
        ///客戶端請求處理
        /// </summary>
        /// <param name="session">會話</param>
        /// <param name="requestInfo">請求信息</param>

        //static void appServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo)
        //{
        //    switch (requestInfo.Key.ToUpper())
        //    {
        //        case ("ECHO"):
        //            session.Send(requestInfo.Body);
        //            break;

        //        case ("ADD"):
        //            session.Send(requestInfo.Parameters.Select(p => Convert.ToInt32(p)).Sum().ToString());
        //            break;

        //        case ("MULT"):

        //            var result = 1;

        //            foreach (var factor in requestInfo.Parameters.Select(p => Convert.ToInt32(p)))
        //            {
        //                result *= factor;
        //            }

        //            session.Send(result.ToString());
        //            break;
        //    }
        //}
    }
}
program類

    最後我們看一下修改後程式的運行結果:

斷開調試工具看一下效果,可以看到服務端顯示客戶端斷開連接

註意事項:

     a) MyServer、自定義命令和MySession的訪問許可權必須設置為public      b) MyServer父類為AppServer<MySession>      c) MySession父類為AppSession<MySession>      d) HELLO父類為CommandBase<MySession,StringRequestInfo>,ExecueteCommand方法傳入值類型分別為MySession和StringRequestInfo      e) 多伺服器中需註意AppSession、AppServer、自定義命令中的AppSession不要搞錯 調試常見錯誤:      

     總結:

     通過自定義Session和Server,可以實現我們自己的AppSession和AppServer允許你根據你業務的需求來方便的擴展SuperSocket,你可以綁定session的連接和斷開事件,伺服器實例的啟動和停止事件。你還可以在AppServer的Setup方法中讀取你的自定義配置信息。總而言之,這些功能讓你方便的創建一個你所需要的socket伺服器成為可能。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在 Windows Forms 和 WPF 應用中使用 FontAwesome 圖標 ...
  • 在C#中 “\”是特殊字元,要表示它的話需要使用“\\”。由於這種寫法不方便,C#語言提供了@對其簡化。只要在字元串前加上@即可直接使用“\”。所以上面的路徑在C#中應該表示為“Book”,@“\Tmp\Book”,@“C:\Tmp\Book”。 相對路徑使用“/”字元作為目錄的分隔字元,而絕對路徑 ...
  • 前言 上一篇講述了執行sql和配置的一些功能,這篇說明IQueryable(linq)或執行sql的查詢緩存與清理,包括擴展到將緩存存儲到Redis中。 擴展類庫源碼: github:https://github.com/skigs/EFCoreExtend 引用類庫: nuget:https:// ...
  • 這幾天老感覺不對, 總覺得少點什麼, 今天才發現, 前面 3 裡面, 在獲取Action參數信息的時候, 少解析了. 裡面還有一個比較重要的東西. 今天看也是一樣的. 在 InvokeAction() 方法裡面, 有一句代碼: 這個是用來獲取參數的. 那麼參數是不是隨便獲取呢? 在Mvc 裡面, 頁 ...
  • 16年我們公司一共開發了好幾個企業網站。最初項目經理讓我用模板引擎,我參照著網上找的模板引擎的代碼及功能,自己寫了一個。當開發了幾個企業網站之後,發現開發效率太低了,同事們用模板引擎開發的過程中,寫模板改模板要花費不少時間,有時候特殊的需求,需要加個資料庫表,或者資料庫已有的欄目或內容表加個欄位什麼 ...
  • 因為一些配置屬性比較多,存在多組屬性,因此結合xml解析、緩存技術,實現配置文化的自動解析、存入緩存、緩存依賴實時更新配置內容。 配置文件反序列化存入緩存的核心方法: public Class.Settings GetSettings() { if (HttpRuntime.Cache["setti ...
  • 網上對TempData的總結為: 保存在session中,Controller每次執行請求時,會從session中一次獲取所有tempdata數據,保存在單獨的內部數據字典中,而後從session中清空tempdata。然後通過key從字典中獲取指定的Tempdata,每訪問一次後對應的Key就會從 ...
  • 比AutoMapper輕量快速簡潔的實體映射庫YeaJur.Mapper ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...