Super socket 记录知识
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");
}
}