zoukankan      html  css  js  c++  java
  • SuperSocket 2.0应用2:基于固定头协议的WebSocket服务器

    SuperSocket:GitHubSuperSocket 2.0 中文文档官方WebSocket Server Demo

    本文开发环境:Win10 + VS2019 + .NET 5.0 + SuperSocket 2.0.0-beta.10。

    Gitee:SuperSocketV2FixedHeaderSample

    续接“SuperSocket 2.0应用1:基于固定头协议的Socket服务器”,本文使用SuperSocket 2.0创建基于固定头协议的WebSocket服务器,通过PackageInfo、PackageMapper、IAsyncCommand、WebSocketSession、MiddlewareBase来说明如何构建一个完整的WebSocket服务器。

    1、PackageInfo

    同SocketServer,略。

    2、PackageMapper

    SuperSocke使用PackageMapper将WebSocketServer中的WebSocketPackage转换为自己感兴趣的包类型。通过WebSocketPackage的Map方法,可以将字节数组(package.Data)或字符串(package.Message)转换为目标PackageInfo。

    示例代码如下:

    public class MyPackageConverter : IPackageMapper<WebSocketPackage, MyPackageInfo>
    {
        /// +-------+---+----------------------+
        /// |request| l |                      |
        /// | type  | e |     request body     |
        /// |  (2)  | n |                      |
        /// |       |(2)|                      |
        /// +-------+---+----------------------+
    
        private const int HeaderSize = 4; //Header总长度
    
        // ReSharper disable once UnusedMember.Local
        private const int HeaderLenOffset = 2; //长度offset
    
        public MyPackageInfo Map(WebSocketPackage package)
        {
            var reader = new SequenceReader<byte>(package.Data);
            reader.TryReadBigEndian(out short packageKey);
    
            var body = package.Data.Slice(HeaderSize).ToArray();
            return new MyPackageInfo
            {
                Key = packageKey,
                Body = body
            };
        }
    }

    3、IAsyncCommand

    同SocketServer,略。

    4、WebSocketSession

    这是连接WebSocketServer的会话类,如同AppSession,能够实现向客户端发送消息等功能。

    5、MiddlewareBase

    此为WebSocketServer在.Net Core中的中间件,类似SocketServer的SuperSocketService。通过注入SessionContainer(即使用UseInProcSessionContainer方法,在SuperSocket.SessionContainer包中声明)可以获取已连接的客户端Session列表,一般用于消息推送。

    示例代码如下:

    public class MyMiddleware : MiddlewareBase
    {
        private ISessionContainer _sessionContainer;
        private Task _sendTask;
        private bool _stopped;
    
        public override void Start(IServer server)
        {
            _sessionContainer = server.GetSessionContainer();
            _sendTask = RunAsync(); //模拟消息推送
        }
    
        private async Task RunAsync()
        {
            while (!_stopped)
            {
                var sent = await Push();
    
                if (sent == 0 && !_stopped)
                {
                    await Task.Delay(1000 * 5);
                }
                else
                {
                    await Task.Delay(1000 * 2);
                }
            }
        }
    
        private async ValueTask<int> Push()
        {
            if (_sessionContainer == null)
            {
                return 0;
            }
    
            // about 300 characters
            var line = string.Join("-", Enumerable.Range(0, 10).Select(x => Guid.NewGuid().ToString()));
            var count = 0;
    
            foreach (var s in _sessionContainer.GetSessions<MyWebSocketSession>())
            {
                await s.SendAsync(line);
                count++;
    
                if (_stopped)
                    break;
            }
    
            return count;
        }
    
        public override void Shutdown(IServer server)
        {
            _stopped = true;
            _sendTask.Wait();
    
            foreach (var s in _sessionContainer.GetSessions<MyWebSocketSession>())
            {
                s.PrintStats();
            }
        }
    }

    6、Main示例

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using FixedHeaderSample.WebSocketServer.Commands;
    using FixedHeaderSample.WebSocketServer.Server;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using SuperSocket;
    using SuperSocket.Command;
    using SuperSocket.WebSocket.Server;
    
    namespace FixedHeaderSample.WebSocketServer
    {
        class Program
        {
            static async Task Main()
            {
                var host = WebSocketHostBuilder.Create()
                    //注册WebSocket消息处理器(使用UseCommand注册命令之后该处理器不起作用)
                    .UseWebSocketMessageHandler(async (session, package) =>
                    {
                        Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss fff} Receive message: {package.Message}.");
    
                        //Send message back
                        var message =
                            $@"{DateTime.Now:yyyy-MM-dd HH:mm:ss fff} Hello from WebSocket Server: {package.Message}.";
                        await session.SendAsync(message);
                    })
                    .UseCommand<MyPackageInfo, MyPackageConverter>(commandOptions =>
                    {
                        //注册命令
                        commandOptions.AddCommand<MyCommand>();
                    })
                    .UseSession<MyWebSocketSession>()
                    .UseInProcSessionContainer()
                    .UseMiddleware<MyMiddleware>()
                    .ConfigureAppConfiguration((hostCtx, configApp) =>
                    {
                        configApp.AddInMemoryCollection(new Dictionary<string, string>
                        {
                            {"serverOptions:name", "TestServer"},
                            {"serverOptions:listeners:0:ip", "Any"},
                            {"serverOptions:listeners:0:port", "4041"}
                        });
                    })
                    .ConfigureLogging((hostCtx, loggingBuilder) =>
                    {
                        //添加控制台输出
                        loggingBuilder.AddConsole();
                    })
                    .Build();
                await host.RunAsync();
            }
        }
    }
  • 相关阅读:
    WalkDirFiles
    http://ocpj8.javastudyguide.com/
    打印文件夹中的文件
    apple
    JDBC
    JDBC connection
    Properties-getProperty
    删除目录中指定文件
    spark 之knn算法
    hbase查询基于标准sql规范中间件Phoenix
  • 原文地址:https://www.cnblogs.com/xhubobo/p/15104079.html
Copyright © 2011-2022 走看看