CODE_SUPERSOCKE1

新建项目步骤

  1. 在vs中创建一个空白解决方案,选择好路径。
  2. 在解决方案下创建项目。VisualC# → Windows → 控制台应用程序.
  3. 右键项目 → 属性 → 应用程序 → 目标框架 → .NET Framework 4.
  4. 右键引用→浏览添加supersocket需要的.dll文件。
  5. 右键项目新建文件夹Config,添加现有文件log4net.config和log4net.unix.config。这两个文件的属性按照要求进行设置即可。
  6. 调试运行出现错误。
  7. 右键引用 → .NET 添加错误提示中需要的.dll文件。

    测试指令

  8. Telnet测试指令

    • telnet 127.0.0.1 2017

      问题

  9. 当一个类显示没有被包含进来的时候,需要根据API手册,找到相应的类。

  10. 当在使用Command时,调用自己写的APPSession和APPServer的时候出现了访问类型不一致的问题。原因是:自定义的AppSession的类的访问权限应该使用public进行限制。

    经验

  11. 在AppServer中OnStartup方法已经过时了(obsolete),替代的方法是OnStarted方法。

  12. 在相对位置不同的类中引用其它路径下的类的时候,需要首先需要使用这个类的命名空间。
  13. 一个配置文件实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <?xml version="1.0"?>
    <configuration>
    <configSections>
    <section name="superSocket"
    type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine" />
    </configSections>
    <appSettings>
    <add key="ServiceName" value="SupperSocketService" />
    </appSettings>
    <!--开启匹配功能-->
    <superSocket xmlns="http://schema.supersocket.net/supersocket"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://schema.supersocket.net/supersocket http://schema.supersocket.net/v1-6/supersocket.xsd">
    <servers>
    <server name="GameServer"
    logFactory="ConsoleLogFactory"
    serverTypeName="GameServer"
    ip="Any"
    port="2017"
    >
    </server>
    </servers>
    <!--type的第一个参数是服务器类的具体路径,第二个参数是项目名(是程序集名,而不是类的命名空间)-->
    <serverTypes>
    <add name="GameServer"
    type="SuperSocketServer.Server1.GameServer, SuperSocketServer"/>
    </serverTypes>
    <!--为该服务器添加日志,生成的日志文件在bin/Debug/logs中进行查看;同时由于开启了日志功能,控制台也会打印相关的信息-->
    <logFactories>
    <add name="ConsoleLogFactory"
    type="SuperSocket.SocketBase.Logging.ConsoleLogFactory, SuperSocket.SocketBase" />
    </logFactories>
    </superSocket>
    <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
    </startup>
    </configuration>
  14. Command运行不稳定啊啊啊

  15. 使用自定义RequestInfo,AppSession的固定数量分隔符协议

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public CounterReceiveFilter() : base((byte)'#', 11)
    {
    }
    public MyAppServer()
    ​ : base(new DefaultReceiveFilterFactory< CounterReceiveFilter, RequestInfo>())
    ​ {


    }
  16. 使用自定义RequestInfo,AppSession的结束符协议协议

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    class TerReceiveFilter : TerminatorReceiveFilter<RequestInfoFirst>
    {
    public TerReceiveFilter()
    : base(Encoding.Default.GetBytes("##")) //传入固定的请求大小
    {
    }
    protected override RequestInfoFirst ProcessMatchedRequest(byte[] data, int offset, int length)
    {
    ///使用一个变量之前必须给它分配相应的内存空间
    RequestInfoFirst info=new RequestInfoFirst();
    info.totalCmd_App = "Hello World";
    return info;
    }
    }
    class GameServer:AppServer<GameSession,RequestInfoFirst>
    {
    string TAG = "GameServer:";
    /// <summary>
    /// AppServer only has two constructors
    /// </summary>
    public GameServer()
    : base(new DefaultReceiveFilterFactory<TerReceiveFilter, RequestInfoFirst>())
    {
    NewSessionConnected += GameServer_NewSessionConnected;
    NewRequestReceived += GameServer_NewRequestReceived;
    }
    private void GameServer_NewRequestReceived(GameSession session, RequestInfoFirst requestInfo)
    {
    Console.WriteLine(requestInfo.totalCmd_App);
    }
    private void GameServer_NewSessionConnected(GameSession session)
    {
    Console.WriteLine(TAG + "GameServer_NewSessionConnected");
    }
  17. 当错误提示为“是否缺少using指令或程序集引用”时,可以采取以下办法:

    • 去API中找相应出错方法的命名空间。
    • 在IDE中找到出错方法的定义处,寻找相应的命名空间。
    • 百度寻找相应方法的命名空间。
  18. ASCII 表对照

  19. 使用自定义RequestInfo,AppSession的头部格式固定且包含内容长度的协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class FixedReceiveFilter: FixedHeaderReceiveFilter<BinaryRequestInfo>
{
public FixedReceiveFilter()
: base(6)
{
}
//只要输入完了长度,这个函数就会自动被触发
protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
{
//这个地方计算的请求体的长度不对。
int lengthOfBody= (header[offset + 4] -48)*10 + header[offset + 5]-48;
Console.WriteLine("header[offset + 4]:"+header[offset + 4]+";header[offset + 5]:"+header[offset + 5]+";lengthOfBody:" + lengthOfBody);
return lengthOfBody;
}
protected override BinaryRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
{
//因为BinaryRequestInfo中的数据成员都是只读的
//所以需要在构造这个对象的时候,给给它进行赋值。
return new BinaryRequestInfo(Encoding.UTF8.GetString(header.Array, header.Offset, 4), bodyBuffer.CloneRange(offset, length));
}
}
class GameServer : AppServer<GameSession, BinaryRequestInfo>
{
string TAG = "GameServer:";
public GameServer()
: base(new DefaultReceiveFilterFactory<FixedReceiveFilter, BinaryRequestInfo>())
{
NewSessionConnected += GameServer_NewSessionConnected;
NewRequestReceived += GameServer_NewRequestReceived;
}
private void GameServer_NewRequestReceived(GameSession session, BinaryRequestInfo requestInfo)
{
Console.WriteLine(requestInfo.Key+":"+requestInfo.Body);
}
private void GameServer_NewSessionConnected(GameSession session)
{
Console.WriteLine(TAG + "GameServer_NewSessionConnected");
}
}
  1. 特别注意

    • session、server、command的定义方法:
    1
    2
    3
    4
    5
    public class GameSession : AppSession<GameSession, BinaryRequestInfo>{}

    public class GameServer : AppServer<GameSession, BinaryRequestInfo>{}

    public class RESTART : CommandBase<GameSession, BinaryRequestInfo>{}

    从上面不难看出只要是使用的session的地方不论是server还是command,他们的另外一个RequestInfo参数必须是和Session中的RequestInfo的参数是一样的,否则会出现参数类型不匹配的错误。

  2. C#中实现接口
    https://www.cnblogs.com/ben-zhang/archive/2012/12/18/2823455.html

  3. SuperSocket实现接口举例

    • 接口

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      // 摘要:
      // Receive filter interface
      //
      // 类型参数:
      // TRequestInfo:
      // The type of the request info.
      public interface IReceiveFilter<TRequestInfo> where TRequestInfo : global::SuperSocket.SocketBase.Protocol.IRequestInfo
      {
      // 摘要:
      // Gets the size of the rest buffer.
      int LeftBufferSize { get; }
      //
      // 摘要:
      // Gets the next Receive filter.
      IReceiveFilter<TRequestInfo> NextReceiveFilter { get; }
      //
      // 摘要:
      // Gets the filter state.
      FilterState State { get; }

      // 摘要:
      // Filters received data of the specific session into request info.
      //
      // 参数:
      // readBuffer:
      // The read buffer.
      //
      // offset:
      // The offset of the current received data in this read buffer.
      //
      // length:
      // The length of the current received data.
      //
      // toBeCopied:
      // if set to true [to be copied].
      //
      // rest:
      // The rest, the length of the data which hasn't been parsed.
      TRequestInfo Filter(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest);
      //
      // 摘要:
      // Resets this instance to initial state.
      void Reset();
      }
    • 实现接口的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class XieReceiveFilter:IReceiveFilter<GameRequestInfo>
{
public int LeftBufferSize
{
//必须要实现get方法。
get
{ return 1; }
}

public IReceiveFilter<GameRequestInfo> NextReceiveFilter
{
//如果不实现get方法,就会报错,就会报没有实现接口的错。
get;
}

public FilterState State
{
get
{
throw new NotImplementedException();
}
}

public GameRequestInfo Filter(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest)
{
throw new NotImplementedException();
}

public void Reset()
{
throw new NotImplementedException();
}
}
  1. 既然要实现接口,那么接口的返回值和函数名一节形参都是不能够改变的。

  2. 为服务器应用自己的过滤器工厂
  • RequestInfo

    1
    2
    3
    4
    public class GameRequestInfo:IRequestInfo
    {
    public string Key { get;set;}
    }
  • Session

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class GameSession : AppSession<GameSession, GameRequestInfo>
    ​ {
    protected override void OnSessionStarted()
    ​ {
    this.Send("Welcome to SuperSocket Telnet Server");
    ​ }

    protected override void HandleUnknownRequest(GameRequestInfo requestInfo)
    {
    this.Send("Unknow request");
    }
    protected override void HandleException(Exception e)
    {
    this.Send("Application error: {0}", e.Message);
    }

    protected override void OnSessionClosed(CloseReason reason)
    {
    //add you logics which will be executed after the session is closed
    base.OnSessionClosed(reason);
    }
    }
  • Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class XieReceiveFilter:IReceiveFilter<GameRequestInfo>
{
public int LeftBufferSize
{
get
{
throw new NotImplementedException();
}
}

public IReceiveFilter< GameRequestInfo> NextReceiveFilter
{
get
{
throw new NotImplementedException();
}
}

public FilterState State
{
get
{
throw new NotImplementedException();
}
}

public GameRequestInfo Filter(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest)
{
throw new NotImplementedException();
}

public void Reset()
{
throw new NotImplementedException();
}
}
  • FilterFactory

  • 1
    2
    3
    4
    5
    6
    7
    class XieReceiveFilterFactory : IReceiveFilterFactory<GameRequestInfo>
    {
    public IReceiveFilter<GameRequestInfo> CreateFilter(IAppServer appServer, IAppSession appSession, IPEndPoint remoteEndPoint)
    {
    throw new NotImplementedException();
    }
    }
  • Server

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class GameServer : AppServer<GameSession, GameRequestInfo>
    {
    string TAG = "GameServer:";
    public GameServer()
    : base(new XieReceiveFilterFactory())
    {
    NewSessionConnected += GameServer_NewSessionConnected;
    NewRequestReceived += GameServer_NewRequestReceived;
    }
    private void GameServer_NewRequestReceived(GameSession session, GameRequestInfo requestInfo)
    {
    Console.WriteLine(requestInfo.ToString());
    }
    private void GameServer_NewSessionConnected(GameSession session)
    {
    Console.WriteLine(TAG + "GameServer_NewSessionConnected");
    }
    }