我的第一個Socket程序-SuperSocket使用入門(一)


第一次使用Socket,遇到過坑,也漲過姿勢,網上關於SuperSocket的教程基本都停留在官方給的簡單demo上,實際使用還是會碰到一些問題,所以准備寫兩篇博客,分別來介紹SuperSocket以及實際的案例應用,應用中我還遇到一些問題,還沒解決,還請有經驗的指出問題

--------------------------------------------------------------------------------begin-------------------------------------------------------------------------------

先奉上官方網址:http://www.supersocket.net/  源碼:http://supersocket.codeplex.com/releases/view/161987

官方的源碼目前就不推薦看了,畢竟也是新手,不一定看得懂,使用前先看下官方的文檔:http://docs.supersocket.net/  官方源碼目錄中有個QuickStart文件夾,顧名思義就是快速開始,官方的Demo,這里很想吐槽,網上的很多Demo都是官方Demo都是這個源碼中最簡單的那個,操,那有個毛用!這一篇就不扯其他的了,只講SuperSocket的使用

本人書讀的比較少,文筆比較差,所以我盡量來寫清楚SuperSocket的使用邏輯

一個SuperSocket的程序,可以包含多個Socket服務(稱為AppServer),一個Socket服務中有多個客戶端連接對象(稱這個連接對象為AppSession),一個客戶端與Socket服務通訊命令都在AppSession中進行(稱這個命令為Commands),每一個命令在被執行前我們可以來控制這個命令是否給予執行,類似與MVC中的 Action Filter(稱為CommandFilterAttribute),還有一些其他的例如命令行協議的,用默認的就可以了,復雜的Socket程序可能需要自定義協議,這里我們不予深究(其實也簡單,搞懂上面的,這個就好搞了)

接下來我拿我項目的代碼分別對上面列出的概念來說明

我用的是最新的SuperSocket1.6.4.0,VS2013,需要使用三個官方提供的類庫:SuperSocket.Common.dll,SuperSocket.SocketBase.dll,SuperSocket.SocketEngine.dll,上面忘了說了,SuperSocket集成了日志插件:log4net,所以這里我們也要引用,注意這個1.6.4.0對應的log4net版本為:1.2.13.0,一定要使用官方Demo包中的dll,避免版本引用不一致的問題,項目結構(控制台程序):

結構實際是參照官方的,如圖:,對應文件夾為:

這是一個將Socket程序的宿主使用Windows服務的形式運行,為什么要使用WindowsService就不解釋了,后面再會寫篇來介紹使用服務。我曾建個普通的windows服務項目,把SuperSocket的代碼集成進去,無奈服務啟動就特么停止,不清楚為啥,所以使用官方提供的Demo,官方的代碼我就不解釋了(其實是我也沒看懂...),我們要通過配置文件來啟動Socket程序,所以先看下App.config

<configuration>
  <configSections>
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/><!-- 注冊log4net -->
    <section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/><!-- 注冊SuperSocket -->
  </configSections>
  <appSettings>
    <add key="ServiceName" value="SupperSocketService"/>  <!-- 服務名稱 -->
    <add key="ServiceDescription" value="試鏡成Socket程序"/>  <!-- 服務說明 -->
  </appSettings>
  <superSocket>
    <servers>
      <server name="WeChatSocket" textEncoding="gb2312" serverType="LXGlass.SocketService.WeChatServer, LXGlass.SocketService" ip="Any" port="2020" maxConnectionNumber="100">
      </server> <!-- 一個socket服務(AppServer),當然可以配置多個 -->
    </servers>
  </superSocket>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
  </startup>
  <runtime>
    <gcServer enabled="true" />
  </runtime>
</configuration>

上面說了,每個命令都在AppSession中,所以先來建個AppSession:

