SuperSocket 簡單示例


這是一個SuperSocket 簡單示例,包括服務端和客戶端。

一、首先使用NuGet安裝SuperSocket和SuperSocket.Engine

二、實現IRequestInfo(數據包):

數據包格式:

包頭4個字節,前2個字節是請求命令,后2個字節是正文長度

using SuperSocket.SocketBase.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SuperSocketServer
{
    public class MyRequestInfo : IRequestInfo
    {
        public MyRequestInfo(byte[] header, byte[] bodyBuffer)
        {
            Key = ASCIIEncoding.ASCII.GetString(new byte[] { header[0], header[1] });
            Data = bodyBuffer;
        }

        public string Key { get; set; }

        public byte[] Data { get; set; }

        public string Body
        {
            get
            {
                return Encoding.UTF8.GetString(Data);
            }
        }
    }
}
View Code

三、實現FixedHeaderReceiveFilter(數據包解析):

using SuperSocket.Facility.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SuperSocketServer
{
    public class MyReceiveFilter : FixedHeaderReceiveFilter<MyRequestInfo>
    {
        public MyReceiveFilter() : base(4)
        {

        }

        protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
        {
            return BitConverter.ToInt16(new byte[] { header[offset + 2], header[offset + 3] }, 0);
        }

        protected override MyRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
        {
            byte[] body = bodyBuffer.Skip(offset).Take(length).ToArray();
            return new MyRequestInfo(header.Array, body);
        }
    }
}
View Code

四、實現AppSession:

using SuperSocket.SocketBase;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SuperSocketServer
{
    public class MySession : AppSession<MySession, MyRequestInfo>
    {
        public MySession()
        {

        }

        protected override void OnSessionStarted()
        {

        }

        protected override void OnInit()
        {
            base.OnInit();
        }

        protected override void HandleUnknownRequest(MyRequestInfo requestInfo)
        {

        }

        protected override void HandleException(Exception e)
        {

        }

        protected override void OnSessionClosed(CloseReason reason)
        {
            base.OnSessionClosed(reason);
        }
    }
}
View Code

五、實現AppServer:

using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utils;

namespace SuperSocketServer
{
    public class MyServer : AppServer<MySession, MyRequestInfo>
    {
        public MyServer() : base(new DefaultReceiveFilterFactory<MyReceiveFilter, MyRequestInfo>())
        {
            this.NewSessionConnected += MyServer_NewSessionConnected;
            this.SessionClosed += MyServer_SessionClosed;
        }

        protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
        {
            return base.Setup(rootConfig, config);
        }

        protected override void OnStarted()
        {
            base.OnStarted();
        }

        protected override void OnStopped()
        {
            base.OnStopped();
        }

        void MyServer_NewSessionConnected(MySession session)
        {
            LogHelper.Log("新客戶端連接,SessionID=" + session.SessionID.Substring(session.SessionID.Length - 6).ToUpper());
        }

        void MyServer_SessionClosed(MySession session, CloseReason value)
        {
            LogHelper.Log("客戶端失去連接,SessionID=" + session.SessionID.Substring(session.SessionID.Length - 6).ToUpper() + ",原因:" + value);
        }
    }
}
View Code

六、實現CommandBase<MySession, MyRequestInfo>:

using SuperSocket.SocketBase.Command;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utils;

namespace SuperSocketServer
{
    public class EC : CommandBase<MySession, MyRequestInfo>
    {
        public override void ExecuteCommand(MySession session, MyRequestInfo requestInfo)
        {
            LogHelper.Log("客戶端 " + session.SessionID.Substring(session.SessionID.Length - 6).ToUpper() + " 發來消息:" + requestInfo.Body);
            byte[] bytes = ASCIIEncoding.UTF8.GetBytes("消息收到");
            session.Send(bytes, 0, bytes.Length);
        }
    }
}
View Code

七、服務端Form1.cs代碼:

using SuperSocket.SocketBase.Config;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Utils;

namespace SuperSocketServer
{
    public partial class Form1 : Form
    {
        private MyServer _myServer;

