SuperSocket actual combat - use the FixedHeaderReceiveFilter of SuperSocket for communication

Posted by MattG on Sun, 16 Jan 2022 21:38:05 +0100

       

catalogue

1, Define message format

2, Establish a TCP client

3, SuperSocket as server

1. Create a new console program SuperSocketServer

2. Use nuget tool to install SuperSocket and SuperSocket Engine library

3. Implement three classes: Filter, Session and Server

4. Key code of Main function:

A few months ago, a project needed to communicate with other devices, using TCP and UDP communication Originally, the C# original socket communication library was used, but later, a "I don't want to say his name Keng dad library" was found. After testing, it was very easy to use, so the "I don't want to say his name Keng dad library" was directly introduced into the project. The usage method is also written in the blog Park, and the test demo also uploads the code (the communication library has no source code, only dll files).

As a result, about three months later, someone left me a message saying that he downloaded the demo source code of "I don't want to say his name Keng dad library" and introduced it into the project, but it has to be charged. It has expired and their project has been hung up. At first, I didn't believe it (I was on a business trip at that time. In fact, the Keng dad Library in my own project expired). I always thought that "I don't want to say his name. Keng dad library" was free. There was something wrong with other libraries in their project. Later, I found that this library really had to charge, and the price was very high. I was * * * * *.

Fortunately, our project hasn't been launched yet, otherwise it will really die and lose face and be lost to foreign countries. But the brother who downloaded my source code is really sorry. I'm sincerely sorry for you here.

Later, I had to change it. Fortunately, the code framework was ok, and the coupling between communication and business was very low. It was easy to change the communication framework. In this world where open source is popular, I am speechless when I encounter a charging library. Later, I found SuperSocket, which is open source. The boss doesn't worry about the software expiration anymore.

This article will not introduce other things about SuperSocket, but only the communication example of FixedHeaderReceiveFilter.

Requirements: one TCP server and multiple TCP clients. The client can send messages to the server, and the server broadcasts messages to each connected client.

1, Define message format

The message format to be sent is given directly:

Public class SuperSocketMessage
    {
        public byte[] Start;//4 bytes
        public ushort Type;//2 bytes, 1 represents text message, 2 represents picture message, others represent unknown and cannot be parsed
        public int Len;//4 bytes
        public string Message;//Text information
        public byte[] Tail;//End of message

        public SuperSocketMessage()
        {
            Start = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF };
            Tail = new byte[] { 0x1F, 0x1F, 0x1F, 0x1F };
        }

        public byte[] ToBytes()
        {
            List<byte> list = new List<byte>();
            list.AddRange(Start);
            var t = BitConverter.GetBytes(Type);
            list.AddRange(t);

            var t3 = System.Text.Encoding.UTF8.GetBytes(Message);
            var t2 = BitConverter.GetBytes(t3.Length);//Note that this is not a Message Length, but the length after the Message is converted into a byte array

            list.AddRange(t2);
            list.AddRange(t3);

            return list.ToArray();
        }
}

Please remember the following numbers or information:

  1. The message header contains three elements: the start, the type, and the length of the message body
  2. Indicates the length from the sixth byte
  3. Indicates that the number of length bytes is 4 bytes
  4. The length of the Body should not be confused. It is not the string length of the Message, but the length of the Message after converting the byte array. When debugging, I started to use the string length of the Message, which caused me a waste of several hours.
  5. Please compare the above information with the parameters in the MyReceiveFilter class below.

2, Establish a TCP client

1. Create a new console program TcpClientTest. In order to test the objectivity, directly use C#'s TcpClient as the client.

2. Add class: mytcpclient cs

class MyTcpClient
    {
        private System.Net.Sockets.TcpClient tcpClient;
        public MyTcpClient(string ip, int port)
        {

            tcpClient = new System.Net.Sockets.TcpClient(ip, port);
            byte[] recData = new byte[1024];
            Action a = new Action(() =>
            {
                while (true)
                {
                    tcpClient.Client.Receive(recData);
                    var msg = System.Text.Encoding.UTF8.GetString(recData);
                    Console.WriteLine(msg);
                }
            });
            a.BeginInvoke(null, null);

        }

        public void Send(string message)
        {
            var data = System.Text.Encoding.UTF8.GetBytes(message);
            tcpClient.Client.Send(data);
        }
        public void Send(byte[] message)
        {
            tcpClient.Client.Send(message);
        }
}

3. Main function:

static void Main(string[] args)
        {
            MyTcpClient c = new MyTcpClient("127.0.0.1", 2020);
            SuperSocketMessage.SSMessage msg = new SuperSocketMessage.SSMessage();
            while (true)
            {
                string m = Console.ReadLine();
                msg.Type = 1;
                msg.Message = m;
                c.Send(msg.ToBytes());
            }
        }

The client implements the console to input any string, encapsulate it into a message and send it to the server; At the same time, start a thread to receive messages from the server. Here, the customer service side does not parse according to the standard, and directly defines the buffer 1024.

In fact, it is better to use the TCP/UDP test tool software sockettool for the client Exe impersonate client.

                                                        

3, SuperSocket as server

1. Create a new console program SuperSocketServer

 

2. Use nuget tool to install SuperSocket and SuperSocket Engine library

