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: 先显 ...
随机推荐
- 深入理解php中的ini配置(2)
继续接着上一篇写. 运行时改变配置 在前一篇中曾经谈到,ini_set函数可以在php执行的过程中,动态修改php的部分配置.注意,仅仅是部分,并非所有的配置都可以动态修改.关于ini配置的可修改性, ...
- UVa 1639 - Candy(数学期望 + 精度处理)
链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- backtype.storm.generated.InvalidTopologyException:null问题的解决
程序启动报错:backtype.storm.generated.InvalidTopologyException:null 问题解决方法: 这个错误一般都是没有定义输出列造成的 检查Spout和Bol ...
- Java中的集合框架-Collections和Arrays
上一篇<Java中的集合框架-Map>把集合框架中的键值对容器Map中常用的知识记录了一下,本节记录一下集合框架的两个工具类Collections和Arrays 一,Collections ...
- C++程序设计入门(上) 函数学习
局部变量和全局变量的访问: 全局变量的作用域时全局,局部变量的作用域是局部,若全局和局部的变量名相同的话,局部变量的改变不会引起全局变量的改变#include<iostream> int ...
- mysql/mariadb学习记录——limit
在mysql/mariadb 中可以用limit来限制查询的条数.例子如下: 1.limit后加一个参数 limit n: //选中查询所有结果中的前两条记录并返回 mysql> ; +---- ...
- 解决mysql远程登录
MySQL不允许远程登录,所以远程登录失败了,解决方法如下: 在装有MySQL的机器上登录MySQL mysql -u root -p密码 执行use mysql; 执行update user set ...
- html5手机浏览器启动微信客户端支付实例
html5手机浏览器启动微信客户端支付实例,外部浏览器html5微信支付技术,如何在手机浏览器微信支付,在微信客户端外的移动端网页使用微信支付 首先在微信支付官网https://pay.weixin. ...
- 常见的移动端H5页面开发遇到的坑和解决办法
转过来,平时看看.虽然还有很多问题至今无解.比如:华为麒麟950的P8和meta打开我们的应用首页经常偶发白屏.!! 1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是 ...
- .NET Core On Liunx环境搭建之MongoDB
伴随着.NET Core的开源,Liunx服务器才是.NET 的未来,公司前几天刚刚上新了一台Liunx服务器,我进行了一下环境的搭建,把经验分享出来. 服务器信息: 服务器用的是阿里云服务器,操作 ...