.net core 和 WPF 开发升讯威在线客服系统:使用 WebSocket 实现访客端通信

本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程。本产品已经成熟稳定并投入商用。
请访问:https://kf.shengxunwei.com


文章目录列表请点击这里


对于在线客服与营销系统,访客端是指浏览网站的互联网用户,或是通过APP、微信等内嵌聊天页面与后台客服交流的用户,在本篇文章中,我将详细介绍如何在 .net core 环境下使用 WebSocket 技术实现访客在网页上与服务器进行通信。

这里存在几个技术难点需要注意:

  • 聊天界面要能无缝嵌入客户的目标网站,对原网站不能有任何影响。
  • 访客可以通过网站右下角的浮动框,一边聊天一边浏览网站,网页的跳转、刷星都不能中断聊天。
  • 需要考虑手机端聊天页面连接不稳定的情况,要能在APP或浏览器切到手机后台失去连接时,对聊天状态和信息进行保持。

访客端实现的效果:

访客端在手机上的效果:

后台客服的实现效果:


在 asp.net core 中配置中间件

首先我们要在 Startup.cs 中,启用 WebSocket 中间件:

var webSocketOptions = new WebSocketOptions() 
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

可配置以下设置:

  • KeepAliveInterval - 向客户端发送“ping”帧的频率,以确保代理保持连接处于打开状态。 默认值为 2 分钟。
  • ReceiveBufferSize - 用于接收数据的缓冲区的大小。 高级用户可能需要对其进行更改,以便根据数据大小调整性能。 默认值为 4 KB。
  • AllowedOrigins - 用于 WebSocket 请求的允许的 Origin 标头值列表。 默认情况下,允许使用所有源。

接收访客端的请求

在请求生命周期后期(例如在 Configure 方法或操作方法的后期),检查它是否是 WebSocket 请求并接受 WebSocket 请求。

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
            {
                await Echo(context, webSocket);
            }
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }
    else
    {
        await next();
    }

});

在请求期间对 Task 执行 await,如下面的示例所示:

app.Use(async (context, next) =>
{
    using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
    {
        var socketFinishedTcs = new TaskCompletionSource<object>();

        BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

        await socketFinishedTcs.Task;
    }
});

如果从操作方法返回过快,则还可能发生 WebSocket 关闭异常。 接受操作方法中的套接字时,需要用该套接字的代码完成运行,然后再从操作方法返回。

收发访客端消息

AcceptWebSocketAsync 方法将 TCP 连接升级到 WebSocket 连接,并提供 WebSocket 对象。 使用 WebSocket 对象发送和接收消息。
之前显示的接受 WebSocket 请求的代码将 WebSocket 对象传递给 Echo 方法。 代码接收消息并立即发回相同的消息。 循环发送和接收消息,直到客户端关闭连接:

private async Task Echo(HttpContext context, WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}

如果在开始循环之前接受 WebSocket 连接,中间件管道会结束。 关闭套接字后,管道展开。 即接受 WebSocket 时,请求停止在管道中推进。 循环结束且套接字关闭时,请求继续回到管道。

处理访客端连接断开

访客端由于失去连接而断开连接时,不会自动向服务器发送通知。 服务器只有在客户端发送通知时才会收到断开连接消息。
如果客户端并非总是发送消息且不希望仅由于连接进入空闲状态就设置超时,则让客户端使用一个计时器并每隔多少秒发送一条心跳消息。 在服务器上,如果某条消息在上一条消息发出后的多少秒内尚未到达,则终止连接并报告客户端已断开连接。


本文对使用 WebSocket 搭建访客端通信框架进行了简要的介绍,在接下来的文章中,我将具体解构服务端程序的结构和设计、客服端程序的结构和设计,敬请关注。


请访问:https://kf.shengxunwei.com


联系QQ: 279060597
联系E-mail:C5118@outlook.com

推荐您关注我的微信订阅号,在我更新文章或产品信息时会进行推送。

posted @ 2021-01-15 10:39  sheng.chao  阅读(2025)  评论(38编辑  收藏