SuperSocket服务端源代码逻辑解析

82 篇文章 3 订阅

SuperSocket服务端默认是以 "\r\n" (回车换行0x0D0A)作为终止符(TerminatorReceiveFilter),接收默认最多处理1024个字节【DefaultMaxRequestLength=1024】。如果一次发送超过1024的字节【发送数据中无 "\r\n"】,将抛出ProtocolError异常,并将非法的客户端连接关闭。

接收的结果StringRequestInfo对象由Key和Body通过空格字符拼接而成。

如果Body为空,则接收的实际结果就是 Key。

如果Body不为空,则接收的实际结果是 Key+" "+Body。

新建窗体应用程序TestServer,重命名窗体名为FormServer。窗体设计如下:

添加对类库。SuperSocket.Common,SuperSocket.SocketBase,SuperSocket.SocketEngine,Log4Net 四个类库的引用。

测试源程序:

using SuperSocket.SocketBase;
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;

namespace TestServer
{
    public partial class FormServer : Form
    {
        AppServer appServer = new AppServer();
        public FormServer()
        {
            InitializeComponent();
        }

        private void FormServer_Load(object sender, EventArgs e)
        {
            ServerConfig serverConfig = new ServerConfig()
            {
                Ip = "127.0.0.1",
                Port = int.Parse(txtPort.Text),
                TextEncoding = "GBK",
                MaxConnectionNumber = ServerConfig.DefaultMaxConnectionNumber,
                Mode = SocketMode.Tcp,
                MaxRequestLength = ServerConfig.DefaultMaxRequestLength,
                KeepAliveTime = ServerConfig.DefaultKeepAliveTime,
                KeepAliveInterval = ServerConfig.DefaultKeepAliveInterval,
                ListenBacklog = ServerConfig.DefaultListenBacklog,
                ReceiveBufferSize = ServerConfig.DefaultReceiveBufferSize,
                SendTimeOut = ServerConfig.DefaultSendTimeout
            };

            if (!appServer.Setup(serverConfig))
            {
                MessageBox.Show("开启监听端口失败");
                return;
            }

            if (!appServer.Start())
            {
                MessageBox.Show("服务器开启监听失败");
                return;
            }

            DisplayContent(string.Format("服务器启动监听成功,服务器IP:{0},端口:{1}...", appServer.Config.Ip, appServer.Config.Port));

            //客户端连接事件
            appServer.NewSessionConnected += AppServer_NewSessionConnected;
            //接收事件
            appServer.NewRequestReceived += AppServer_NewRequestReceived; 
            //客户端已关闭事件
            appServer.SessionClosed += AppServer_SessionClosed; 
        }

        private void AppServer_SessionClosed(AppSession session, SuperSocket.SocketBase.CloseReason value)
        {
            string sessionIp = string.Format("{0}:{1}", session.RemoteEndPoint.Address, session.RemoteEndPoint.Port);
            DisplayContent(string.Format("客户端已关闭:{0},端口:{1},原因:{2}", session.RemoteEndPoint.Address, session.RemoteEndPoint.Port, value));
        }

        private void AppServer_NewRequestReceived(AppSession session, SuperSocket.SocketBase.Protocol.StringRequestInfo requestInfo)
        {
            string body = requestInfo.Body;
            string charSet = session.Charset.BodyName;
            DateTime dt = session.LastActiveTime;
            string key = requestInfo.Key;//session.CurrentCommand;
            string sessionIp = string.Format("{0}:{1}", session.RemoteEndPoint.Address, session.RemoteEndPoint.Port);
            StringBuilder sb = new StringBuilder(sessionIp + ":\n接收内容:");
            string content = key;            
            if (body.Length > 0)
            {
                content = key + (" " + body);
            }
            sb.Append(content);
            sb.Append("    \n发送时间:" + dt.ToString("yyyy-MM-dd HH:mm:ss"));
            sb.Append("    \n字符编码:" + charSet);
            DisplayContent(sb.ToString());
        }

        private void AppServer_NewSessionConnected(AppSession session)
        {
            string sessionIp = string.Format("{0}:{1}", session.RemoteEndPoint.Address, session.RemoteEndPoint.Port);
            DisplayContent(string.Format("客户端已连接:{0},虚拟端口:{1}", session.RemoteEndPoint.Address, session.RemoteEndPoint.Port));
        }

        /// <summary>
        /// 异步显示内容
        /// </summary>
        /// <param name="addContent"></param>
        private void DisplayContent(string addContent)
        {
            if (this.InvokeRequired)
            {
                Action<string> actionUpd = DisplayContentEx;
                actionUpd.BeginInvoke(addContent, null, null);
            }
            else
            {
                DisplayContentEx(addContent);
            }
        }