3. Implement three classes: Filter, Session and Server

The Filter class is as follows:

public class MyReceiveFilter : FixedHeaderReceiveFilter<BinaryRequestInfo>
    {

        public MyReceiveFilter()
            : base(10)//Message header length
        {        }
        /// <summary>
        ///
        /// </summary>
        ///< param name = "header" > * byte [] header * the cached data does not simply contain the data of the protocol header. Sometimes the tcp protocol length is 409600, many < / param >
        ///< param name = "offset" > the index of the header data starting from the cached data, generally 0 (TCP protocol may start with a large data such as 405504) < / param >
        ///< param name = "length" > this length is equal to the parameter in base(10) < / param >
        /// <returns></returns>
        protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
        {
            return GetBodyLengthFromHeader(header, offset, length, 6, 4);//6 indicates the number of bytes, and the beginning indicates the length. 4: since int indicates the length, int occupies 4 bytes
        }
        protected override BinaryRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
        {

            byte[] body = new byte[length];
            Array.Copy(bodyBuffer, offset, body, 0, length);

            Int16 type = BitConverter.ToInt16(header.ToArray(), 4);

            BinaryRequestInfo r = new BinaryRequestInfo(type.ToString(), body);
            return r;

            //The following code does not parse the body, but returns all to the previous layer
            //byte[] h = header.ToArray();
            //byte[] full = new byte[h.Count()+length];
            //Array.Copy(h, full, h.Count());
            //Array.Copy(body, 0, full, h.Count(), body.Length );
            //BinaryRequestInfo r = new BinaryRequestInfo("",full);
            //return r;

        }

        /// <summary>
        ///
        /// </summary>
        ///< param name = "header" > data to be parsed < / param >
        ///< param name = "offset" > the index of the header data starting from the header, which is generally 0 or may not be 0 < / param >
        ///< param name = "length" > this length is equal to the parameter in base(10) < / param >
        ///< param name = "lenstartindex" > indicates the number of bytes of length starting from < / param >
        ///< param name = "lenbytescount" > several bytes to represent the length: 4 bytes = int,2 bytes = int16,1 byte = byte < / param >
        /// <returns></returns>
        private int GetBodyLengthFromHeader(byte[] header, int offset, int length, int lenStartIndex, int lenBytesCount)
        {
            var headerData = new byte[lenBytesCount];
            Array.Copy(header, offset + lenStartIndex, headerData, 0, lenBytesCount);//
            if (lenBytesCount == 1)
            {
                int i = headerData[0];
                return i;
            }
            else if (lenBytesCount == 2)
            {
                int i = BitConverter.ToInt16(headerData, 0);
                return i;
            }
            else //  if (lenBytesCount == 4)
            {
                int i = BitConverter.ToInt32(headerData, 0);
                return i;
            }
        }
}

The Server and Session classes are as follows:

public class MyServer : AppServer<MySession, BinaryRequestInfo>
    {
        public MyServer()
            : base(new DefaultReceiveFilterFactory<MyReceiveFilter, BinaryRequestInfo>()) //Use the default accept filter factory (DefaultReceiveFilterFactory)
        {
        }
    }

    public class MySession : AppSession<MySession, BinaryRequestInfo>
    {
    }

BinaryRequestInfo implements the IRequestInfo interface, which is just a key. It seems that all data in SuperSocket implements this interface

4. Key code of Main function:

to configure:

MyServer appServer = new MyServer();
            var se = new SuperSocket.SocketBase.Config.ServerConfig();
            se.TextEncoding = "Unicode";// System.Text.Encoding.
            se.TextEncoding = "gbk";// System.Text.Encoding.
            se.Ip = "127.0.0.1";
            se.Port = 2020;
            se.Mode = SocketMode.Tcp;

Register, start:

if (!appServer.Setup(se)) //Setup with listening port
            {
                Console.WriteLine("Failed to setup!");
                Console.ReadKey();
                return;
            }
            Console.WriteLine();
            //Try to start the appServer
            if (!appServer.Start())
            {
                Console.WriteLine("Failed to start!");
                Console.ReadKey();
                return;
            }

Registration event:

appServer.NewSessionConnected += appServer_NewSessionConnected;
appServer.SessionClosed += appServer_SessionClosed;
appServer.NewRequestReceived += XXXXXXXXXXXXXXXXXXX

Resolution method:

static void appServer_NewRequestReceived(MySession session, BinaryRequestInfo requestInfo)
        {
            string key = requestInfo.Key;
            switch (key)
            {
                case "1":
                    Console.WriteLine("Get message from " + session.RemoteEndPoint.ToString() + ":" + System.Text.Encoding.UTF8.GetString(requestInfo.Body));
                    break;
                case "2":
                    Console.WriteLine("Get image");
                    break;
                default:
                    Console.WriteLine("Get unknown message.");
                    break;
            }
        }

OK, done The screenshot is as follows:

Attached source code download address: https://download.csdn.net/download/hanghangz/11236794

In the project, nuget is used to download packages. The contents in packages are not uploaded. The file is too large. Go to nuget yourself

Use the FixedHeaderReceiveFilter of SuperSocket for communication - thin horse - blog Garden (cnblogs.com)