Home>

The protocol analysis in socket is the most complicated place in socket communication program design.If your application layer protocol is poorly designed or implemented,Common sticky packets in socket communication,Subcontracting is unavoidable.supersocket has a commandline protocol built into the command line format. If you use a protocol in another format,You must implement your own custom protocol protocol. After reading a document, You may find it difficult to implement your custom protocol with supersocket. To make this easier, supersocket provides some general protocol parsing tools, You can use them to implement your own communication protocol simply and quickly:

terminatorreceivefilter(supersocket.socketbase.protocol.terminatorreceivefilter, supersocket.socketbase) --- terminator protocol countspliterreceivefilter(supersocket.facility.protocol.countspliterreceivefilter, supersocket.facility) --- fixed number separator protocol fixedsizereceivefilter(supersocket.facility.protocol.fixedsizereceivefilter, supersocket.facility) --- fixed request size protocol beginendmarkreceivefilter(supersocket.facility.protocol.beginendmarkreceivefilter, supersocket.facility) --- with start and stop protocol fixedheaderreceivefilter(supersocket.facility.protocol.fixedheaderreceivefilter, supersocket.facility) --- The header format is fixed and contains the content length protocol

1.terminatorreceivefilter terminator protocol

The terminator protocol is similar to the command line protocol,Some protocols use a terminator to determine a request.For example, a protocol uses two characters "##" as a terminator, Then you can use the class "terminatorreceivefilterfactory":

Terminator protocol:terminatorprotocolserver:

public class terminatorprotocolserver:appserver
{
 public terminatorprotocolserver ()
  :base (new terminatorreceivefilterfactory ("##"))
 {
 }
}

Implement your receivefilter based on terminatorreceivefilter:

public class yourreceivefilter:terminatorreceivefilter<yourrequestinfo>
{
 //more code
}

Implement your receive filter factory to create acceptance filter instances:

public class yourreceivefilterfactory:ireceivefilterfactory<yourrequestinfo>
{
 //more code
}

2, countspliterreceivefilter fixed number separator protocol

Some protocols define requests in this format "#part1 #part2 #part3 #part4 #part5 #part6 #part7 #". Each request has 7 parts separated by "#". The implementation of this protocol is very simple:

///<summary>
///Request format:#part1 #part2 #part3 #part4 #part5 #part6 #part7 #
///</summary>
public class countspliterappserver:appserver
{
 public countspliterappserver ()
  :base (new countspliterreceivefilterfactory ((byte) "#", 8)) //8 delimiters,7 parameters. In addition to using the default filter factory,You can also customize the protocol by referring to the previous example
 {
 }
}

3. fixedsizereceivefilter fixed request size protocol

In this agreement, All requests are the same size.If each of your requests is a string of 8 characters,Like "huang li", what you should do is to implement a receive filter like this:

class myreceivefilter:fixedsizereceivefilter<stringrequestinfo>
{
 public myreceivefilter ()
  :base (8) //Incoming fixed request size
 {
 }
 protected override stringrequestinfo processmatchedrequest (byte [] buffer, int offset, int length, bool tobecopied)
 {
  //todo:Construct the request instance from the parsed data,And return
 }
}

Then use this receive filter in your appserver class:

public class myappserver:appserver
{
 public myappserver ()
  :base (new defaultreceivefilterfactory<myreceivefilter, stringrequestinfo>()) //Use the default acceptance filter factory (defaultreceivefilterfactory)
 {
 }
}

4, beginmarkreceivefilter with start and stop protocol

There is a fixed start and end tag in every request of this type of protocol.For example, I have an agreement,All its messages follow this format "&xxxxxxxxxxxxxx #". So in this case, "&" Is the start tag, "#" Is the end tag,So your acceptance filter can be defined like this:

class myreceivefilter:beginendmarkreceivefilter<stringrequestinfo>
{
 //The start and end tags can also be two or more bytes
 private readonly static byte [] beginmark=new byte [] {(byte) "&"};
 private readonly static byte [] endmark=new byte [] {(byte) "#"};
 public myreceivefilter ()
  :base (beginmark, endmark) //Pass in the start and end marks
 {
 }
 protected override stringrequestinfo processmatchedrequest (byte [] readbuffer, int offset, int length)
 {
  //todo:Construct the request instance from the parsed data,And return
 }
}

Then use this receive filter in your appserver class:

public class myappserver:appserver
{
 public myappserver ()
  :base (new defaultreceivefilterfactory<myreceivefilter, stringrequestinfo>()) //Use the default acceptance filter factory (defaultreceivefilterfactory)
 {
 }
}

