SupperSocket深入浅出(一)

  花了几天时间了解了SupperSocket工作原理,各各类之间的工作关系。SupperSocket大部资料网上都有,但写的都不适合初学者。

今天花点时间写下这几天的学习成果,一方面是为了将来更好的回顾知识点,另一方面想给初学者提供一份参考资料。考虑到笔功有限,

如果下面有什么信息不正确或写的不好,请大家多多包容!

 

  首先我贴一简单的代码。后面我会详细的说明工作原理和他们之间如何调用!下面的代码我也是从网上找的,相当简单。

我今天主要是讲解下SupperSocket的理解!

public class TelnetServer : AppServer<TelnetSession>
    {
        protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
        {
            return base.Setup(rootConfig, config);
        }

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

        protected override void OnStopped()
        {
            base.OnStopped();
        }
    }
public class TelnetSession : AppSession<TelnetSession>
    {
        protected override void OnSessionStarted()
        {
            //this.Send("Welcome to SuperSocket Telnet Server\r\n");
            byte[] bytes = Encoding.ASCII.GetBytes("Welcome\r\n to SuperSocket\r\n Telnet Server\r\n");
            this.Send(bytes, 0, bytes.Length);
        }

        protected override void HandleUnknownRequest(StringRequestInfo 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);
        }
    }
public class ECHO : CommandBase<TelnetSession, StringRequestInfo>
    {
        public override void ExecuteCommand(TelnetSession session, StringRequestInfo requestInfo)
        {
            session.Send(requestInfo.Body);
        }
    }
static void Main(string[] args)
        {
            Console.WriteLine("Press any key to start the server!");

            Console.ReadKey();
            Console.WriteLine();

            var appServer = new TelnetServer();

            //Setup the appServer
            if (!appServer.Setup(2012)) //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;
            }

            Console.WriteLine("The server started successfully, press key 'q' to stop it!");

            while (Console.ReadKey().KeyChar != 'q')
            {
                Console.WriteLine();
                continue;
            }

            //Stop the appServer
            appServer.Stop();

            Console.WriteLine("The server was stopped!");
            Console.ReadKey();
        }

服务端代码就上面四部分,看起来很简单吧,但是大家真的看懂了吗,他们的工作原理是怎样的。命令 ECHO 这个类根本没有构造对象,他是怎样运行的?你越看越疑惑吧!

后面我会说明。

我还是先把客户端代码贴出来。代码简化了,如果大家不知道EasyClietn 可以使用Nuget搜索SuperSocket.ClientEngine、SuperSocket.ProtoBase 

因为版本有很多,大家最好是用Nuget

 

private void button1_Click(object sender, EventArgs e)
        {
            string strText = "add 1 1\r\n";
            if (client != null && client.IsConnected  )
            {
                Byte[] smk = new Byte[strText.Length];
                for (int i = 0; i < strText.Length; i++)
                {
                    Byte ss = Convert.ToByte(strText[i]);
                    smk[i] = ss;
                }
                byte[] b = Encoding.ASCII.GetBytes("ECHO 1 1\r\n");
                client.Send(smk.ToArray());  //EasyClient<MyPackageInfo> client
            }
        }

 

 

byte[] b = Encoding.ASCII.GetBytes("ECHO 1 1\r\n");
 client.Send(smk.ToArray());  

给服务端发送了二进制的“
ECHO 1 1\r\n" ,在这里给大家一个问题,为什么后面要加\r\n 换行符。大家带着问题继续往下看。


现在给了大家两个问题?,现在我们来解决问题。
服务端是如何接收到消息。其它大家可以不要具体体解,因为SupperStocket封闭了TCP 和 UDP 层。


SuperSocket.SocketEngine.AsyncStreamSocketSession 这个类是工作最底运类

从这个类可以知道数据的接收来源。 

这个类是由

SuperSocket.SocketEngine.AsyncStreamSocketSession 《 SuperSocket.SocketEngine.AsyncSocketServer 《 SocketServerFactory 《 ProviderKey

《 ProviderFactoryInfo 《 AppDomainAppServer 《 DefaultBootstrap

这是最底层类,获取数据和发达送数据,这个大部分我们不要了解,因为这些都被AppSession封装起来了。 

 大家想了解的可以看下这个类。