/// <summary>
    /// 微信Session
    /// </summary>
    public class WeChatSession:AppSession<WeChatSession>
    {

        /// <summary>
        /// 是否登錄
        /// </summary>
        public bool isLogin { get; set; }

        /// <summary>
        /// 機器編碼
        /// </summary>
        public string SN { get; set; }
            

        protected override void OnSessionStarted()
        {
            //this.Send("Welcome to SuperSocket WeChat Server\r\n");
        }

        protected override void OnInit()
        {
            //this.Charset = Encoding.GetEncoding("gb2312");
            base.OnInit();
        }

        protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
        {
            LogHelper.WriteLog("收到命令:" + requestInfo.Key.ToString());
            this.Send("不知道如何處理 " + requestInfo.Key.ToString() +" 命令\r\n");
        }


        /// <summary>
        /// 異常捕捉
        /// </summary>
        /// <param name="e"></param>
        protected override void HandleException(Exception e)
        {
            this.Send("\n\r異常信息:{0}", e.Message);
            //base.HandleException(e);
        }

        /// <summary>
        /// 連接關閉
        /// </summary>
        /// <param name="reason"></param>
        protected override void OnSessionClosed(CloseReason reason)
        {
            base.OnSessionClosed(reason);
              
        }
    }

在這個Session中我額外定義了兩個屬性:isLogin、SN,Session也就類似與asp.net中的Session

接着把AppSession注冊到服務(AppServer)中

/// <summary>
    /// 微信服務
    /// </summary>
    //[WeChatCheckCommandFilter]
    public  class WeChatServer:AppServer<WeChatSession>
    {

        protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
        {
            return base.Setup(rootConfig, config);
        }

        protected override void OnStarted()
        {
            LogHelper.WriteLog("WeChat服務啟動");
            base.OnStarted();

        }

        protected override void OnStopped()
        {
            LogHelper.WriteLog("WeChat服務停止");
            base.OnStopped();
        }

        /// <summary>
        /// 新的連接
        /// </summary>
        /// <param name="session"></param>
        protected override void OnNewSessionConnected(WeChatSession session)
        {
            //LogHelper.WriteLog("WeChat服務新加入的連接:" + session.LocalEndPoint.Address.ToString());
            base.OnNewSessionConnected(session);
        }

    }

 注意這兩個類的繼承關系,代碼很簡單,我把我的業務代碼刪掉了,先搞懂supersocket

再接着就是關鍵了(其實這些都是關鍵....),命令!先建一個CHECK的命令:

public class CHECK : CommandBase<WeChatSession, StringRequestInfo>
    {
        public override void ExecuteCommand(WeChatSession session, StringRequestInfo requestInfo)
        {
            if (requestInfo.Parameters.Count() != 1)
            {
                session.Send("The wrong format\r\n");
            }
            else
            {
                string sn = requestInfo.Parameters[0].ToString();
                if (string.IsNullOrWhiteSpace(sn))
                    session.Send("The wrong sn\r\n");
                else
                {
                    //已用此SN注冊的連接會替換Sesion
                    var session_client = session.AppServer.GetAllSessions().Where(c => c.SN == sn);
                    if (session_client != null)
                    {
                        foreach (var item in session_client)
                        {
                            item.Send("new check,To close the connection for you\r\n");
                            item.Close();
                        }
                    }

                    session.isLogin = true;
                    session.SN = sn;
                    session.Send("success\r\n");
                }
            }
        }
    }

這個命令繼承自:CommandBase<WeChatSession, StringRequestInfo>,WeChatSession為我們剛才寫的Session,StringRequestInfo為當前請求命令中的信息

當客戶端發送:CHECK 1\r\n 就會收到success的返回,關於這個格式,就是命令行協議了,我這里使用默認的,想要自定義,去參照官方文檔,這個默認的命令行協議的規則:每次請求和響應的數據結尾都有\r\n也就是換行符,通過\r\n來判斷命令的結尾,CHECK為命令key,requestInfo.Key可以獲得,上面的requestInfo.Parameters[0]是這個key后面以空格進行分割得到數組,所以requestInfo.Parameters[0]就可以取到CHECK 1 \r\n中的1,需要更多的數據就繼續空格加

我代碼中有段:已用此SN注冊的連接會替換Sesion這里解釋一下,因為每連上一個客戶端,我們都要給他一個標識(這也是CHECK命令存在的意義),當一個客戶端已用這個CHECK 1注冊了,另外一個客戶端也要用CHECK 1來注冊,那程序就有兩個sn=1的session了,為了保證唯一性,所以這里要把之前已注冊CHECK=1的給踢掉,請無視item.send中的英文

需要其他命令的再添加類,繼承CommandBase<WeChatSession, StringRequestInfo>

推薦個Socket客戶端調試工具:SocketTool,下載地址:http://pan.baidu.com/s/1dDcZCfJ

基礎就到這里了,下一篇說說實際的應用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM