zoukankan      html  css  js  c++  java
  • 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
    ");
                byte[] bytes = Encoding.ASCII.GetBytes("Welcome
     to SuperSocket
     Telnet Server
    ");
                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
    ";
                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
    ");
                    client.Send(smk.ToArray());  //EasyClient<MyPackageInfo> client
                }
            }
    byte[] b = Encoding.ASCII.GetBytes("ECHO 1 1
    ");
     client.Send(smk.ToArray());  

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


    现在给了大家两个问题?,现在我们来解决问题。
    服务端是如何接收到消息。其它大家可以不要具体体解,因为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层面上。下一稿将说明应用动,协议和命令是怎样工作。





  • 相关阅读:
    Oracle优化器模式不同导致索引失效
    Python补零操作
    正则表达式
    python习题(二)
    Linux常见报错及解决方法(持续更新)
    总结(三)----2020上
    总结二
    总结---持更
    python多线程实现方式,最基础的实现方式模块是什么
    python2和python3区别
  • 原文地址:https://www.cnblogs.com/qq247039968/p/7837869.html
Copyright © 2011-2022 走看看