class AsyncStreamSocketSession : SocketSession, IAsyncSocketSessionBase, INegotiateSocketSession
    {
        private byte[] m_ReadBuffer;
        private int m_Offset;
        private int m_Length;

        private bool m_IsReset;

        public AsyncStreamSocketSession(Socket client, SslProtocols security, SocketAsyncEventArgsProxy socketAsyncProxy)
            : this(client, security, socketAsyncProxy, false)
        {

        }

        public AsyncStreamSocketSession(Socket client, SslProtocols security, SocketAsyncEventArgsProxy socketAsyncProxy, bool isReset)
            : base(client)
        {
            SecureProtocol = security;
            SocketAsyncProxy = socketAsyncProxy;
            var e = socketAsyncProxy.SocketEventArgs;
            m_ReadBuffer = e.Buffer;
            m_Offset = e.Offset;
            m_Length = e.Count;

            m_IsReset = isReset;
        }

        /// <summary>
        /// Starts this session communication.
        /// </summary>
        public override void Start()
        {
            //Hasn't started, but already closed
            if (IsClosed)
                return;

            OnSessionStarting();
        }

        private void OnSessionStarting()
        {
            try
            {
                OnReceiveStarted();
                m_Stream.BeginRead(m_ReadBuffer, m_Offset, m_Length, OnStreamEndRead, m_Stream);
            }
            catch (Exception e)
            {
                LogError(e);
                OnReceiveTerminated(CloseReason.SocketError);
                return;
            }

            if (!m_IsReset)
                StartSession();
        }

        private void OnStreamEndRead(IAsyncResult result)
        {
            var stream = result.AsyncState as Stream;

            int thisRead = 0;

            try
            {
                thisRead = stream.EndRead(result);
            }
            catch (Exception e)
            {
                LogError(e);
                OnReceiveTerminated(CloseReason.SocketError);
                return;
            }

            if (thisRead <= 0)
            {
                OnReceiveTerminated(CloseReason.ClientClosing);
                return;
            }

            OnReceiveEnded();

            int offsetDelta;

            try
            {
                offsetDelta = AppSession.ProcessRequest(m_ReadBuffer, m_Offset, thisRead, true);
            }
            catch (Exception ex)
            {
                LogError("Protocol error", ex);
                this.Close(CloseReason.ProtocolError);
                return;
            }

            try
            {
                if (offsetDelta < 0 || offsetDelta >= Config.ReceiveBufferSize)
                    throw new ArgumentException(string.Format("Illigal offsetDelta: {0}", offsetDelta), "offsetDelta");

                m_Offset = SocketAsyncProxy.OrigOffset + offsetDelta;
                m_Length = Config.ReceiveBufferSize - offsetDelta;

                OnReceiveStarted();
                m_Stream.BeginRead(m_ReadBuffer, m_Offset, m_Length, OnStreamEndRead, m_Stream);
            }
            catch (Exception exc)
            {
                LogError(exc);
                OnReceiveTerminated(CloseReason.SocketError);
                return;
            }
        }

        private Stream m_Stream;

        private SslStream CreateSslStream(ICertificateConfig certConfig)
        {
            //Enable client certificate function only if ClientCertificateRequired is true in the configuration
            if(!certConfig.ClientCertificateRequired)
                return new SslStream(new NetworkStream(Client), false);

            //Subscribe the client validation callback
            return new SslStream(new NetworkStream(Client), false, ValidateClientCertificate);
        }

        private bool ValidateClientCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            var session = AppSession;

            //Invoke the AppServer's method ValidateClientCertificate
            var clientCertificateValidator = session.AppServer as IRemoteCertificateValidator;

            if (clientCertificateValidator != null)
                return clientCertificateValidator.Validate(session, sender, certificate, chain, sslPolicyErrors);

            //Return the native validation result
            return sslPolicyErrors == SslPolicyErrors.None;
        }

        private IAsyncResult BeginInitStream(AsyncCallback asyncCallback)
        {
            IAsyncResult result = null;

            var certConfig = AppSession.Config.Certificate;
            var secureProtocol = SecureProtocol;

            switch (secureProtocol)
            {
                case (SslProtocols.None):
                    m_Stream = new NetworkStream(Client);
                    break;
                case (SslProtocols.Default):
                case (SslProtocols.Tls):
                case (SslProtocols.Ssl3):
                    SslStream sslStream = CreateSslStream(certConfig);
                    result = sslStream.BeginAuthenticateAsServer(AppSession.AppServer.Certificate, certConfig.ClientCertificateRequired, SslProtocols.Default, false, asyncCallback, sslStream);
                    break;
                case (SslProtocols.Ssl2):
                    SslStream ssl2Stream = CreateSslStream(certConfig);
                    result = ssl2Stream.BeginAuthenticateAsServer(AppSession.AppServer.Certificate, certConfig.ClientCertificateRequired, SslProtocols.Ssl2, false, asyncCallback, ssl2Stream);
                    break;
                default:
                    var unknownSslStream = CreateSslStream(certConfig);
                    result = unknownSslStream.BeginAuthenticateAsServer(AppSession.AppServer.Certificate, certConfig.ClientCertificateRequired, secureProtocol, false, asyncCallback, unknownSslStream);
                    break;
            }

            return result;
        }

        private void OnBeginInitStreamOnSessionConnected(IAsyncResult result)
        {
            OnBeginInitStream(result, true);
        }

        private void OnBeginInitStream(IAsyncResult result)
        {
            OnBeginInitStream(result, false);
        }

        private void OnBeginInitStream(IAsyncResult result, bool connect)
        {
            var sslStream = result.AsyncState as SslStream;

            try
            {
                sslStream.EndAuthenticateAsServer(result);
            }
            catch (IOException exc)
            {
                LogError(exc);

                if (!connect)//Session was already registered
                    this.Close(CloseReason.SocketError);

                OnNegotiateCompleted(false);
                return;
            }
            catch (Exception e)
            {
                LogError(e);

                if (!connect)//Session was already registered
                    this.Close(CloseReason.SocketError);

                OnNegotiateCompleted(false);
                return;
            }

            m_Stream = sslStream;
            OnNegotiateCompleted(true);
        }

        protected override void SendSync(SendingQueue queue)
        {
            try
            {
                for (var i = 0; i < queue.Count; i++)
                {
                    var item = queue[i];
                    m_Stream.Write(item.Array, item.Offset, item.Count);
                }

                OnSendingCompleted(queue);
            }
            catch (Exception e)
            {
                LogError(e);
                OnSendError(queue, CloseReason.SocketError);
                return;
            }
        }

        protected override void OnSendingCompleted(SendingQueue queue)
        {
            try
            {
                m_Stream.Flush();
            }
            catch (Exception e)
            {
                LogError(e);
                OnSendError(queue, CloseReason.SocketError);
                return;
            }

            base.OnSendingCompleted(queue);
        }

        protected override void SendAsync(SendingQueue queue)
        {
            try
            {
                var item = queue[queue.Position];
                m_Stream.BeginWrite(item.Array, item.Offset, item.Count, OnEndWrite, queue);
            }
            catch (Exception e)
            {
                LogError(e);
                OnSendError(queue, CloseReason.SocketError);
            }
        }

        private void OnEndWrite(IAsyncResult result)
        {
            var queue = result.AsyncState as SendingQueue;

            try
            {
                m_Stream.EndWrite(result);
            }
            catch (Exception e)
            {
                LogError(e);
                OnSendError(queue, CloseReason.SocketError);
                return;
            }
            
            var nextPos = queue.Position + 1;

            //Has more data to send
            if (nextPos < queue.Count)
            {
                queue.Position = nextPos;
                SendAsync(queue);
                return;
            }

            OnSendingCompleted(queue);
        }

        public override void ApplySecureProtocol()
        {
            var asyncResult = BeginInitStream(OnBeginInitStream);

            if (asyncResult != null)
                asyncResult.AsyncWaitHandle.WaitOne();
        }

        public SocketAsyncEventArgsProxy SocketAsyncProxy { get; private set; }

        ILog ILoggerProvider.Logger
        {
            get { return AppSession.Logger; }
        }

        public override int OrigReceiveOffset
        {
            get { return SocketAsyncProxy.OrigOffset; }
        }

        private bool m_NegotiateResult = false;

        void INegotiateSocketSession.Negotiate()
        {
            IAsyncResult asyncResult;

            try
            {
                asyncResult = BeginInitStream(OnBeginInitStreamOnSessionConnected);
            }
            catch (Exception e)
            {
                LogError(e);
                OnNegotiateCompleted(false);
                return;
            }

            if (asyncResult == null)
            {
                OnNegotiateCompleted(true);
                return;
            }
        }

        bool INegotiateSocketSession.Result
        {
            get { return m_NegotiateResult; }
        }

        private EventHandler m_NegotiateCompleted;

        event EventHandler INegotiateSocketSession.NegotiateCompleted
        {
            add { m_NegotiateCompleted += value; }
            remove { m_NegotiateCompleted -= value; }
        }

        private void OnNegotiateCompleted(bool negotiateResult)
        {
            m_NegotiateResult = negotiateResult;

            //One time event handler
            var handler = Interlocked.Exchange<EventHandler>(ref m_NegotiateCompleted, null);

            if (handler == null)
                return;

            handler(this, EventArgs.Empty);
        }
    }
