Super socket 記錄知識
大魚網址 相關版本可以在這里找找
https://www.cnblogs.com/jzywh/archive/2010/12/23/supersocketupdate.html
SuperSocket 1.6 中文文檔
https://docs.supersocket.net/v1-6/zh-CN
SuperSocket 1.4系列文檔(2) SuperSocket的基本配置
配置文件示例
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="socketServer" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
</configSections>
<appSettings>
<add key="ServiceName" value="BroardcastService"/>
</appSettings>
<socketServer loggingMode="IndependantFile">
<servers>
<server name="BroardcastServer"
serviceName="BroardcastService"
ip="Any" port="911" mode="Async">
</server>
</servers>
<services>
<service name="BroardcastService"
type="SuperSocket.QuickStart.BroadcastService.BroadcastServer, SuperSocket.QuickStart.BroadcastService" />
</services>
</socketServer>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
</configuration>
服務名稱
<appSettings>
<add key="ServiceName" value="BroardcastService"/>
</appSettings>
這個配置項將被用作SuperSocket系統服務的名稱。如果ServiceName設置成BroardcastService, 則運行InstallService.bat這個批處理文件之后, SuperSocket系統服務將以"BroadcastService"這個名字安裝到系統之中。
SuperSocket的根配置
<socketServer loggingMode="IndependantFile">
....
</socketServer>
- loggingMode
ShareFile: 多個服務器實例共享同日志文件,默認選項;IndependantFile:多個服務器實例擁有獨立的日志文件;Console: 控制台日志輸出,只在控制台應用程序中有效。
- maxWorkingThreads:線程池最大工作線程數量
- minWorkingThreads:線程池最小工作線程數量
- maxCompletionPortThreads:線程池最大完成端口線程數量
- minCompletionPortThreads:線程池最小完成端口線程數量
服務器實例配置
<servers>
<server name="BroardcastServer"
serviceName="BroardcastService"
ip="Any"
port="911"
mode="Async">
</server>
</servers>
- name: 服務器實例名稱
- serviceName: 指定服務器實例運行的服務的名稱。此名稱為定義此服務器實例運行的服務的節點的名稱。
- ip: 指定socket服務器監聽的服務器IP地址。Any: 監聽本機所有的IPv4地址;IPv6Any, 監聽本機所有IPv6的地址。
- port: 指定socket服務器監聽的端口。
- mode: Sync:同步模式;Async: 異步模式;Udp: Udp協議
- disabled: true或者false。是否禁用該服務器實例,默認為否。
- readTimeOut: 從socket讀取數據超時時間,默認為0。
- sendTimeOut: 從socket發送數據超時時間,默認為0。
- maxConnectionNumber: 最大允許的客戶端連接數目,默認為100。
- receiveBufferSize: 用於接收數據的緩沖區大小,默認為2048。
- sendBufferSize: 用戶發送數據的緩沖區大小,默認為2048。
- logCommand: true或者false,是否記錄命令。
- clearIdleSession: true或者false, 是否清除空閑會話,默認為false。
- clearIdleSessionInterval: 清除空閑會話的時間間隔,默認為120,單位為秒。
- idleSessionTimeOut: 會話超時時間,默認值為300,單位為秒。
- security: Empty, Tls或者Ssl3。 Socket服務器所采用的傳輸層加密協議,默認值為空。
- maxCommandLength: 最大允許的命令長度,默認值為1024。
- disableSessionSnapshot: 是否禁用會話快照,默認值為false。(1.4 SP1)
- sessionSnapshotInterval: 生成會話快照的時間間隔。默認值為5,單位為秒。
- keepAliveTime: keep alive消息發送時間間隔。默認值為600, 單位為秒。
- keepAliveInterval:keep alive失敗重試的時間間隔。默認值為60, 單位為秒。
多服務器實例的配置
設置不同的實例名稱和IP端口組合即可。
<servers>
<server name="BroardcastServerA"
serviceName="BroardcastService"
ip="Any"
port="911"
mode="Async">
</server>
<server name="BroardcastServerB"
serviceName="BroardcastService"
ip="Any"
port="912"
mode="Async">
</server>
</servers>
服務配置
<services>
<service name="BroardcastService"
type="SuperSocket.QuickStart.BroadcastService.BroadcastServer, SuperSocket.QuickStart.BroadcastService" />
</services>
- name: 服務定義的名稱,即服務器實例節點serviceName所對應的名稱。
- type: 該服務所對應AppServer類型的完整名稱。
SuperSocket 1.4系列文檔(3) 使用SuperSocket的第一步,實現你自己的AppServer和AppSession
什么是AppSession?
AppSession 代表一個和客戶端的邏輯連接,基於連接的操作應該定於在該類之中。你可以用該類的實例發送數據到客戶端,接收客戶端發送的數據或者關閉連接。
什么是AppServer?
AppServer 代表了監聽客戶端連接,承載TCP連接的服務器實例。理想情況下,我們可以通過AppServer實例獲取任何你想要的客戶端連接,服務器級別的操作和邏輯應該定義在此類之中。
創建你的AppSession
現在,我們以EchoServer為例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SuperSocket.SocketBase;
namespace SuperSocket.QuickStart.EchoService
{
public class EchoSession : AppSession<EchoSession>
{
public override void StartSession()
{
SendResponse("Welcome to EchoServer!");
}
public override void HandleExceptionalError(Exception e)
{
SendResponse("Server side error occurred!");
}
}
}
在此示例之中,EchoSession為我們做了兩件事情:
1. 當客戶端連接上時,發送歡迎信息到客戶端;
2. 當命令執行的時拋出異常,發送消息"Server side error occurred!"到客戶端。
創建你的AppServer
我們還是以EchoServer 為例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SuperSocket.SocketBase;
namespace SuperSocket.QuickStart.EchoService
{
public class EchoServer : AppServer<EchoSession>
{
}
}
你的AppServer實現需要一個AppSession的類型作為泛型參數用於繼承基類AppServer.因為EchoServer不需要額外的邏輯,所以不需要寫任何代碼在該類之中。
然后我們再以BroadcastServer 為例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Command;
namespace SuperSocket.QuickStart.BroadcastService
{
public class BroadcastServer : AppServer<BroadcastSession>
{
private Dictionary<string, List<string>> broadcastDict = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
private object broadcastSyncRoot = new object();
private Dictionary<string, BroadcastSession> broadcastSessionDict = new Dictionary<string, BroadcastSession>(StringComparer.OrdinalIgnoreCase);
private object syncRoot = new object();
public BroadcastServer()
{
lock (broadcastSyncRoot)
{
//It means that device V001 will receive broadcast messages from C001 and C002,
//device V002 will receive broadcast messages from C002 and C003
broadcastDict["C001"] = new List<string> { "V001" };
broadcastDict["C002"] = new List<string> { "V001", "V002" };
broadcastDict["C003"] = new List<string> { "V002" };
}
}
internal void RegisterNewSession(BroadcastSession session)
{
if (string.IsNullOrEmpty(session.DeviceNumber))
return;
lock (syncRoot)
{
broadcastSessionDict[session.DeviceNumber] = session;
}
}
internal void RemoveOnlineSession(BroadcastSession session)
{
if (string.IsNullOrEmpty(session.DeviceNumber))
return;
lock (syncRoot)
{
broadcastSessionDict.Remove(session.DeviceNumber);
}
}
internal void BroadcastMessage(BroadcastSession session, string message)
{
List<string> targetDeviceNumbers;
lock (broadcastSyncRoot)
{
if(!broadcastDict.TryGetValue(session.DeviceNumber, out targetDeviceNumbers))
return;
}
if (targetDeviceNumbers == null || targetDeviceNumbers.Count <= 0)
return;
List<BroadcastSession> sessions = new List<BroadcastSession>();
lock (syncRoot)
{
BroadcastSession s;
foreach(var key in targetDeviceNumbers)
{
if (broadcastSessionDict.TryGetValue(key, out s))
sessions.Add(s);
}
}
Async.Run(() =>
{
sessions.ForEach(s => s.SendResponse(message));
});
}
protected override void OnAppSessionClosed(object sender, AppSessionClosedEventArgs<BroadcastSession> e)
{
RemoveOnlineSession(e.Session);
base.OnAppSessionClosed(sender, e);
}
}
}
此時,我們可以發現BroadcastServer 類中定義了許多在其他地方可以直接使用的應用程序級別的邏輯和方法。
SuperSocket 1.4系列文檔(4) 使你的SuperSocket AppServer運行
在SocketService中運行你的AppServer
SuperSocket 提供了一個名叫"SocketService"的項目,它是一個能夠讓AppServer運行於其中的容器。 SocketService能夠使你的AppServer 以控制台或者windows服務的形式運行 (需注冊)。
有兩種方法可以讓你的AppServer運行於SocketService之中:
- 復制你的AppServer的dll輸出到SocketService的編譯輸出目錄
- 在你的AppServer項目中引用SocketService 項目。如果你是用這種方式,你需要新建一個名為"SuperSocket.SocketService.exe.config"的配置文件,並且設置這個文件的Build Action為Content和Copy if newer。新建此文件的原因是VS.NET不會復制SocketService項目的配置文件到此項目的輸出目錄,但最終運行的程序是SuperSocket.SocketService.exe,所以文件SuperSocket.SocketService.exe.config是必須的。QuickStart中的示例項目都是通過這種方式構建。
不管你用哪一種方法,在你運行SocketService之前,必須添加你的socket服務器定義到配置文件SuperSocket.SocketService.exe.config之中。
這里有一個配置示例:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="socketServer" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
</configSections>
<appSettings>
<add key="ServiceName" value="BroardcastService"/>
</appSettings>
<socketServer loggingMode="IndependantFile">
<servers>
<server name="BroardcastServer"
serviceName="BroardcastService"
ip="Any" port="911" mode="Async">
</server>
</servers>
<services>
<service name="BroardcastService"
type="SuperSocket.QuickStart.BroadcastService.BroadcastServer, SuperSocket.QuickStart.BroadcastService" />
</services>
</socketServer>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
</configuration>
同時,將SuperSocket提供的log4net配置文件(Config/log4net.config)包含到你的啟動項目里面(同樣是Config目錄下),並確保它編譯時被輸出。
定義你的SocketServer時候主要有兩個地方需要注意:
1) 定義你的服務:
<services>
<service name="BroardcastService"
type="SuperSocket.QuickStart.BroadcastService.BroadcastServer, SuperSocket.QuickStart.BroadcastService" />
</services>
服務是指你在此程序中能運行的的類型,你應該將你實現的AppServer的完整類型名稱和簡稱添加到你的服務節點。
2) 定義你的服務器實例
<servers>
<server name="BroardcastServer"
serviceName="BroardcastService"
ip="Any" port="911" mode="Async">
</server>
</servers>
在你添加完服務節點之后,你就可以基於你剛添加的服務來添加你的服務器實例。一個Server xml節點代表了一個服務器運行實例。Server節點的屬性"serviceName" 被用來確定一個服務器實例運行的AppServer的類型。Server節點還有其他必填屬性,例如: name, ip 和 port。你還可以定義其他的可選屬性,相關的屬性介紹你可以在下面的鏈接中找到:http://www.cnblogs.com/jzywh/archive/2011/04/20/2022946.html
你完成的配置之后,你就可以啟動你的SuperSocket了。
1) 以控制台的形式啟動
運行輸出目錄的批處理文件 "RunServer.bat" 就可以讓你的SuperSocket 以控制台程序的形式運行
2) 以Windows服務的形式啟動
SocketService項目提供了兩個批處理文件用於windows service,InstallService.bat用於安裝SuperSocket服務,UninstallService.bat 用於卸載服務。因為SocketService默認的啟動方式是手動啟動,所以在安裝完服務之后請手動啟動服務。
你也可以在你自己的應用程序容器中運行SuperSocket.
添加SuperSocket相關的引用到你的項目,然后添加下面的代碼到你的應用程序入口:
LogUtil.Setup();
SocketServiceConfig serverConfig = ConfigurationManager.GetSection("socketServer") as SocketServiceConfig;
if (!SocketServerManager.Initialize(serverConfig))
{
return;
}
if (!SocketServerManager.Start())
{
SocketServerManager.Stop();
return;
}
無論怎樣,在應用程序配置文件中添加SuperSocket相關的配置都是必需的, 同時確保把SuperSocket提供的log4net配置文件log4net.config輸出到目錄/Config也是使日志功能正常工作的必要條件。
SuperSocket 1.4系列文檔(5) 實現你的Socket命令
大部分的業務邏輯代碼應該放在Command里面。Command會由SuperSocket引擎根據收到的CommandInfo的Key來自動的執行。
例如,客戶端向SuperSocket發送一個以ECHO為Key的Command時, 如
"ECHO I love you\r\n",
名為ECHO的Command就會被執行。
Echo命令定義如下:
public class ECHO : StringCommandBase<EchoSession>
{
#region CommandBase<EchoSession> Members
public override void ExecuteCommand(EchoSession session, StringCommandInfo commandInfo)
{
session.SendResponse(commandInfo.Data);
}
#endregion
}
(注意,命令類必須為public)
當SuperSocket引擎收到一個以"ECHO"為Key的StringCommandInfo時,ECHO命令類的ExecuteCommand方法會被自動的執行。
如果你在你的協議里面定義了自己的CommandInfo類型,你應該基於CommandBase<SessionType, CommandInfoType>來創建Command:
public class ECHO : CommandBase<EchoSession, MyCommandInfo>
{
#region CommandBase<EchoSession> Members
public override void ExecuteCommand(EchoSession session, MyCommandInfo commandInfo)
{
session.SendResponse(commandInfo.Data);
}
#endregion
}
在某些情況下,你的CommandInfo的key必須為16進制數字構成的字符串或者其它不能用來作為類名的字符串,此時,你可以override Command類的Name屬性用於匹配command info的 key:
public class ECHO : CommandBase<EchoSession, MyCommandInfo>
{
public override string Name
{
get { return "0A"; }
}
#region CommandBase<EchoSession> Members
public override void ExecuteCommand(EchoSession session, MyCommandInfo commandInfo)
{
session.SendResponse(commandInfo.Data);
}
#endregion
}
在ExecuteCommand方法之中,你可以使用session實例來發送數據到客戶端,你也可以通過session.AppServer語句來訪問AppServer,然后用AppServer的屬性和方法來實現你的業務邏輯。
public override void ExecuteCommand(EchoSession session, MyCommandInfo commandInfo)
{
var appServer = session.AppServer;
//Your business logics
//Send data to client
session.SendResponse(commandInfo.Data);
}
SuperSocket 1.4系列文檔(6) 在AppSession和Commands中訪問AppServer
在AppSession和Commands中訪問AppServer很方便,示例代碼如下:
public class YourSession : AppSession<YourSession>
{
public override void StartSession()
{
SendResponse("Welcome to " + AppServer.Name);
}
public override void HandleExceptionalError(Exception e)
{
}
}
public class STOP : StringCommandBase<EchoSession>
{
#region CommandBase<EchoSession> Members
public override void ExecuteCommand(EchoSession session, StringCommandInfo commandInfo)
{
session.AppServer.Stop();
}
#endregion
}
雖然你可以訪問AppServer的最基本接口所定義的屬性和方法,但是你沒有辦法訪問你自己實現的AppServer的方法和屬性。你可以直接將AppServer轉化成你自己的AppServer類型來解決這個問題,不過SuperSocket為你提供了更方便的解決方法。
你可以用new關鍵字來重寫AppSession基類的AppServer屬性,代碼如下:
public class BroadcastSession : AppSession<BroadcastSession>
{
public string DeviceNumber { get; set; }
public new BroadcastServer AppServer
{
get { return (BroadcastServer)base.AppServer; }
}
public override void HandleExceptionalError(Exception e)
{
}
}
這樣你就可以在AppSession或者Commands之中直接訪問你自己定義的AppServer的功能了。
public class BROA : StringCommandBase<BroadcastSession>
{
public override void ExecuteCommand(BroadcastSession session, StringCommandInfo commandData)
{
string message = commandData.Data;
session.AppServer.BroadcastMessage(session, message);
session.SendResponse("101 message broadcasted");
}
}