        public void DisplayContentEx(string addContent)
        {
            this.Invoke(new MethodInvoker(() =>
            {
                if (rtxtDisplay.TextLength >= 10240)
                {
                    rtxtDisplay.Clear();
                }
                rtxtDisplay.AppendText(addContent + "\n");
                rtxtDisplay.ScrollToCaret();
            }));
        }
    }
}


程序运行如图

【新开一个客户端,建立连接,并发送】

具体介绍下面两个方法AppServer.Setup() 与 AppServer.Start()

一、方法appServer.Setup(serverConfig),基本配置设置。

最终的本质就是 实例化类 new AsyncSocketServer(appServer, listeners)

1.实例化类 SuperSocket.SocketEngine.SocketServerFactory.

如果不指定编码格式,将默认为ASCII

         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();

2.设置监听配置:设置服务端的IP和端口

                if (config.Port > 0)
                {
                    listeners.Add(new ListenerInfo
                    {
                        EndPoint = new IPEndPoint(ParseIPAddress(config.Ip), config.Port),
                        BackLog = config.ListenBacklog,
                        Security = BasicSecurity
                    });
                }

3.设置接收过滤器:

return new CommandLineReceiveFilterFactory(TextEncoding);

=>new CommandLineReceiveFilterFactory(encoding, new BasicRequestInfoParser());

=>new TerminatorReceiveFilterFactory("\r\n",encoding, new BasicRequestInfoParser());

//注意:这里指定 终止符为 回车换行。

4.创建socket服务,最终目的就是实例化类:AsyncSocketServer

CreateSocketServer<TRequestInfo>(IAppServer appServer, ListenerInfo[] listeners, IServerConfig config)

=> case(SocketMode.Tcp):
                    return new AsyncSocketServer(appServer, listeners);

 

二、方法:appServer.Start()。启动一个服务端实例并监听接受Accept客户端连接

1.开始实例化【最大连接数】个异步socket代理对象

=>AsyncSocketServer 对象m_SocketServer.Start()

实例化最大连接数【MaxConnectionNumber】个异步socket代理对象:SocketAsyncEventArgsProxy

new SocketAsyncEventArgsProxy(SocketAsyncEventArgs socketEventArgs,true);

并订阅 【完成异步操作】的事件 Completed

public SocketAsyncEventArgsProxy(SocketAsyncEventArgs socketEventArgs, bool isRecyclable)
        {
            SocketEventArgs = socketEventArgs;
            OrigOffset = socketEventArgs.Offset;
            SocketEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(SocketEventArgs_Completed);
            IsRecyclable = isRecyclable;
        }

        static void SocketEventArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            var socketSession = e.UserToken as IAsyncSocketSession;

            if (socketSession == null)
                return;

            if (e.LastOperation == SocketAsyncOperation.Receive)
            {
                socketSession.AsyncRun(() => socketSession.ProcessReceive(e));
            }

            else
            {
                throw new ArgumentException("The last operation completed on the socket was not a receive");
            }
        } 

 

2.执行父类的启动监听:抽象类SocketServerBase的Start()方法

内部类 TcpAsyncSocketListener的Start()方法

var listener => return new TcpAsyncSocketListener(listenerInfo);

                var listener = CreateListener(ListenerInfos[i]);
                listener.Error += new ErrorHandler(OnListenerError);
                listener.Stopped += new EventHandler(OnListenerStopped);

                //当接受Accept一个客户端时触发
                listener.NewClientAccepted += new NewClientAcceptHandler(OnNewClientAccepted);

3.执行异步监听类TcpAsyncSocketListener的Start(Config)方法,这才是真正的启用监听。

public override bool Start(IServerConfig config)
        {
            m_ListenSocket = new Socket(this.Info.EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                m_ListenSocket.Bind(this.Info.EndPoint);
                m_ListenSocket.Listen(m_ListenBackLog);

                m_ListenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                m_ListenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);

                SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs();
                m_AcceptSAE = acceptEventArg;
                acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(acceptEventArg_Completed);

                if (!m_ListenSocket.AcceptAsync(acceptEventArg))
                    ProcessAccept(acceptEventArg);

                return true;

            }
            catch (Exception e)
            {
                OnError(e);
                return false;
            }
        }

4.等待一个新的客户端连接:

开始一个异步操作以接受传入的连接尝试。

m_ListenSocket.AcceptAsync(acceptEventArg)

三、当一个客户端连接成功时,会自动触发完成事件:

TcpAsyncSocketListener类的 void ProcessAccept(SocketAsyncEventArgs e)

生成一个用于发送和接收的Socket对象

socket = e.AcceptSocket;

           //本次客户端已连接,同时开启:等待下一个新的客户端连接

           e.AcceptSocket = null;

            bool willRaiseEvent = false;

            try
            {
                willRaiseEvent = m_ListenSocket.AcceptAsync(e);//引发接受下一个新的客户端连接尝试
            }

if (socket != null)
                OnNewClientAccepted(socket, null);

自动触发事件:AsyncSocketServer类的

protected override void OnNewClientAccepted(ISocketListener listener, Socket client, object state)

即执行private IAppSession ProcessNewClient(Socket client, SslProtocols security)

相关代码:

            if (security == SslProtocols.None)
                socketSession = new AsyncSocketSession(client, socketEventArgsProxy);
            else
                socketSession = new AsyncStreamSocketSession(client, security, socketEventArgsProxy);

创建Session用于发送和接收

protected IAppSession CreateSession(Socket client, ISocketSession session)

实例化并初始化 new AppSession()并Initialize()

public virtual void Initialize(IAppServer<TAppSession, TRequestInfo> appServer, ISocketSession socketSession)
        {
            var castedAppServer = (AppServerBase<TAppSession, TRequestInfo>)appServer;
            AppServer = castedAppServer;
            Charset = castedAppServer.TextEncoding;
            SocketSession = socketSession;
            SessionID = socketSession.SessionID;
            m_Connected = true;
            m_ReceiveFilter = castedAppServer.ReceiveFilterFactory.CreateFilter(appServer, this, socketSession.RemoteEndPoint);

            var filterInitializer = m_ReceiveFilter as IReceiveFilterInitializer;
            if (filterInitializer != null)
                filterInitializer.Initialize(castedAppServer, this);

            socketSession.Initialize(this);

            OnInit();
        }

为 异步会话.AsyncSocketSession绑定关闭事件 socketSession.Closed += SessionClosed;

然后异步AsyncSocketServer的注册会话方法。RegisterSession(IAppSession appSession)

然后AppServerBase的RegisterSession

触发新的会话连接事件AppServerBase的 OnNewSessionConnected(appSession);

NewSessionConnected.BeginInvoke(session, OnNewSessionConnectedCallback, handler);

然后 开始执行任务:

AppServer.AsyncRun(() => socketSession.Start());

即 Task.Factory.StartNew(task, taskOption).ContinueWith(...)

启动的任务 即  AsyncSocketSession的Start()方法

public override void Start()
        {
            StartReceive(SocketAsyncProxy.SocketEventArgs);

            if (!m_IsReset)
                StartSession();
        }

AsyncSocketSession的StartReceive方法

private void StartReceive(SocketAsyncEventArgs e, int offsetDelta)

有个关键的异步接收 :

willRaiseEvent = Client.ReceiveAsync(e);

四、当客户端向服务端发送消息时,触发完成事件

本质是为事件NewRequestReceived的参数StringRequestInfo对象赋值后,触发事件NewRequestReceived。

如果超过了最大请求字节数,服务端将这个的客户端连接关闭,并提示协议错误【ProtocolError】,此时并不会触发事件NewRequestReceived

1.当有新的发送文本到达服务端时,会触发 SocketAsyncEventArgsProxy的完成事件

SocketEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(SocketEventArgs_Completed);

也就是任务:处理接收 ProcessReceive:

           if (e.LastOperation == SocketAsyncOperation.Receive)
            {
                socketSession.AsyncRun(() => socketSession.ProcessReceive(e));
            }

AsyncSocketSession的ProcessReceive()f方法

public void ProcessReceive(SocketAsyncEventArgs e)

2,执行方法 offsetDelta = this.AppSession.ProcessRequest(e.Buffer, e.Offset, e.BytesTransferred, true);

            其中AppSession的处理请求方法ProcessRequest

3.执行过滤请求方法:FilterRequest

             SuperSocket.SocketBase.Protocol.TerminatorReceiveFilter类的Filter方法

            BasicRequestInfoParser类的ParseRequestInfo方法返回StringRequestInfo对象

           AppSession的FilterRequest 里面判断 如果请求的字节数 超过 最大请求字节数,将关闭客户端连接,返回ProtocolError

           if (currentRequestLength >= maxRequestLength)
            {
                if (Logger.IsErrorEnabled)
                    Logger.Error(this, string.Format("Max request length: {0}, current processed length: {1}", maxRequestLength, currentRequestLength));

                Close(CloseReason.ProtocolError);
                return null;
            }

如果请求字节数 小于 最大请求字节数,将执行 AppServer.ExecuteCommand(this, requestInfo);

也就是触发事件 NewRequestReceived。

 

最后执行异步等待读取下一次数据块,新的异步接收开始了

            //read the next block of data sent from the client
            StartReceive(e, offsetDelta);

 

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值