IIS 中使用 WebSocket

下面将介绍如何在iis上使用 websocket 。

创建项目

我们需要创建一个 WebApi

打开初始程序中 Program 类的 main 方法,并进行修改

 

服务器 - 添加管理类

创建一个管理类用于管理 WebSocket 的链接

复制代码
 1 public class WebSocketConnectionManager
 2 {
 3     private Dictionary<string, WebSocket> connections = new Dictionary<string, WebSocket>();
 4     private int onlineUserCount = 0;
 5 
 6     //检测到链接时加入列表
 7     public void AddWebSocket(WebSocket webSocket)
 8     {
 9         string connectionId = Guid.NewGuid().ToString();
10         connections.TryAdd(connectionId, webSocket);
11     }
12 
13     //断开链接时移除列表中数据
14     public void RemoveWebSocket(WebSocket webSocket)
15     {
16         var connection = connections.FirstOrDefault(pair => pair.Value == webSocket);
17         if (!connection.Equals(default(KeyValuePair<string, WebSocket>)))
18         {
19             connections.Remove(connection.Key);
20         }
21     }
22 
23     //获取当前连接数
24     public int GetOnlineUserCount()
25     {
26         return onlineUserCount;
27     }
28 
29     //链接计数器
30     public void IncrementOnlineUserCount()
31     {
32         onlineUserCount++;
33     }
34     public void DecrementOnlineUserCount()
35     {
36         if (onlineUserCount > 0)
37         {
38             onlineUserCount--;
39         }
40     }
41 }
View Code
复制代码

将管理类以单例的方式添加到服务列表中

方便在控制器中调用,调用方法如下

复制代码
 1 [ApiController]
 2 [Route("[controller]")]
 3 public class WebSocketController : ControllerBase
 4 {
 5     private readonly WebSocketConnectionManager _webSocketConnectionManager;
 6     public WebSocketController(WebSocketConnectionManager webSocketConnectionManager)
 7     {
 8         _webSocketConnectionManager = webSocketConnectionManager;
 9     }
10 
11     [HttpGet]
12     [Route("ConnectionNum")]
13     public IActionResult ConnectionNum()
14     {
15         int onlineUserCount = _webSocketConnectionManager.GetOnlineUserCount();
16 
17         return Ok("WebSocket API Connect Num - " + onlineUserCount);
18     }
19 }
View Code
复制代码

服务器 - 在 IIS 中添加 WebSocket

如需在服务器上使用 WebSocket ,需服务器管理器中添加 WebSocket 协议

继续在 Program 类的 main 方法 添加代码

复制代码
var app = builder.Build();

//获取 WebSocekets 并将 管理 加入到 Websocket处理中
WebSocketHandler webSocketHandler = new WebSocketHandler(app.Services.GetRequiredService<WebSocketConnectionManager>());
//WebSockets 选项 (可忽略使用默认值)
WebSocketOptions options = new WebSocketOptions();
options.KeepAliveInterval = TimeSpan.FromSeconds(120);
options.ReceiveBufferSize = 4 * 1024;

app.UseWebSockets(options);
app.Use(async (context, next) =>
{
    if (context.WebSockets.IsWebSocketRequest)
    {
        //走自己处理
        WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
        await webSocketHandler.HandleWebSocketAsync(webSocket);
    }
    else
    {
        //走控制器
        await next();
    }
});
View Code
复制代码

WebSocketHandler 类

复制代码
public class WebSocketHandler
{
    private WebSocket webSocket;
    private WebSocketConnectionManager connectionManager;
    public WebSocketHandler(WebSocketConnectionManager connectionManager)
    {
        this.connectionManager = connectionManager;
    }

    public async Task HandleWebSocketAsync(WebSocket socket)
    {
        this.webSocket = socket;
        this.connectionManager.AddWebSocket(webSocket);
        // 连接成功后,增加在线用户数量
        connectionManager.IncrementOnlineUserCount();

        try
        {
            byte[] buffer = new byte[1024];
            WebSocketReceiveResult result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

            while (!result.CloseStatus.HasValue)
            {
                string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
                Console.WriteLine($"Received: {message}");

                // Process and respond to the message here

                await socket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

                result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }

            if (result.CloseStatus.HasValue)
            {
                CloseWebSocket();
                await socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
            }
        }
        catch (Exception ex)
        {
            try
            {
                // 指定要写入的文件路径

                string executablePath = System.Reflection.Assembly.GetEntryAssembly().Location;
                string executableDirectory = Path.GetDirectoryName(executablePath);
                string fileName = "error.log"; // 文件名
                string filePath = Path.Combine(executableDirectory, fileName);
                if (!File.Exists(filePath))
                {
                    using (File.Create(filePath))
                    {
                        // 文件流在这个块内创建并打开,随后会在块结束时自动关闭。
                    }
                }

                // 使用 StreamWriter 打开文件以追加方式写入错误信息
                using (StreamWriter writer = File.AppendText(filePath))
                {
                    // 写入错误信息和时间戳
                    writer.WriteLine($"[{DateTime.Now}] {ex.Message}");
                }
            }
            catch (Exception)
            {
                // 处理可能的文件操作异常
                Console.WriteLine("写入错误日志时发生异常:" + ex.Message);
            }


            CloseWebSocket();
        }

    }
    private void CloseWebSocket()
    {
        if (this.webSocket != null)
        {
            this.connectionManager.RemoveWebSocket(this.webSocket);

            // 断开连接后,减少在线用户数量
            connectionManager.DecrementOnlineUserCount();

            this.webSocket.Dispose();
        }


    }
}
View Code
复制代码

客户端 - WebSocket 链接请求

代码示例 

复制代码
public class WebSocketApi
{
    static Uri clientUri = new Uri("wss://www.lilongfei.club:1994"); // WebSocket server address https 使用
    //static Uri clientUri = new Uri("ws://www.lilongfei.club:1994"); // WebSocket server address http 使用

    static ClientWebSocket clientWebSocket = new ClientWebSocket();

    #region 客户端 IIS
    public static async Task WebSocketStart()
    {
        try
        {
            //只进行一次链接请求
            if (clientWebSocket.State != WebSocketState.Open)
            {
                //将代理器设为空
                clientWebSocket.Options.Proxy = null;
                //链接 IIS服务器
                await clientWebSocket.ConnectAsync(clientUri, CancellationToken.None);
            }

            Console.WriteLine("Connected to the WebSocket server.");

            // Send a message to the server
            string messageToSend = "Hello, server!";
            byte[] sendBuffer = Encoding.UTF8.GetBytes(messageToSend);
            await clientWebSocket.SendAsync(new ArraySegment<byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None);

            // Receive and handle the server's response
            byte[] receiveBuffer = new byte[1024];
            WebSocketReceiveResult receiveResult = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
            string receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);
            Console.WriteLine($"Received: {receivedMessage}");
        }
        catch (Exception e)
        {
            await CloseWebSocket(clientWebSocket);
            Console.WriteLine(e);
            throw;
        }

    }

    //关闭 WebSocket 链接
    static async Task CloseWebSocket(ClientWebSocket clientWebSocket)
    {
        byte[] closeBuffer = Encoding.UTF8.GetBytes("Connection closing...");
        WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure;
        string closeDescription = "Connection closed gracefully";
        CancellationToken ct = CancellationToken.None;

        await clientWebSocket.CloseOutputAsync(closeStatus, closeDescription, ct);
        WebSocketReceiveResult result = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(new byte[1024]), ct);
        await clientWebSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, ct);
    }

    #endregion
View Code
复制代码

完成收工

posted @   已惯天涯  阅读(802)  评论(2编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示