一、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? 來管理多個客戶端連接