5, fixedheaderreceivefilter header format is fixed and contains the content length protocol

This protocol defines a request as two major parts, The first part defines the basic information including the length of the second part and so on. We usually call the first part the head.

For example, we have a protocol like this:the header contains 6 bytes, the first 4 bytes are used to store the requested name, The last two bytes are used to represent the length of the request body:

///+ ------- + --- + ------------------------------- +

///| request | l | |

///| name | e | request body |

///| (4) | n | |

///| | (2) | |

///+ ------- + --- + ------------------------------- +

With supersocket, you can implement this protocol very conveniently:

class myreceivefilter:fixedheaderreceivefilter<binaryrequestinfo>
{
 public myreceivefilter ()
  :base (6)
 {
 }
 protected override int getbodylengthfromheader (byte [] header, int offset, int length)
 {
  return (int) header [offset + 4] * 256 + (int) header [offset + 5];
 }
 protected override binaryrequestinfo resolverequestinfo (arraysegment<byte>header, byte [] bodybuffer, int offset, int length)
 {
  return new binaryrequestinfo (encoding.utf8.getstring (header.array, header.offset, 4), bodybuffer.clonerange (offset, length));
 }
}

You need to implement your own acceptance filter based on the class fixedheaderreceivefilter.

The 6 passed into the constructor of the parent class represents the length of the header; The method "getbodylengthfromheader (...)" should return the length of the request body based on the header received; The method resolverequestinfo (....) "should return an instance of your request type based on the request header and request body you received.

Actual use scenario:

You have already learned about the five protocol templates here.And know the relevant format processing.Let's look at an example network:

Communication protocol format:

I see that the protocol is tangled in the client sending hexadecimal, how the server receives,Hex messages are as follows:

26 01 00 19 4e 4a 30 31 31 01 44 41 31 31 32 00 07 00 00 00 00 00 00 34 34

Hex is also good,Decimal is also good,Other bases are also good,Eventually they are converted to byte []. In fact, when processing data,The data sent in the past can be converted into byte [], so the service only needs to parse byte [] array.Parsing according to the protocol can get the desired data.The following example uses fixedsizereceivefilter, the code is as follows:

According to the communication protocol above,Let's start the analysis:

