C#使用WebSocket实现聊天室功能

下面是我给您详细讲解“C#使用WebSocket实现聊天室功能”的完整攻略。

什么是WebSocket

WebSocket 是一种网络通信协议,能够在单个 TCP 连接上进行全双工通信。它在客户端和服务器之间建立一个套接字连接,使得数据可以双向传输。

实现聊天室功能的方案

要使用WebSocket实现聊天室功能,需要一个WebSocket的服务器来处理客户端请求和消息的转发。而在C#中,我们可以使用ASP.NET WebSocket库来创建 WebSocket 服务器。

前端实现

在前端页面中,需要使用WebSocket对象建立与服务器的连接,并在连接成功后通过send()方法向服务器发送消息。

var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function () {
  console.log('连接成功');
};

ws.onmessage = function (evt) {
  console.log('收到来自服务器的消息:', evt.data);
};

ws.onerror = function (evt) {
  console.log('连接发生错误:', evt);
};

ws.onclose = function (evt) {
  console.log('连接关闭');
};

function sendMessage() {
  var message = document.getElementById("messageInput").value;
  ws.send(message);
}

服务端实现

在服务端,我们可以使用ASP.NET WebSocket库来实现 WebSocket 服务器。代码如下:

using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

namespace ChatServer
{
    public class WebSocketHandler
    {
        private readonly WebSocket _webSocket;

        public WebSocketHandler(WebSocket webSocket)
        {
            _webSocket = webSocket;
        }

        public async Task Handle()
        {
            var buffer = new byte[1024 * 4];

            while (_webSocket.State == WebSocketState.Open)
            {
                var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

                if (result.MessageType == WebSocketMessageType.Text)
                {
                    // 将接收到的消息发送给所有客户端
                    var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
                    await SendMessageToAllAsync(message);
                }
                else if (result.MessageType == WebSocketMessageType.Close)
                {
                    // 客户端关闭连接时,需要将其移除
                    await RemoveWebSocketAsync(_webSocket);
                    break;
                }
            }
        }
    }

    public class ChatWebSocketMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ConcurrentDictionary<string, WebSocket> _webSockets;

        public ChatWebSocketMiddleware(RequestDelegate next)
        {
            _next = next;
            _webSockets = new ConcurrentDictionary<string, WebSocket>();
        }

        public async Task Invoke(HttpContext context)
        {
            if (!context.WebSockets.IsWebSocketRequest)
            {
                await _next.Invoke(context);
                return;
            }

            var webSocket = await context.WebSockets.AcceptWebSocketAsync();

            _webSockets.TryAdd(webSocket.GetHashCode().ToString(), webSocket);

            var handler = new WebSocketHandler(webSocket);
            await handler.Handle();

            await RemoveWebSocketAsync(webSocket);
        }

        private Task SendMessageToAllAsync(string message)
        {
            var tasks = new List<Task>();

            foreach (var webSocket in _webSockets)
            {
                if (webSocket.Value.State == WebSocketState.Open)
                {
                    var encodedMessage = Encoding.UTF8.GetBytes(message);
                    var buffer = new ArraySegment<byte>(encodedMessage, 0, encodedMessage.Length);

                    tasks.Add(webSocket.Value.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None));
                }
            }

            return Task.WhenAll(tasks);
        }

        private Task RemoveWebSocketAsync(WebSocket webSocket)
        {
            _webSockets.TryRemove(webSocket.GetHashCode().ToString(), out _);

            return Task.CompletedTask;
        }
    }

    public static class ChatWebSocketExtensions
    {
        public static IApplicationBuilder UseChatWebSocketMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware<ChatWebSocketMiddleware>();
        }
    }
}

在上述代码中,我们创建了一个 WebSocketHandler 类来处理每个连接的数据收发,使用 ConcurrentDictionary 来存储所有活动的WebSocket连接。

然后创建 ChatWebSocketMiddleware 类来处理每个 WebSocket 请求,验证请求是否为有效的 WebSocket 连接,并将其添加到活动连接列表中。接着就可以在 Handle() 方法中接收和发送消息。

最后,创建 ChatWebSocketExtensions 类,以便在 Startup.cs 中使用该中间件。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // …

    app.UseChatWebSocketMiddleware();

    // …
}

至此,我们就成功实现了一个简单的聊天室功能。

示例说明

示例一

我们可以创建一个简单的 HTML 页面来测试我们的聊天室功能。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>WebSocket Chat Demo</title>
</head>
<body>
  <div id="messages"></div>
  <input id="messageInput" type="text" />
  <button onclick="sendMessage()">发送</button>
  <script>
    var ws = new WebSocket('ws://localhost:8080');
    ws.onopen = function () {
      console.log('连接成功');
    };

    ws.onmessage = function (evt) {
      console.log('收到来自服务器的消息:', evt.data);

      var div = document.createElement('div');
      div.innerHTML = evt.data;
      document.getElementById('messages').appendChild(div);
    };

    ws.onerror = function (evt) {
      console.log('连接发生错误:', evt);
    };

    ws.onclose = function (evt) {
      console.log('连接关闭');
    };

    function sendMessage() {
      var message = document.getElementById("messageInput").value;
      ws.send(message);
      document.getElementById("messageInput").value = "";
    }
  </script>
</body>
</html>

启动后台 C# 应用程序,然后在浏览器中打开该 HTML 页面,你会发现页面会显示所有发送到聊天室的消息,并可以通过文本框发送消息。

示例二

我们在 ASP.NET CORE 的中间件中添加 WebSocket 支持,从而实现了 WebSocket 服务器。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddWebSocketManager();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseWebSockets();

        app.MapWebSocketManager("/chat", app.ApplicationServices.GetService<ChatRoomHandler>());

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

