一般我们在做展厅项目的时候,交互方式和常见的数字孪生项目是不一样的,常见的数字孪生是通过鼠标点击来进行操作,但是在展厅中屏幕和主机物理距离是很远的,然后无线鼠标操作受到场地影响又影响用户的体验。那么我们是不是可以用一个平板或者手机来交互呢。
使用移动端控制我们的展厅必然会涉及到服务端和客户端通信的问题。我们的实现思路如下。
首先服务端要开启一个websocket监听,完成一个收消息和发消息的基本函数。
如果移动端要控制多个大屏还要实现消息的广播,将移动端收到的消息广播给所有的客户端,客户端再根据收到的消息再处理相应的逻辑。
服务端代码:
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static ConcurrentDictionary<string, WebSocket> _clients = new ConcurrentDictionary<string, WebSocket>();
static async Task Main(string[] args)
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:7799/");
listener.Start();
Console.WriteLine("Listening for WebSocket connections...");
while (true)
{
HttpListenerContext context = await listener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
ProcessWebSocketRequest(context);
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
}
static async void ProcessWebSocketRequest(HttpListenerContext context)
{
WebSocketContext webSocketContext = null;
try
{
webSocketContext = await context.AcceptWebSocketAsync(subProtocol: null);
string clientId = Guid.NewGuid().ToString();
WebSocket webSocket = webSocketContext.WebSocket;
_clients.TryAdd(clientId, webSocket);
Console.WriteLine("WebSocket client connected. ClientId: " + clientId);
byte[] buffer = new byte[1024];
WebSocketReceiveResult result = null;
CancellationTokenSource cts = new CancellationTokenSource();
while (webSocket.State == WebSocketState.Open)
{
try
{
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cts.Token);
if (result.MessageType == WebSocketMessageType.Text)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine("Received message from ClientId " + clientId + ": " + message);
// 广播消息给所有客户端
Task broadcastTask = BroadcastMessage(message, clientId);
await broadcastTask; // 等待广播完成
// 示例:给指定客户端发送消息
await SendMessageToClient(message, clientId);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
Console.WriteLine("WebSocket client disconnected. ClientId: " + clientId);
break;
}
}
catch (WebSocketException ex)
{
Console.WriteLine("An error occurred while receiving or broadcasting message: " + ex.Message);
break;
}
}
_clients.TryRemove(clientId, out _);
webSocket.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: " + ex.Message);
}
finally
{
if (webSocketContext != null)
{
webSocketContext.WebSocket.Dispose();
}
}
}
static async Task BroadcastMessage(string message, string senderClientId)
{
byte[] buffer = Encoding.UTF8.GetBytes(message);
foreach (var client in _clients)
{
WebSocket webSocket = client.Value;
if (webSocket.State == WebSocketState.Open && client.Key != senderClientId)
{
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
static async Task SendMessageToClient(string message, string clientId)
{
if (_clients.TryGetValue(clientId, out WebSocket webSocket))
{
byte[] buffer = Encoding.UTF8.GetBytes(message);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
服务端已经搭好了。