The first step is to define a data structure suitable for the protocol

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
/************************************************* ***************
* clr version:4.0.30319.42000
* Creation time:2017-01-23 21:12:30
* 2017
* Description:protocol data packet
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
 public class hldata
 {
  ///<summary>
  ///start symbol
  ///</summary>
  public char head {get;set;}
  ///<summary>
  ///protocol packet data
  ///</summary>
  public byte ping {get;set;}
  ///<summary>
  ///Data length
  ///</summary>
  public ushort lenght {get;set;}
  ///<summary>
  ///terminal id
  ///</summary>
  public uint fid {get;set;}
  ///<summary>
  ///target type
  ///</summary>
  public byte type {get;set;}
  ///<summary>
  ///Forwarding terminal id
  ///</summary>
  public uint sid {get;set;}
  ///<summary>
  ///send count
  ///</summary>
  public ushort sendcount {get;set;}
  ///<summary>
  ///reserved text
  ///</summary>
  public byte [] retain {get;set;}
  ///<summary>
  ///XOR check
  ///</summary>
  public byte check {get;set;}
  ///<summary>
  ///end symbol
  ///</summary>
  public char end {get;set;}
  public override string tostring ()
  {
   return string.format ("Start symbol:{0}, packet data:{1}, data length:{2}, terminal id:{3}, destination type:{4}, forwarding terminal id:{5}, send Packet count:{6}, reserved field:{7}, XOR check:{8}, end symbol:{9} ",    head, ping, lenght, fid, type, sid, sendcount, retain, check, end);
  }
 }
}
hldata

The second step is to create a requestinfo to receive data from the server.

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using supersocket.socketbase.protocol;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created time:2017-01-22 21:03:31
* 2017
* Description:data request
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
 public class hlprotocolrequestinfo:requestinfo<hldata>
 {
  public hlprotocolrequestinfo (hldata hldata)
  {
   //If you need to use the command line protocol,Then the command class name hldata is the same
   initialize ("hldata", hldata);
  }
 }
}
hlprotocolrequestinfo class

The third step, the fixedsize protocol analysis

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using supersocket.socketbase.protocol;
using supersocket.facility.protocol;
using supersocket.common;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created time:2017-01-22 21:06:01
* 2017
* Description:protocol analysis class,Fixed request size protocol
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
 ///<summary>
 ///protocol with fixed request size,(Frame format is hlprotocolrequestinfo)
 ///</summary>
 public class hlprotocolreceivefilter:fixedsizereceivefilter<hlprotocolrequestinfo>
 {
  public hlprotocolreceivefilter ():base (25) //total byte length 1 + 1 + 2 + 5 + 1 + 5 + 2 + 6 + 1 + 1=25
  {
  }
  protected override hlprotocolrequestinfo processmatchedrequest (byte [] buffer, int offset, int length, bool tobecopied)
  {
   var hldata=new hldata ();
   hldata.head=(char) buffer [offset];//Begin parsing of identifiers,1 byte
   hldata.ping=buffer [offset + 1];//Data, starting from the second bit, only 1 byte
   hldata.lenght=bitconverter.touint16 (buffer, offset + 2);//data length,Starting from the 3rd bit, 2 bytes
   hldata.fid=bitconverter.touint32 (buffer, offset + 4);//this terminal id, starting from the 5th bit, 5 bytes
   hldata.type=buffer [offset + 9];//Target type,Starting from the 10th bit, 1 byte
   hldata.sid=bitconverter.touint32 (buffer, offset + 10);//Forwarding terminal id, starting from the 11th bit, 5 bytes
   hldata.sendcount=bitconverter.touint16 (buffer, offset + 15);//Send packet count,Starting from 16th bit, 2 bytes
   hldata.retain=buffer.clonerange (offset + 17, 6);//reserved fields,Starting from 18 bits, 6 bytes
   hldata.check=buffer [offset + 23];//Exclusive OR check,Starting from 24 bits, 1 byte
   hldata.end=(char) buffer [offset + 24];//End symbol,From byte 25, one byte
   return new hlprotocolrequestinfo (hldata);
  }
 }
}
hlprotocolreceivefilter class

The fourth step, the establishment of the agreement factory hlreceivefilterfactory

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using supersocket.socketbase;
using supersocket.socketbase.protocol;
using system.net;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created time:2017-01-23:22:01:25
* 2017
* Description:Agreement factory
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
 public class hlreceivefilterfactory:ireceivefilterfactory<hlprotocolrequestinfo>
 {
  public ireceivefilter<hlprotocolrequestinfo>createfilter (iappserver appserver, iappsession appsession, ipendpoint remoteendpoint)
  {
   return new hlbeginendmarkreceivefilter ();
  }
 }
}
hlreceivefilterfactory class

The fifth step, custom hlprotocolsession inherits appsession

using supersocket.socketbase;
using supersocket.socketbase.protocol;
using system;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created time:2017-01-22 21:15:11
* 2017
* Description:Custom hlprotocolsession
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
 public class hlprotocolsession:appsession<hlprotocolsession, hlprotocolrequestinfo>
 {
  protected override void handleexception (exception e)
  {
  }
 }
}
hlprotocolsession class

Step 6.Custom hlprotocolserver inherits appserver

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using supersocket.socketbase;
using supersocket.socketbase.protocol;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created time:2017-01-22 21:16:57
* 2017
* Description:Custom server
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
 public class hlprotocolserver:appserver<hlprotocolsession, hlprotocolrequestinfo>
  {
    ///<summary>
    ///use custom protocol factory
    ///</summary>
    public hlprotocolserver ()
      :base (new hlreceivefilterfactory ())
    {
    }
  }
}
hlprotocolserver class

Step 7. Add start and stop agreement hlbeginendmarkreceivefilter

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using supersocket.common;
using supersocket.facility.protocol;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created time:2017-01-23 22:07:03
* 2017
* Description:agreement with start and stop characters, "&" Is the start tag, "#" Is the end tag,Start and end tags are defined by yourself
*
* Revision history:
*
*
************************************************** *************** /
namespace supersocketdemo
{
  public class hlbeginendmarkreceivefilter:beginendmarkreceivefilter<hlprotocolrequestinfo>
  {
    private readonly static char strbegin="&";
    private readonly static char strend="#";
    //The start and end tags can also be two or more bytes
    private readonly static byte [] beginmark=new byte [] {(byte) strbegin};
    private readonly static byte [] endmark=new byte [] {(byte) strend};
    public hlbeginendmarkreceivefilter ():base (beginmark, endmark)
    {
    }
    ///<summary>
    ///The data parsed here will remove both the head and tail
    ///</summary>
    ///<param name="readbuffer"></param>
    ///<param name="offset"></param>
    ///<param name="length"></param>
    ///<returns></returns>
    protected override hlprotocolrequestinfo processmatchedrequest (byte [] readbuffer, int offset, int length)
    {
      var hldata=new hldata ();
      hldata.head=strbegin;//define the start symbol
      hldata.ping=readbuffer [offset];//Data, from the first bit, only 1 byte
      hldata.lenght=bitconverter.touint16 (readbuffer, offset + 1);//data length,Starting from the second bit, 2 bytes
      hldata.fid=bitconverter.touint32 (readbuffer, offset + 3);//this terminal id, starting from the 4th bit, 5 bytes
      hldata.type=readbuffer [offset + 8];//Target type,Starting from the 9th bit, 1 byte
      hldata.sid=bitconverter.touint32 (readbuffer, offset + 9);//Forwarding terminal id, starting from the 10th bit, 5 bytes
      hldata.sendcount=bitconverter.touint16 (readbuffer, offset + 14);//Send packet count,Starting from the 15th bit, 2 bytes
      hldata.retain=readbuffer.clonerange (offset + 16, 6);//reserved fields,Starting from 17 bits, 6 bytes
      hldata.check=readbuffer [offset + 22];//Exclusive OR check,Starting from 23 bits, 1 byte
      hldata.end=strend;//End symbol,arrogant
      return new hlprotocolrequestinfo (hldata);
    }
  }
}
hlbeginendmarkreceivefilter class

Step eight, service start and stop

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;
/************************************************* ***************
* clr version:4.0.30319.42000
* Created:2017-01-19 00:02:17
* 2017
* Description:service start and stop entrance
*
* Revision history:2017-01-01 Adjust custom mysession and myserver
* 2017 -01-23 communication protocol analysis,Register events directly with portals
*
************************************************** *************** /
namespace supersocketdemo
{
  class program
  {
    ///<summary>
    ///start or stop the supersocket service
    ///</summary>
    ///<param name="args"></param>
    static void main (string [] args)
    {
      console.writeline ("Please press any key to start the supersocket service!");
      console.readkey ();
      console.writeline ();
      var hlprotocolserver=new hlprotocolserver ();
      //Set the port number
      int port=2017;
      //Start the application service port
      if (! hlprotocolserver.setup (port)) //Listen to port 2017 at startup
      {
        console.writeline ("Service port failed to start!");
        console.readkey ();
        return;
      }
      console.writeline ();
      //Register connection event
      hlprotocolserver.newsessionconnected +=hlprotocolserver_newsessionconnected;
      //Registration request event
      hlprotocolserver.newrequestreceived +=hlprotocolserver_newrequestreceived;
      //Register session close event
      hlprotocolserver.sessionclosed +=hlprotocolserver_sessionclosed;
      //Try to start the application service
      if (! hlprotocolserver.start ())
      {
        console.writeline ("Service startup failed!");
        console.readkey ();
        return;
      }
      console.writeline ("Server State:" + hlprotocolserver.state.tostring ());
      console.writeline ("The service started successfully.
Please press "e" to stop service! ");
      while (console.readkey (). keychar!="e")
      {
        console.writeline ();
        continue;
      }
      //Out of service
      hlprotocolserver.stop ();
      console.writeline ("Service stopped!");
      console.readkey ();
    }
    static void hlprotocolserver_sessionclosed (hlprotocolsession session, supersocket.socketbase.closereason value)
    {
      console.writeline (session.remoteendpoint.tostring () + "The connection was broken.
 Reason for disconnection:"+ value);
    }
    static void hlprotocolserver_newsessionconnected (hlprotocolsession session)
    {
      console.writeline (session.remoteendpoint.tostring () + "connected.");
    }
    ///<summary>
    ///The protocol doesn't have much complicated logic,No command mode is needed,Just use this method.
    ///</summary>
    ///<param name="session"></param>
    ///<param name="requestinfo"></param>
    private static void hlprotocolserver_newrequestreceived (hlprotocolsession session, hlprotocolrequestinfo requestinfo)
    {
      console.writeline ();
      console.writeline ("Data source:" + session.remoteendpoint.tostring ());
      console.writeline ("Receive data content:" + requestinfo.body);
    }
  }
}
program class

The communication protocol needs to be debugged using gadgets,I usetcp/udp port debugging tool sockettool v2You can download it directly.Send hex messages using hex mode,Server output:

c
  • Previous Tutorial for logging in to MySQL after installation of MySQL 5717
  • Next C # SqlHelper application development learning