创建WebSocket服务器
定义
定义
命名空间:
TouchSocket.Http
TouchSocket.Http.WebSockets
安装:
dotnet add package TouchSocket.Http
一、说明
WebSocket
是基于Http
协议的升级协议,所以应当挂载在http
服务器执行。
二、可配置项
三、支持插件接口
插件方法 | 功能 |
---|---|
IWebSocketHandshakingPlugin | 当收到握手请求之前,可以进行连接验证等 |
IWebSocketHandshakedPlugin | 当成功握手响应之后 |
IWebSocketReceivedPlugin | 当收到Websocket的数据报文 |
IWebSocketClosingPlugin | 当收到关闭请求时触发。如果对方直接断开连接,则此方法则不会触发。 |
IWebSocketClosedPlugin | 当WebSocket连接断开时触发,无论是否正常断开。但如果是断网等操作,可能不会立即执行,需要结合心跳操作和CheckClear插件来进行清理。 |
四、创建WebSocket服务
4.1 简单直接创建
可以使用WebSocket插件,直接指定一个特殊url
路由,来完全接收WebSocket连接。
然后通过插件来接收数据。(例:下列接收数据)
var service = new HttpService();
await service.SetupAsync(new TouchSocketConfig()//加载配置
.SetListenIPHosts(7789)
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.UseWebSocket()//添加WebSocket功能
.SetWSUrl("/ws")//设置url直接可以连接。
.UseAutoPong();//当收到ping报文时自动回应pong
}));
await service.StartAsync();
service.Logger.Info("服务器已启动");
4.2 验证连接
可以对连接的Url
、Query
、Header
等参数进行验证,然后决定是否执行WebSocket
连接。
var service = new HttpService();
await service.SetupAsync(new TouchSocketConfig()//加载配置
.SetListenIPHosts(7789)
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.UseWebSocket()//添加WebSocket功能
.SetVerifyConnection(VerifyConnection)
.UseAutoPong();//当收到ping报文时自动回应pong
}));
await service.StartAsync();
service.Logger.Info("服务器已启动");
/// <summary>
/// 验证websocket的连接
/// </summary>
/// <param name="client"></param>
/// <param name="context"></param>
/// <returns></returns>
private static bool VerifyConnection(IHttpSessionClient client, HttpContext context)
{
if (!context.Request.IsUpgrade())//如果不包含升级协议的header,就直接返回false。
{
return false;
}
if (context.Request.UrlEquals("/ws"))//以此连接,则直接可以连接
{
return true;
}
else if (context.Request.UrlEquals("/wsquery"))//以此连接,则需要传入token才可以连接
{
if (context.Request.Query.Get("token") == "123456")
{
return true;
}
else
{
context.Response
.SetStatus(403, "token不正确")
.Answer();
}
}
else if (context.Request.UrlEquals("/wsheader"))//以此连接,则需要从header传入token才可以连接
{
if (context.Request.Headers.Get("token") == "123456")
{
return true;
}
else
{
context.Response
.SetStatus(403, "token不正确")
.Answer();
}
}
return false;
}
4.3 通过WebApi创建
通过WebApi的方式会更加灵活,也能很方便的获得Http相关参数。还能实现多个Url的连接路由。
实现步骤:
- 配置
WebApi
相关,详情请看WebApi - 在插件中接收
WebSocket
连接。
var service = new HttpService();
await service.SetupAsync(new TouchSocketConfig()//加载配置
.SetListenIPHosts(7789)
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddRpcStore(store =>
{
store.RegisterServer<MyApiServer>();//注册服务
});
})
.ConfigurePlugins(a =>
{
a.UseWebApi();
}));
await service.StartAsync();
service.Logger.Info("服务器已启动");
【接收连接】
public class MyApiServer : RpcServer
{
private readonly ILog m_logger;
public MyApiServer(ILog logger)
{
this.m_logger = logger;
}
[Router("/[api]/[action]")]
[WebApi(HttpMethodType.GET)]
public async Task ConnectWS(IWebApiCallContext callContext)
{
if (callContext.Caller is HttpSessionClient sessionClient)
{
if (await sessionClient.SwitchProtocolToWebSocketAsync(callContext.HttpContext))
{
m_logger.Info("WS通过WebApi连接");
var webSocket = sessionClient.WebSocket;
}
}
}
}
或者接收到连接后,直接使用WebSocket
接收。这样如果想直接在WebApi
返回数据也比较方便。
public class MyApiServer : RpcServer
{
private readonly ILog m_logger;
public MyApiServer(ILog logger)
{
this.m_logger = logger;
}
[Router("/[api]/[action]")]
[WebApi(HttpMethodType.GET)]
public async Task ConnectWS(IWebApiCallContext callContext)
{
if (callContext.Caller is HttpSessionClient sessionClient)
{
if (await sessionClient.SwitchProtocolToWebSocketAsync(callContext.HttpContext))
{
m_logger.Info("WS通过WebApi连接");
var webSocket = sessionClient.WebSocket;
webSocket.AllowAsyncRead = true;
while (true)
{
using (var tokenSource=new CancellationTokenSource(TimeSpan.FromSeconds(30)))
{
using (var receiveResult = await webSocket.ReadAsync(tokenSource.Token))
{
if (receiveResult.IsCompleted)
{
//webSocket已断开
return;
}
//webSocket数据帧
var dataFrame = receiveResult.DataFrame;
//此处可以处理数据
}
}
}
}
}
}
}
4.4 通过Http上下文直接创建
使用上下文直接创建的优点在于能更加个性化的实现WebSocket
的连接。
class MyHttpPlugin : PluginBase, IHttpPlugin
{
public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e)
{
if (e.Context.Request.UrlEquals("/GetSwitchToWebSocket"))
{
var result = await client.SwitchProtocolToWebSocketAsync(e.Context);
return;
}
await e.InvokeNext();
}
}
4.5 创建基于Ssl的WebSocket服务
创建WSs
服务器时,其他配置不变,只需要在config
中配置SslOption
代码即可,放置了一个自制Ssl
证书,密码为“RRQMSocket”以供测试。使用配置非常方便。
var config = new TouchSocketConfig();
config.SetServiceSslOption(new ServiceSslOption() //Ssl配置,当为null的时候,相当于创建了ws服务器,当赋值的时候,相当于wss服务器。
{
Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"),
SslProtocols = SslProtocols.Tls12
});
五、接收消息
WebSocket服务器接收消息,目前有两种方式。第一种就是通过订阅IWebSocketReceivedPlugin
插件完全异步的接收消息。第二种就是调用WebSocket
,然后调用ReadAsync
方法异步阻塞式读取。