通信协议—WebSocket
一、WebSocket编程概念
1.1 什么是WebSocket
WebSocket 是一种全双工通信协议,允许在客户端(通常是浏览器)和服务器之间建立持久连接,以实现实时的双向通信。它是 HTML5 标准的一部分,相比传统的 HTTP 请求,WebSocket 提供了更低的延迟和更高的性能,特别适合于需要实时更新数据的应用程序,如在线聊天、实时监控、游戏等
1.2 WebSocket的基本使用步骤
1.2.1 )服务器端
1.2.1.1)使用System.Net.WebSocket命名空间
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
1.2.1.2) 创建WebSocket服务器端点
public async Task HandleWebSocketConnection(HttpContext context)
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
await EchoWebSocket(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
1.2.1.3)处理WebSocket消息
private async Task EchoWebSocket(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);
}
// 关闭 WebSocket 连接
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
1.2.1.4)启动服务器
public static async Task Main(string[] args)
{
var webSocketServer = new WebSocketServer();
await webSocketServer.Start();
}
1.2.2 )客户端
1.2.2.1)使用System.Net.WebSocket.ClientWebSocket 命名空间
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
1.2.2.2)创建WebSocket客户端并连接到服务器
public async Task ConnectToWebSocketServer()
{
using (var clientWebSocket = new ClientWebSocket())
{
Uri serverUri = new Uri("ws://localhost:8080/ws");
await clientWebSocket.ConnectAsync(serverUri, CancellationToken.None);
await SendAndReceiveData(clientWebSocket);
}
}
1.2.2.3)发送和接收数据
private async Task SendAndReceiveData(ClientWebSocket clientWebSocket)
{
var buffer = new byte[1024 * 4];
string message = "Hello, WebSocket Server!";
var sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));
await clientWebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
WebSocketReceiveResult result = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string receivedMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine($"Received: {receivedMessage}");
}
1.2.2.4)启动客户端
public static async Task Main(string[] args)
{
var webSocketClient = new WebSocketClient();
await webSocketClient.ConnectToWebSocketServer();
}
1.2.3) 运行步骤
1.2.3.1)先启动服务器程序,服务器将开始监听请求。
1.2.3.2)再启动客户端程序,客户端会连接到服务器并发送一条消息。
1.2.3.3)服务器接收到消息后,打印消息并回复。
1.2.3.4)客户端接收到服务器的回复并打印。
1.3 完整代码示例
1.3.1)服务器端
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WebSocketServerExample
{
public class WebSocketServer
{
private readonly IWebHost _webHost;
public WebSocketServer()
{
_webHost = new WebHostBuilder()
.UseKestrel()
.ConfigureServices(services => services.AddRouting())
.Configure(app =>
{
app.UseWebSockets();
app.Use(async (context, next) =>
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
await EchoWebSocket(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
});
})
.Build();
}
public async Task Start()
{
await _webHost.StartAsync();
}
private async Task EchoWebSocket(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);
}
// 关闭 WebSocket 连接
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
}
class Program
{
static async Task Main(string[] args)
{
var webSocketServer = new WebSocketServer();
await webSocketServer.Start();
}
}
}
// 代码解释
// 创建 WebSocket 服务器端点:
// app.UseWebSockets();:启用 WebSocket 中间件。
// context.WebSockets.IsWebSocketRequest:检查请求是否为 WebSocket 请求。
// context.WebSockets.AcceptWebSocketAsync():接受 WebSocket 请求并创建 WebSocket 对象。
// 处理 WebSocket 消息:
// await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);:接收客户端发送的消息。
// await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);:将接收到的消息发送回客户端。
// await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);:当收到关闭请求时,关闭连接。
1.3.2)客户端
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
namespace WebSocketClientExample
{
public class WebSocketClient
{
public async Task ConnectToWebSocketServer()
{
using (var clientWebSocket = new ClientWebSocket())
{
Uri serverUri = new Uri("ws://localhost:8080/ws");
await clientWebSocket.ConnectAsync(serverUri, CancellationToken.None);
await SendAndReceiveData(clientWebSocket);
}
}
private async Task SendAndReceiveData(ClientWebSocket clientWebSocket)
{
var buffer = new byte[1024 * 4];
string message = "Hello, WebSocket Server!";
var sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));
await clientWebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
WebSocketReceiveResult result = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string receivedMessage = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine($"Received: {receivedMessage}");
}
}
class Program
{
static async Task Main(string[] args)
{
var webSocketClient = new WebSocketClient();
await webSocketClient.ConnectToWebSocketServer();
}
}
}
// 代码解释
// 创建 WebSocket 客户端并连接到服务器:
// new ClientWebSocket():创建 WebSocket 客户端对象。
// clientWebSocket.ConnectAsync(serverUri, CancellationToken.None);:连接到服务器。
发送和接收数据:
// await clientWebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);:向服务器发送消息。
// await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);:接收服务器的消息。
1.4 注意事项
1.4.1)端口号和URI : 确保服务器和客户端使用相同的端口号和URI路径
1.4.2)异常处理 :在实际应用中,需要添加适当的异常处理代码,例如处理连接失败、接收或发送消息时的异常等
1.4.3)多客户端处理 :上述服务器端代码仅处理一个客户端,对于多客户端场景,需要使用更复杂的逻辑,例如使用 ConcurrentDictionary 来管理多个客户端连接