        public Form1()
        {
            InitializeComponent();
            LogHelper.Init(this, txtLog);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _myServer = new MyServer();
            ServerConfig serverConfig = new ServerConfig()
            {
                Port = 2021
            };
            _myServer.Setup(serverConfig);
            _myServer.Start();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            foreach (MySession session in _myServer.GetAllSessions())
            {
                byte[] bytes = ASCIIEncoding.UTF8.GetBytes("服務端廣播消息");
                session.Send(bytes, 0, bytes.Length);
            }
        }
    }
}
View Code

八、客戶端Form1.cs代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SuperSocketClient
{
    public partial class Form1 : Form
    {
        private Socket _socket;

        private NetworkStream _socketStream;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            EndPoint serverAddress = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2021);
            _socket = new Socket(serverAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _socket.Connect(serverAddress);
            _socketStream = new NetworkStream(_socket);

            //SocketAsyncEventArgs socketAsyncArgs = new SocketAsyncEventArgs();
            //byte[] buffer = new byte[10240];
            //socketAsyncArgs.SetBuffer(buffer, 0, buffer.Length);
            //socketAsyncArgs.Completed += ReciveAsync;
            //_socket.ReceiveAsync(socketAsyncArgs);

            Receive(_socket);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                Random rnd = new Random();
                string cmd = "EC";
                string msg = "測試消息00" + rnd.Next(0, 100).ToString("00");
                Send(cmd, msg);
            });
        }

        public void Send(string cmd, string msg)
        {
            byte[] cmdBytes = Encoding.ASCII.GetBytes(cmd);
            byte[] msgBytes = Encoding.UTF8.GetBytes(msg);
            byte[] lengthBytes = BitConverter.GetBytes((short)msgBytes.Length);

            _socketStream.Write(cmdBytes, 0, cmdBytes.Length);
            _socketStream.Write(lengthBytes, 0, lengthBytes.Length);
            _socketStream.Write(msgBytes, 0, msgBytes.Length);
            _socketStream.Flush();
            Log("發送:" + msg);
        }

        private void ReciveAsync(object obj, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0)
            {
                string data = ASCIIEncoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                Log("接收:" + data);
            }
        }

        private void Receive(Socket socket)
        {
            Task.Factory.StartNew(() =>
            {
                try
                {
                    while (true)
                    {
                        byte[] buffer = new byte[10240];
                        int receiveCount = _socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                        if (receiveCount > 0)
                        {
                            string data = ASCIIEncoding.UTF8.GetString(buffer, 0, receiveCount);
                            Log("接收:" + data);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log("Receive出錯:" + ex.Message + "\r\n" + ex.StackTrace);
                }
            }, TaskCreationOptions.LongRunning);
        }

        #region Log
        /// <summary>
        /// 輸出日志
        /// </summary>
        private void Log(string log)
        {
            if (!this.IsDisposed)
            {
                this.BeginInvoke(new Action(() =>
                {
                    txtLog.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + " " + log + "\r\n\r\n");
                }));
            }
        }
        #endregion

    }
}
View Code

輔助工具類LogHelper:

using SuperSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Utils
{
    public class LogHelper
    {
        private static Form1 _frm;

        private static TextBox _txtLog;

        public static void Init(Form1 frm, TextBox txt)
        {
            _frm = frm;
            _txtLog = txt;
        }

        /// <summary>
        /// 輸出日志
        /// </summary>
        public static void Log(string log)
        {
            if (!_frm.IsDisposed)
            {
                _frm.BeginInvoke(new Action(() =>
                {
                    _txtLog.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + " " + log + "\r\n\r\n");
                }));
            }
        }

    }
}
View Code

測試截圖:

問題:

1、客戶端使用SocketAsyncEventArgs異步接收數據,第一次能收到數據,后面就收不到了,不知道什么原因,同步接收數據沒問題

2、SuperSocket源碼中的示例和網上相關的博客,客戶端要么是原生Socket實現,要么是Socket調試工具,客戶端不需要復雜一點的功能或數據結構嗎?客戶端不需要解包嗎?SuperSocket不能用來寫客戶端嗎?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM