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, , 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()) //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 = ; 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 = ;
- try
- {
- thisRead = stream.EndRead(result);
- }
- catch (Exception e)
- {
- LogError(e);
- OnReceiveTerminated(CloseReason.SocketError);
- return;
- }
- if (thisRead <= )
- {
- 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 < || 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 = ; 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 + ;
- //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);
- }
- }
- 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 >= ? rootConfig.MaxWorkingThreads : new Nullable<int>(),
- rootConfig.MaxCompletionPortThreads >= ? rootConfig.MaxCompletionPortThreads : new Nullable<int>(),
- rootConfig.MinWorkingThreads >= ? rootConfig.MinWorkingThreads : new Nullable<int>(),
- rootConfig.MinCompletionPortThreads >= ? 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层面上。下一稿将说明应用动,协议和命令是怎样工作。
SupperSocket深入浅出(一)的更多相关文章
- SupperSocket深入浅出(二)
如果还没有看SuperStock深入浅出(一) ,请先看 这一章,主要说下命令是如果运行的.刚开始的时候会发现拷别人的代码命令是可以运行的,在修改的过程中突然发现命令无效了? 这里什么原因?,我先把代 ...
- SupperSocket深入浅出
这篇文章出要是SuperSocket底层如何接收数据 Process(ArraySegment<byte> segment) 获取加载数据(直到数据全部接收后返回) namespace S ...
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 【深入浅出jQuery】源码浅析2--奇技淫巧
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 深入浅出Struts2+Spring+Hibernate框架
一.深入浅出Struts2 什么是Struts2? struts2是一种基于MVC的轻量级的WEB应用框架.有了这个框架我们就可以在这个框架的基础上做起,这样就大大的提高了我们的开发效率和质量,为公司 ...
- DOM 事件深入浅出(二)
在DOM事件深入浅出(一)中,我主要给大家讲解了不同DOM级别下的事件处理程序,同时介绍了事件冒泡和捕获的触发原理和方法.本文将继续介绍DOM事件中的知识点,主要侧重于DOM事件中Event对象的属性 ...
- DOM 事件深入浅出(一)
在项目开发时,我们时常需要考虑用户在使用产品时产生的各种各样的交互事件,比如鼠标点击事件.敲击键盘事件等.这样的事件行为都是前端DOM事件的组成部分,不同的DOM事件会有不同的触发条件和触发效果.本文 ...
- 深入浅出node(2) 模块机制
这部分主要总结深入浅出Node.js的第二章 一)CommonJs 1.1CommonJs模块定义 二)Node的模块实现 2.1模块分类 2.2 路径分析和文件定位 2.2.1 路径分析 2.2.2 ...
- IOS 网络-深入浅出(一 )-> 三方SDWebImage
首要我们以最为常用的UIImageView为例介绍实现原理: 1)UIImageView+WebCache: setImageWithURL:placeholderImage:options: 先显 ...
随机推荐
- Debian下Cannot set LC_CTYPE to default locale: No such file or directory解决方法
把语言环境变量改为英文 将Ubuntu系统语言环境改为英文的en_US.UTF-8 查看当前系统语言环境 locale 编辑配置文件,将zh_US.UTF-8改为en_US.UTF-8,zh改为en ...
- BZOJ1563:[NOI2009]诗人小G(决策单调性DP)
Description Input Output 对于每组数据,若最小的不协调度不超过1018,则第一行一个数表示不协调度若最小的不协调度超过1018,则输出"Too hard to arr ...
- 【[HEOI2016/TJOI2016]字符串】
码农题啊 上来先无脑一个\(SA\)的板子,求出\(SA\)和\(het\)数组 我们只需要从\(sa[i]\in[a,b]\)的所有\(i\)中找到一个\(i\)使得\(sa[i]\)和\(rk[c ...
- PHP面试系列 之框架(二)---- 常见框架的特性
题:PHP框架有哪些,你用过哪些?各自的优缺点是什么? 考点: (1)PHP框架的差异和优缺点 1.Yaf框架 使用PHP扩展的形式写的一个PHP框架,也就是以C语言为底层编写的,性能上要比PHP代码 ...
- AWR报告分析
AWR报告分析 awr报告是oracle 10g下提供的一种性能收集和分析工具,它能提供一个时间段内整个系统资源使用情况的报告,通过这个报告,我们就可以了解一个系统的整个运行情况,这就像一个人全面的体 ...
- 微服务之配置中心ConfigKeeper
在微服务架构中,配置中心是必不可少的基础服务.ConfigKeeper已开源,本文将深度分析配置中心的核心内容,错过「Spring Cloud中国社区北京沙龙-2018.10.28 」的同学将从本篇文 ...
- eclipse中svn插件装好后出现"位置错误"的处理
错误现象: 验证位置时发生错误:"org.apache.subversion.javahl.ClientException:svn:E210004: Number is larger tha ...
- oracle 11G dataguard 恢复
检查主备机的sys 密码是否一致,忘记密码可以修改,同步 .alter user sys identified by xxx: orapwd file=oraxxx.ora password=admi ...
- 如何设计处优秀的Restful API
只知道遵规循矩的程序员是假程序员,任何技术都是不断发明创造改进的. 如何设计处优秀的Restful API? 盲目跟风,设计糟糕的Resful API = 浪费时间 ! 不啰嗦,直接进入技术主题: ...
- ThinkPHP微信扫码支付接口
最近折腾微信扫码支付,看了微信官方文档,找了很多网页,发现和文档/demo不匹配,现在自己算是弄出来了(文件名称有所更改),贴出来分享一下 一.将有用的官方lib文件和使用的相关文件放置到vendor ...