跳到主要内容
版本:4.0-beta

创建WebSocket服务器

定义

定义

命名空间:
TouchSocket.HttpTouchSocket.Http.WebSockets
安装:
dotnet add package TouchSocket.Http

一、说明

WebSocket服务器是基于HTTP协议升级而来的长连接通信协议服务器。它继承自HttpService,在完成HTTP握手后,通过协议升级建立WebSocket连接。每个成功连接的客户端都会在服务器端创建一个对应的HttpSessionClient实例,后续的所有WebSocket通信都通过该实例完成。

二、特点

  • 基于HTTP协议升级,支持标准WebSocket协议。
  • 支持文本、二进制以及其他Type数据传输。
  • 内置心跳机制(Ping/Pong)。
  • 支持数据帧分包和组合。
  • 支持WSS(WebSocket Secure)加密连接。
  • 支持多种连接验证方式。
  • 高性能异步处理。
  • 基于插件驱动,支持AOP编程。

三、产品应用场景

  • 实时通信应用:聊天室、在线客服、实时协作等。
  • 实时数据推送:股票行情、游戏数据、监控数据等。
  • 物联网设备通信:传感器数据上报、设备控制等。
  • Web应用实时交互:在线编辑器、实时画板等。

四、服务器架构

4.1 连接架构

WebSocket服务器基于HTTP服务器,当收到WebSocket握手请求时,会将HTTP连接升级为WebSocket连接。每个WebSocket连接对应一个HttpSessionClient实例。

4.2 协议升级流程

  1. 客户端发送HTTP握手请求
  2. 服务器验证握手请求
  3. 服务器响应握手成功
  4. 连接升级为WebSocket协议
  5. 开始WebSocket数据帧通信

五、可配置项

继承HttpService的所有配置项,无特殊配置。

六、支持插件接口

插件方法功能
IWebSocketConnectingPlugin当收到握手请求之前,可以进行连接验证等
IWebSocketConnectedPlugin当成功握手响应之后
IWebSocketReceivedPlugin当收到Websocket的数据报文
IWebSocketClosingPlugin当收到关闭请求时触发。如果对方直接断开连接,则此方法则不会触发。
IWebSocketClosedPlugin当WebSocket连接断开时触发,无论是否正常断开。但如果是断网等操作,可能不会立即执行,需要结合心跳操作和CheckClear插件来进行清理。

七、创建WebSocket服务器

7.1 简单直接创建

最简单的方式是使用WebSocket插件,直接指定URL路由来接收WebSocket连接。

🔄 正在加载代码...

7.2 验证连接

可以对连接的URLQuery参数、Header等进行验证,决定是否允许WebSocket连接。

🔄 正在加载代码...
提示

在验证过程中,如果url不匹配,或者不包含升级协议头的话,一般不需要额外处理,直接返回false即可。随后这个请求会被当作普通的HTTP请求处理。

如果url正确,但是其他鉴权没通过时,才需要直接进行Http响应。

7.3 其他方式创建

实际上,只要在升级协议后,能访问到HttpContext,即可通过SwitchProtocolToWebSocketAsync方式创建WebSocket连接更加灵活,可以方便地获取HTTP参数,实现多个URL的连接路由。

🔄 正在加载代码...
信息

SwitchProtocolToWebSocketAsync后的WebSocket实例还是会放置在所在的HttpSessionClient中,可以通过HttpSessionClient.WebSocket获取到。

7.4 创建基于SSL的WebSocket服务(WSS)

创建WSS(WebSocket Secure)服务器,只需在配置中添加SSL选项。详情: Http服务器配置Ssl

八、接收消息

WebSocket服务器有多种接收消息的方式,可以根据不同的使用场景选择合适的方法。

8.1 插件方式接收消息

使用插件接收消息是最推荐的方式,它提供了高度解耦和灵活的数据处理能力。

(1)定义插件:

🔄 正在加载代码...

(2)配置使用插件:

🔄 正在加载代码...
提示

在服务器端,默认情况下插件的所有函数都可能被并发执行,因此应当做好线程安全处理。更多详情请参考:插件开发使用指南

8.2 异步阻塞接收

异步阻塞接收是通过直接调用WebSocketReadAsync方法来同步阻塞式读取数据。这种方式的特点是能在代码上下文中直接获取数据,便于处理复杂的数据逻辑。

一般的,在IWebSocketConnectedPlugin插件中(即刚连接成功)调用ReadAsync方法来接收数据。

🔄 正在加载代码...
信息

ReadAsync方式是异步非阻塞的接收方式,不会占用线程资源,只会阻塞当前Task。因此可以大量使用,不需要考虑性能问题。

注意

使用ReadAsync方式会阻塞IWebSocketConnectedPlugin的插件传递链,在收到WebSocket消息时不会触发IWebSocketReceivedPlugin插件。

8.3 接收中继数据

WebSocket在接收大数据时,可能会分包接收。可以通过WSDataFrame.Opcode的值是不是WSDataType.Cont来判断是不是分包数据。

分包数据的处理方式有很多,下面提供一种内存缓存的方式:

🔄 正在加载代码...
注意

内存缓存的方式适合数据量不大的场景,如果数据量较大,建议使用其他缓存等方式。

九、发送数据

按照WebSocket服务器架构,每个成功连接的客户端都会在服务器端创建一个HttpSessionClient实例。要发送WebSocket消息,需要通过这些实例进行操作。

9.1 获取客户端实例

一般的,如果在插件中收到信息时,可以直接拿到HttpSessionClient实例。或者IWebSocket对象。此时直接操作即可。

如果在服务器的其他地方想要发送消息,可以通过下面代码获取所有在线客户端,然后选择需要发送的客户端。

🔄 正在加载代码...

9.2 发送文本消息

🔄 正在加载代码...

9.3 发送二进制消息

🔄 正在加载代码...

9.4 发送自定义数据帧

🔄 正在加载代码...

9.5 发送Ping、Pong消息

🔄 正在加载代码...

9.7 发送大数据(分包)

发送大数据时,需要分包发送,可以使用SendAsync的重载方法,设置FIN标志。

🔄 正在加载代码...

十、连接管理

10.1 主动关闭连接

在使用WebSocket时,如果想主动关闭连接,可以使用CloseAsync方法,同时可以携带一个关闭原因。

默认关闭状态码为1000。意为:正常关闭。

🔄 正在加载代码...

十一、示例Demo