public class ChatRoomHandler : WebSocketHandler
{
    public ChatRoomHandler(WebSocketConnectionManager webSocketConnectionManager) : base(webSocketConnectionManager)
    {
    }

    public override Task OnConnected(WebSocket socket)
    {
        return base.OnConnected(socket);
    }

    public override Task ReceiveAsync(WebSocket socket, WebSocketReceiveResult result, byte[] buffer)
    {
        string message = $"{socket.GetHashCode().ToString()} said: {Encoding.UTF8.GetString(buffer, 0, result.Count)}";
        return SendMessageToAllAsync(message);
    }
}

public static class WebSocketExtensions
{
    public static IServiceCollection AddWebSocketManager(this IServiceCollection services)
    {
        services.AddSingleton<WebSocketConnectionManager>();

        return services;
    }

    public static IApplicationBuilder MapWebSocketManager(this IApplicationBuilder app, string path, Type type)
    {
        return app.Map(path, builder =>
        {
            builder.UseMiddleware<WebSocketManagerMiddleware>(type);
        });
    }
}

public class WebSocketManagerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly WebSocketHandler _webSocketHandler;

    public WebSocketManagerMiddleware(RequestDelegate next, WebSocketHandler webSocketHandler)
    {
        _next = next;
        _webSocketHandler = webSocketHandler;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.WebSockets.IsWebSocketRequest)
        {
            await _next(context);
            return;
        }

        WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
        await _webSocketHandler.OnConnected(webSocket);

        try
        {
            await _webSocketHandler.ReceiveAsync(webSocket);
        }
        catch (Exception ex)
        {
            await _webSocketHandler.OnDisconnected(webSocket);
        }
    }
}

该示例演示了如何创建 WebSocket 基础结构以处理 WebSocket 连接。WebSocketConnectionManager 类负责管理所有 WebSocket 的集合,其中包含 WebSocket 对象和 ID。WebSocketHandler 类负责处理 WebSocket 连接上的事件,包括消息收发、连接和断开连接。

反复测试后可发现,我们已经成功实现了聊天室的功能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#使用WebSocket实现聊天室功能 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • jquery常用方法及使用示例汇总

    jQuery常用方法及使用示例汇总 什么是jQuery? jQuery是一个快速、简洁的JavaScript库,使得JavaScript更容易使用。通过jQuery,您可以处理HTML文档遍历和操作,使得动态效果和用户交互变得更加简单和快速。 常用方法 1. 事件处理 click():点击事件 hover():鼠标悬停事件 mousedown():鼠标按下事…

    jquery 2023年5月27日
    00
  • jquery获取一组checkbox的值(实例代码)

    下面是详细讲解“jquery获取一组checkbox的值(实例代码)”的完整攻略。 1. 前提准备 在实现获取一组checkbox的值的功能之前,我们需要确保页面上已经存在需要操作的checkbox元素,并且需要引入jQuery库。可以使用以下代码在页面底部引入jQuery: <script src="https://cdn.bootcss.…

    jquery 2023年5月28日
    00
  • jQuery ajaxComplete()方法

    在jQuery中,可以使用ajaxComplete()方法来注册一个全局的回调函数,该函数在每个Ajax请求完成时都会被调用。以下是详细攻略,含两个示例,演示如何使用ajaxComplete()方法: 语法 ajaxComplete()方法的语法如下: $(document).ajaxComplete(function(event, xhr, setting…

    jquery 2023年5月9日
    00
  • jQuery删除节点的三个方法即remove()detach()和empty()

    当开发使用jQuery的时候,删除某一个DOM节点是非常常见的操作。而要删除一个DOM节点,jQuery提供了三个方法remove(),detach(),和empty(),分别用于删除节点本身,删除节点及所有子节点,并保留该节点在内存中的数据,以及删除节点的所有子节点。 1. remove() .remove()方法是jQuery的核心方法之一,它会将匹配元…

    jquery 2023年5月28日
    00
  • jQWidgets jqxTooltip destroy()方法

    以下是关于 jQWidgets jqxTooltip 组件中 destroy() 方法的详细攻略。 jQWidgets jqxTooltip destroy() 方法 jQWidgets jqxTooltip 组件的 destroy() 方法用于销毁已创建的 jqxTooltip 组件。可以使用该方法在不需要组件时释放内存和资源。 语法 $(‘#toolti…

    jquery 2023年5月11日
    00
  • 基于jquery异步传输json数据格式实例代码

    下面是关于“基于jquery异步传输json数据格式实例代码”的完整攻略。 什么是异步传输 异步传输是指传输数据时不需要等待响应,而是在传输过程中可以继续执行其他操作。这个特性可以通过Ajax技术实现。Ajax(Asynchronous JavaScript and XML)是一种用于创建快速动态网页的技术,通过在后台与服务器进行少量数据交换,Ajax可以使…

    jquery 2023年5月28日
    00
  • jQuery实现的登录浮动框效果代码

    下面是简单的“jQuery实现的登录浮动框效果代码”的攻略: 1. 准备工作 在使用jQuery之前,需要先在HTML文件中导入jQuery库。在头部添加以下代码即可: <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script&gt…

    jquery 2023年5月28日
    00
  • jQWidgets jqxProgressBar模板属性

    以下是关于 jQWidgets jqxProgressBar 组件中模板属性的详细攻略。 jQWidgets jqxProgressBar 模板属性 jQWidgets jqxProgressBar 组件的模板属性用于定义进度条的外观和行为。 语法 // 设置模板属性 $(‘#progressBar’).jqxProgressBar({ template: …

    jquery 2023年5月12日
    00
合作推广
合作推广
分享本页
返回顶部