View Code

 

SuperSocket.SocketEngine.AsyncStreamSocketSession 《 SuperSocket.SocketEngine.AsyncSocketServer 《 SocketServerFactory 《 AppServerBase

在SuperSocket.SocketBase.AppServerBase类里
 private bool SetupSocketServer()
        {
            try
            {
                m_SocketServer = m_SocketServerFactory.CreateSocketServer<TRequestInfo>(this, m_Listeners, Config);
                return m_SocketServer != null;
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                    Logger.Error(e);

                return false;
            }
        }

 



#region IActiveConnector

        /// <summary>
        /// Connect the remote endpoint actively.
        /// </summary>
        /// <param name="targetEndPoint">The target end point.</param>
        /// <param name="localEndPoint">The local end point.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">This server cannot support active connect.</exception>
        Task<ActiveConnectResult> IActiveConnector.ActiveConnect(EndPoint targetEndPoint, EndPoint localEndPoint)
        {
            var activeConnector = m_SocketServer as IActiveConnector;

            if (activeConnector == null)
                throw new Exception("This server cannot support active connect.");

            return activeConnector.ActiveConnect(targetEndPoint, localEndPoint);
        }

        /// <summary>
        /// Connect the remote endpoint actively.
        /// </summary>
        /// <param name="targetEndPoint">The target end point.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">This server cannot support active connect.</exception>
        Task<ActiveConnectResult> IActiveConnector.ActiveConnect(EndPoint targetEndPoint)
        {
            return ((IActiveConnector)this).ActiveConnect(targetEndPoint, null);
        }

        #endregion IActiveConnector

 private bool SetupSocketServer()
        {
            try
            {
                m_SocketServer = m_SocketServerFactory.CreateSocketServer<TRequestInfo>(this, m_Listeners, Config);
                return m_SocketServer != null;
            }
            catch (Exception e)
            {
                if (Logger.IsErrorEnabled)
                    Logger.Error(e);

                return false;
            }
        }
private void SetupBasic(IRootConfig rootConfig, IServerConfig config, ISocketServerFactory socketServerFactory)
        {
            if (rootConfig == null)
                throw new ArgumentNullException("rootConfig");

            RootConfig = rootConfig;

            if (config == null)
                throw new ArgumentNullException("config");

            if (!string.IsNullOrEmpty(config.Name))
                m_Name = config.Name;
            else
                m_Name = string.Format("{0}-{1}", this.GetType().Name, Math.Abs(this.GetHashCode()));

            Config = config;

            SetDefaultCulture(rootConfig, config);

            if (!m_ThreadPoolConfigured)
            {
                if (!TheadPoolEx.ResetThreadPool(rootConfig.MaxWorkingThreads >= 0 ? rootConfig.MaxWorkingThreads : new Nullable<int>(),
                        rootConfig.MaxCompletionPortThreads >= 0 ? rootConfig.MaxCompletionPortThreads : new Nullable<int>(),
                        rootConfig.MinWorkingThreads >= 0 ? rootConfig.MinWorkingThreads : new Nullable<int>(),
                        rootConfig.MinCompletionPortThreads >= 0 ? rootConfig.MinCompletionPortThreads : new Nullable<int>()))
                {
                    throw new Exception("Failed to configure thread pool!");
                }

                m_ThreadPoolConfigured = true;
            }

            if (socketServerFactory == null)
            {
                var socketServerFactoryType =
                    Type.GetType("SuperSocket.SocketEngine.SocketServerFactory, SuperSocket.SocketEngine", true);

                socketServerFactory = (ISocketServerFactory)Activator.CreateInstance(socketServerFactoryType);
            }

            m_SocketServerFactory = socketServerFactory;

            //Read text encoding from the configuration
            if (!string.IsNullOrEmpty(config.TextEncoding))
                TextEncoding = Encoding.GetEncoding(config.TextEncoding);
            else
                TextEncoding = new ASCIIEncoding();
        }

 

 

请天就写到这里了,看到这里你可以结合源码应该能知道SuperSocket是如何发送数据和接收数据。当前接收的数据还是停留在
TCP UDP层面上。下一稿将说明应用动,协议和命令是怎样工作。





 

posted @ 2017-11-15 11:44  玖彩技术团队  阅读(7473)  评论(2编辑  收藏  举报
以上只是个人想法和实践经验,如果有文字错误和语法错误,请加以指点! QQ:247039968 emil:wujc@younger.com 无论是美女的歌声,还是鬣狗的狂吠,无论是鳄鱼的眼泪,还是恶狼的嚎叫,都不会使我动摇