你好呀~欢迎关注微信公众号:python入门到放弃

AspNetCore中的实时通讯

.NetCore admin 427浏览

实时通讯(SignalR)

实现实时通讯的方式:

  • 1、短轮询(javascript(ajax):setinterval,settimeout)
    优点:简单,易实现
    缺点:并非实时通讯
  • 2、长轮询(流的形式)
    是单工的,不能实现双向。
    实现类似在服务器构建一个死循环,挂起,当监听到数据改变,返回到客户端,客户端收到消息,再次发送请求。即设置更长的超时时间,是一种服务器堵塞的方式
  • 3、server-Sent Event(HTML5协议)
    不是所有的浏览器都支持
    和服务器保持长连接实现。同样他也是单工。
    和长轮询的区别在于,客服端发起连接后,就保持长连接.服务器源源不断的向客户端发送消息。
  • 4、Websocker
    基于Tcp的长连接,是全双工的。
    主流的浏览器全部支持。
    在网页游戏中是应用很多的。

在Core实现实时通讯

一、使用Websocker实现
1、在Startup中使用中间件

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
{
            app.UseDefaultFiles();
            app.UseStaticFiles();
            // 使用中间件
            app.UseWebSockets();
            // 拦截请求
            app.Use(async (context, next) =>
            {
                if (context.Request.Path == "/websocket")
                {
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        // 接收该WebScoker
                        WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();
                        await ScoketHander.GetMessage(socket);
                    }
                    else
                    {
                        await context.Response.WriteAsync("不是ws/wss协议链接");
                    }
                }
                else
                {
                    await next();
                }
            });
            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }

ScoketHander类中的代码如下:

public static async Task GetMessage(WebSocket socket)
        
{
            byte[] buffer = new byte[1024];
            // 接收流数据
            var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            while (!result.CloseStatus.HasValue)
            {
                // 把字节转变为string
                string messgae = Encoding.Default.GetString(buffer).Replace("\0","");
                messgae += $" -- {DateTime.Now}";
                // 把string转变为字节
                byte[] responsebyte = Encoding.Default.GetBytes(messgae);
                await socket.SendAsync(new ArraySegment<byte>(responsebyte), result.MessageType, result.EndOfMessage, CancellationToken.None);
                result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
            await socket.CloseAsync(result.CloseStatus.Value,result.CloseStatusDescription, CancellationToken.None); 
        }

前端代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <div>
        <input type="button" value="Conn" id="ConnButton" />
        <hr />
        Message: <input type="text" id="message" />
        <input type="button" value="Send" id="SendButton" />
    </div>
    <ul id="MessageList">
    </ul>
</body>
</html>
<script src="jquery.min.js"></script>
<script>
    $(function ({
        var ws;
        if (SupportWebSocket()) {
            $("#ConnButton").click(function ({
                // 打开一个 web socket
                ws = new WebSocket(GetSocketUrl("/websocket"));
                ws.onopen = function ({
                    // 连接上触发
                    console.log("连接完成,可以发送消息了。");
                }
                // 接受消息
                ws.onmessage = function (evt{
                    var received_msg = evt.data;
                    var li = document.createElement("li");
                    li.textContent = received_msg;
                    $("#MessageList").append(li);
                };
            });
            // 发送消息
            $("#SendButton").click(function ({
                var msg = $("#message").val();
                ws.send(msg);
            });

        } else {
            console.log("该浏览器不支持WebSocket");
        }
        // 是否支持WebSocket
        function SupportWebSocket({
            return "WebSocket" in window;
        }
        // 获取Url
        function GetSocketUrl(url{
            // 获取架构scheme https|http
            var scheme = document.location.protocol == "https:" ? "wss" : "ws";
            // 获取端口
            var port = document.location.port ? (":" + document.location.port) : "";
            // 组合
            //var websockerurl = scheme + "://" + document.location.hostname + port + "/websocket";
            var websockerurl = scheme + "://" + document.location.hostname + port + url;
            return websockerurl;
        }
    });
</script>

二、使用SignalR框架
在Core一般推荐使用SignalR框架,SignalR是一个开源库,他简化了Web实时通讯的开发难度。
它是集成Websocker,server-Sent Event,长轮询一体的一个开源框架。足够覆盖所有的浏览器。根据浏览器的不同自动改变使用的方式。开发者无需关心。这里需要提出Hub集线器的概念。
Hub集线器他是负责客户端和服务端的通讯,负责通讯方式的切换,二进制和Json协议序列化。
实现如下:
在Startup中注入服务并且添加中间件:

public void ConfigureServices(IServiceCollection services)
        
{
            services.AddControllersWithViews();
            services.AddSignalR();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
{
            app.UseDefaultFiles();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                // 使用路由拦截请求
                endpoints.MapHub<ChatHub>("/Chat");
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

ChatHub中代码如下:

public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        
{
            await Clients.All.SendAsync("ReceiveMessage",user,$"{message}  {DateTime.Now}");
        }
    }

前端Html代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <div>
        UserName:<input type="text" id="username" />
        <br />
        Message: <input type="text" id="message" />
        <input type="button" value="Send" id="SendButton" />
    </div>
    <ul id="MessageList">
    </ul>
</body>
</html>
<script src="lib/jquery/dist/jquery.js"></script>
<script src="lib/jquery/signalr.js"></script>
<script>
    var connection = new signalR.HubConnectionBuilder().withUrl("/chat").build();
    connection.on("ReceiveMessage"function (user, message{
        var msg = user + ":" + message;
        var li = document.createElement("li");
        li.textContent = msg;
        $("#MessageList").append(li);
    })
    connection.start().catch(function (ex{
        console.log(ex);
    });
    $("#SendButton").click(function ({
        var user = $("#username").val();
        var msg = $("#message").val();
        connection.invoke("SendMessage", user, msg);
    });
</script>

signalr.js包安装的方式:
需要安装Node.js,在项目目录创建package.json文件:

{
  "dependencies": {
    "@aspnet/signalr""3.0.0-preview6.19307.2"
  }
}

转载请注明: 十三 » AspNetCore中的实时通讯

喜欢 (0) or 分享 ( 0)