服务功能实现
技术点
- 传输方式:TCP 协议保证数据有序、无丢失传输,通过字节流拆包 / 封包机制解决粘包 / 半包问题。
- 协议格式:采用 "4 字节长度头 + JSON 消息体" 的二进制协议,解决 TCP 粘包 / 半包问题。
- 消息格式:
MessageStyle消息格式,所有的消息都使用MessageStyle,包裹将消息放到Message中,然后设置不同的public MessageTypeEnum Type { get; set; }
项目执行流程
- 程序入口执行:调用Main方法,依次执行
RegisterApplicationEvents和InitializeSocket,进行事件注册和socket初始化 - 启动
AcceptClientConnections线程:循环调用_serverSocket.Accept()阻塞监听客户端连接请求,该线程为后台线程,不阻塞主线程 - 链接完成后使用
HandleConsoleInput启动控制台命令
客户端连接
-
接收客户端连接
AcceptClientConnections调用
GenerateUniqueClientId生成CLIENT_+GUID格式的唯一客户端 ID。创建
ClientInfo对象,存储客户端 Socket、ID、最后活跃时间、连接状态等信息。加锁将
ClientInfo添加到_clients字典,线程安全。控制台输出客户端连接信息(ID、IP、端口)。
-
发送欢迎消息
调用
SendWelcomeMessageToClient,发送欢迎消息,通过SendMessageToClient按 "4 字节长度头 + JSON 消息体" 协议发送给客户端,完成客户端身份初始化。启动客户端消息处理线程
csharp
// 启动处理客户端消息的线程
Thread clientThread = new Thread(() => HandleClient(clientId));
clientThread.IsBackground = true;
clientThread.Start();
为当前客户端分配独立的 private static void HandleClient(string clientId) 线程。
-
然后接收和处理客户端发来的消息
ProcessClientMessage(clientId, message); -
解析数据,先读取四字节长度的消息,然后一直接收并解析数据
csharp
// 读取4字节的消息长度
int lengthBytesRead = 0;
while (lengthBytesRead < 4)
{
int read = clientInfo.Socket.Receive(
lengthBuffer,
lengthBytesRead,
4 - lengthBytesRead,
SocketFlags.None);
if (read == 0)
{
// 客户端断开连接
throw new SocketException((int) SocketError.ConnectionReset);
}
lengthBytesRead += read;
}
// 将4字节转换为消息长度(网络字节序转主机字节序)
int messageLength = BitConverter.ToInt32(lengthBuffer, 0);
messageLength = IPAddress.NetworkToHostOrder(messageLength);
// 根据长度读取完整消息
messageBuffer.SetLength(0);
- 处理各种消息
csharp
private static void HandleTextMessage(string clientId, MessageStyle message)
private static void HandleBroadcastMessage(string clientId, MessageStyle message)
private static void HandlePrivateMessage(string clientId, MessageStyle message)
private static void HandleSetUserName(string clientId, MessageStyle message)
等等-----
- 使用控制台发送命令
csharp
/// <summary>
/// 处理控制台输入
/// </summary>
private static void HandleConsoleInput()
{
Console.WriteLine("\n服务器命令:");
DeaultConsoleLine();
while (true)
{
try
{
string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
continue;
var parts = input.Trim().Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0) continue;
string command = parts[0].ToUpper();
string[] args = parts.Length > 1 ? parts.Skip(1).ToArray() : new string[0];
switch (command)
{
case "/EXIT":
break;
default:
Console.WriteLine("未知命令,输入 /help 查看可用命令");
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"处理命令时出错: {ex.Message}");
}
}
}
项目引用


基础工具代码
仅需要生成客户端id这一个工具代码,只有一个地方使用到了,所以也可以删掉直接写到用地方。
csharp
/// <summary>
/// 生成客户端ID
/// </summary>
private static string GenerateClientId()
{
lock (_lock)
{
return $"CLIENT_{Guid.NewGuid():N}";
}
}
变量创建
csharp
/// <summary>
/// socket
/// </summary>
private static Socket _serverSocket;
/// <summary>
/// 客户端列表
/// </summary>
private static Dictionary<string, ClientInfo> _clients = new Dictionary<string, ClientInfo>();
/// <summary>
/// 线程锁
/// </summary>
private static object _lock = new object();
/// <summary>
/// 端口
/// </summary>
private static int Port = 23841;
socket链接
csharp
/// <summary>
/// 初始化socket
/// </summary>
private static void InitSocket()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipNode = new IPEndPoint(IPAddress.Any, Port);
try
{
_serverSocket.Bind(ipNode);
_serverSocket.Listen(10);
Console.WriteLine($"服务器已启动,监听端口: {Port}");
Console.WriteLine("等待客户端连接...");
// 启动接受连接的线程
Thread acceptThread = new Thread(AcceptClients);
acceptThread.IsBackground = true;
acceptThread.Start();
// 处理控制台输入
HandleConsoleInput();
}
catch (Exception ex)
{
Console.WriteLine($"服务器启动失败: {ex.Message}");
}
}
/// <summary>
/// 接受客户端连接的线程
/// </summary>
private static void AcceptClients()
{
while (true)
{
try
{
Socket clientSocket = _serverSocket.Accept();
// 生成客户端ID
string clientId = GenerateClientId();
// 创建客户端信息
ClientInfo clientInfo = new ClientInfo
{
ClientId = clientId,
Socket = clientSocket,
LastActiveTime = DateTime.Now,
IsConnected = true
};
// 添加到客户端字典
lock (_lock)
{
_clients[clientId] = clientInfo;
}
IPEndPoint clientEndPoint = (IPEndPoint)clientSocket.RemoteEndPoint;
Console.WriteLine($"客户端 {clientId} 已连接,IP: {clientEndPoint.Address}:{clientEndPoint.Port}");
// 发送欢迎消息和客户端ID
SendWelcomeMessage(clientId);
// 启动处理客户端消息的线程
Thread clientThread = new Thread(() => HandleClient(clientId));
clientThread.IsBackground = true;
clientThread.Start();
}
catch (Exception ex)
{
Console.WriteLine($"接受客户端连接时出错: {ex.Message}");
}
}
}
/// <summary>
/// 事件注册
/// </summary>
private static void EventRegistration()
{
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
try
{
if (_serverSocket != null && _serverSocket.Connected)
{
_serverSocket.Shutdown(SocketShutdown.Both);
}
_serverSocket?.Close();
Console.WriteLine("服务器Socket已释放");
}
catch (Exception ex)
{
Console.WriteLine($"释放服务器Socket失败: {ex.Message}");
}
};
}
并且在Main中调用
csharp
static void Main(string[] args)
{
EventRegistration();
InitSocket();
}
事件处理
用户管理
发送欢迎消息,在用户连接之后
csharp
/// <summary>
/// 发送欢迎消息
/// </summary>
private static void SendWelcomeMessage(string clientId)
{
try
{
ClientInfo clientInfo;
lock (_lock)
{
if (!_clients.TryGetValue(clientId, out clientInfo))
{
return;
}
}
WelComMessageModel welComMessage = new WelComMessageModel("欢迎连接到Socket服务器!");
MessageStyle messageStyle = new MessageStyle
(
MessageTypeEnum.Welcome,
clientInfo.ClientId,
JsonConvert.SerializeObject(welComMessage)
);
SendMessage(clientInfo.ClientId, JsonConvert.SerializeObject(messageStyle));
}
catch (Exception ex)
{
Console.WriteLine($"发送欢迎消息失败: {ex.Message}");
}
}
/// <summary>
/// 移除客户端
/// </summary>
private static void RemoveClient(string clientId)
{
lock (_lock)
{
if (_clients.ContainsKey(clientId))
{
try
{
_clients[clientId].Socket.Shutdown(SocketShutdown.Both);
_clients[clientId].Socket.Close();
}
catch { }
_clients.Remove(clientId);
Console.WriteLine($"客户端 {clientId} 已从列表中移除");
}
}
}
消息事件
消息接收与消息预处理
csharp
/// <summary>
/// 处理客户端消息
/// </summary>
private static void HandleClient(string clientId)
{
ClientInfo clientInfo;
lock (_lock)
{
if (!_clients.TryGetValue(clientId, out clientInfo))
{ return; }
}
byte[] tempBuffer = new byte[1024];
try
{
byte[] lengthBuffer = new byte[4];
using (MemoryStream messageBuffer = new MemoryStream())
{
while (true)
{
// 读取4字节的消息长度
int lengthBytesRead = 0;
while (lengthBytesRead < 4)
{
int read = clientInfo.Socket.Receive(
lengthBuffer,
lengthBytesRead,
4 - lengthBytesRead,
SocketFlags.None);
if (read == 0)
{
// 客户端断开连接
throw new SocketException((int)SocketError.ConnectionReset);
}
lengthBytesRead += read;
}
// 将4字节转换为消息长度(网络字节序转主机字节序)
int messageLength = BitConverter.ToInt32(lengthBuffer, 0);
messageLength = IPAddress.NetworkToHostOrder(messageLength);
// 根据长度读取完整消息
messageBuffer.SetLength(0);
int totalBytesRead = 0;
while (totalBytesRead < messageLength)
{
int bytesToRead = Math.Min(tempBuffer.Length, messageLength - totalBytesRead);
int read = clientInfo.Socket.Receive(tempBuffer, 0, bytesToRead, SocketFlags.None);
if (read == 0)
{
// 客户端断开连接
throw new SocketException((int)SocketError.ConnectionReset);
}
messageBuffer.Write(tempBuffer, 0, read);
totalBytesRead += read;
}
// 处理消息
string message = Encoding.UTF8.GetString(messageBuffer.ToArray());
clientInfo.LastActiveTime = DateTime.Now;
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 客户端 {clientId} 发送: {message}");
// 解析客户端消息并处理
ProcessClientMessage(clientId, message);
}
}
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.ConnectionReset ||
ex.SocketErrorCode == SocketError.ConnectionAborted)
{
Console.WriteLine($"客户端 {clientId} 主动断开连接");
}
else if (ex.SocketErrorCode == SocketError.TimedOut)
{
Console.WriteLine($"客户端 {clientId} 连接超时");
}
else
{
Console.WriteLine($"客户端 {clientId} 网络异常: {ex.Message} (错误码: {ex.SocketErrorCode})");
}
}
catch (IOException ex)
{
Console.WriteLine($"客户端 {clientId} IO异常: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"客户端 {clientId} 未知异常: {ex.Message}");
}
finally
{
// 移除客户端
RemoveClient(clientId);
}
}
/// <summary>
/// 处理客户端发送的消息
/// </summary>
/// <param name="clientId">发送消息的客户端ID</param>
/// <param name="message">JSON格式的消息字符串</param>
private static void ProcessClientMessage(string clientId, string message)
{
try
{
// 反序列化基础消息结构
MessageStyle clientMessage = JsonConvert.DeserializeObject<MessageStyle>(message);
if (clientMessage == null)
{
Console.WriteLine($"客户端 {clientId} 发送无效消息格式: {message}");
return;
}
// 根据消息类型处理
switch (clientMessage.Type)
{
case MessageTypeEnum.Text:
HandleTextMessage(clientId, clientMessage);
break;
case MessageTypeEnum.Broadcast:
HandleBroadcastMessage(clientId, clientMessage);
break;
case MessageTypeEnum.PrivateMsg:
HandlePrivateMessage(clientId, clientMessage);
break;
case MessageTypeEnum.SetUserName:
HandleSetUserName(clientId, clientMessage);
break;
case MessageTypeEnum.Heartbeat:
HandleHeartbeatMessage(clientId, clientMessage);
break;
case MessageTypeEnum.Unknown:
HandleUnknownMessage(clientId, clientMessage);
break;
case MessageTypeEnum.ListRequest:
HandleListRequest(clientId);
break;
default:
Console.WriteLine($"客户端 {clientId} 发送未知消息类型: {clientMessage.Type}");
break;
}
}
catch (JsonSerializationException jsonEx)
{
Console.WriteLine($"客户端 {clientId} 消息反序列化失败: {jsonEx.Message},原始消息: {message}");
}
catch (Exception ex)
{
Console.WriteLine($"处理客户端 {clientId} 消息时出错: {ex.Message}");
}
}
处理文本消息
csharp
/// <summary>
/// 处理文本消息
/// </summary>
private static void HandleTextMessage(string clientId, MessageStyle message)
{
try
{
StandMessageModel textModel = JsonConvert.DeserializeObject<StandMessageModel>(message.Message);
string responseMsg = $"收到你的文本消息: {textModel.Message}";
// 回复发送者
MessageStyle response = new MessageStyle(MessageTypeEnum.Text, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, responseMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(response));
}
catch (Exception ex)
{
Console.WriteLine($"处理文本消息失败: {ex.Message}");
}
}
处理广播消息
csharp
/// <summary>
/// 处理广播消息
/// </summary>
private static void HandleBroadcastMessage(string clientId, MessageStyle message)
{
try
{
StandMessageModel broadcastModel = JsonConvert.DeserializeObject<StandMessageModel>(message.Message);
string broadcastContent = $"[{GetClientName(clientId)}({clientId})] 广播: {broadcastModel.Message}";
// 构建广播消息
MessageStyle broadcastMsg = new MessageStyle(MessageTypeEnum.Broadcast, clientId,
JsonConvert.SerializeObject(new StandMessageModel(clientId, "ALL", broadcastContent)));
string broadcastJson = JsonConvert.SerializeObject(broadcastMsg);
// 发送给所有在线客户端,包括发送者自己
lock (_lock)
{
foreach (var client in _clients)
{
SendMessage(client.Key, broadcastJson);
}
}
Console.WriteLine($"客户端 {clientId} 发送广播: {broadcastModel.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"处理广播消息失败: {ex.Message}");
}
}
处理私聊消息
csharp
/// <summary>
/// 处理私聊消息
/// </summary>
private static void HandlePrivateMessage(string clientId, MessageStyle message)
{
try
{
StandMessageModel privateModel = JsonConvert.DeserializeObject<StandMessageModel>(message.Message);
string targetClientId = privateModel.TargetClientID;
string privateContent = privateModel.Message;
// 验证目标客户端是否存在
if (!_clients.ContainsKey(targetClientId))
{
// 回复发送者:目标不存在
string errorMsg = $"目标客户端 {targetClientId} 不存在或已离线";
MessageStyle errorResponse = new MessageStyle(MessageTypeEnum.Text, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, errorMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(errorResponse));
return;
}
// 构建私聊消息
string senderName = GetClientName(clientId);
string privateMsgContent = $"[{senderName}({clientId})] 私聊: {privateContent}";
MessageStyle privateMsg = new MessageStyle(MessageTypeEnum.PrivateMsg, clientId,
JsonConvert.SerializeObject(new StandMessageModel(clientId, targetClientId, privateMsgContent)));
// 发送给目标客户端
SendMessage(targetClientId, JsonConvert.SerializeObject(privateMsg));
// 回复发送者:发送成功
string successMsg = $"已向 {targetClientId} 发送私聊消息: {privateContent}";
MessageStyle successResponse = new MessageStyle(MessageTypeEnum.Text, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, successMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(successResponse));
Console.WriteLine($"客户端 {clientId} 向 {targetClientId} 发送私聊: {privateContent}");
}
catch (Exception ex)
{
Console.WriteLine($"处理私聊消息失败: {ex.Message}");
}
}
处理设置用户名
csharp
/// <summary>
/// 处理设置用户名
/// </summary>
private static void HandleSetUserName(string clientId, MessageStyle message)
{
try
{
StandMessageModel userNameModel = JsonConvert.DeserializeObject<StandMessageModel>(message.Message);
string newUserName = userNameModel.Message.Trim();
if (string.IsNullOrEmpty(newUserName))
{
// 回复错误
string errorMsg = "用户名不能为空";
MessageStyle errorResponse = new MessageStyle(MessageTypeEnum.Text, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, errorMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(errorResponse));
return;
}
// 更新客户端用户名
lock (_lock)
{
if (_clients.ContainsKey(clientId))
{
_clients[clientId].ClientName = newUserName;
}
}
// 回复成功
string successMsg = newUserName;
MessageStyle successResponse = new MessageStyle(MessageTypeEnum.SetUserName, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, successMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(successResponse));
Console.WriteLine($"客户端 {clientId} 设置用户名为: {newUserName}");
}
catch (Exception ex)
{
Console.WriteLine($"处理设置用户名失败: {ex.Message}");
}
}
处理心跳消息
csharp
/// <summary>
/// 处理心跳消息
/// </summary>
private static void HandleHeartbeatMessage(string clientId, MessageStyle message)
{
try
{
StandMessageModel heartbeatModel = JsonConvert.DeserializeObject<StandMessageModel>(message.Message);
// 回复心跳确认
string heartbeatMsg = "心跳确认 - 服务器已收到";
MessageStyle heartbeatResponse = new MessageStyle(MessageTypeEnum.Heartbeat, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, heartbeatMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(heartbeatResponse));
Console.WriteLine($"客户端 {clientId} 心跳检测: {heartbeatModel.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"处理心跳消息失败: {ex.Message}");
}
}
处理未知类型消息
csharp
/// <summary>
/// 处理未知类型消息
/// </summary>
private static void HandleUnknownMessage(string clientId, MessageStyle message)
{
try
{
StandMessageModel unknownModel = JsonConvert.DeserializeObject<StandMessageModel>(message.Message);
string responseMsg = $"收到未知类型消息: {unknownModel.Message}";
// 回复发送者
MessageStyle response = new MessageStyle(MessageTypeEnum.Unknown, clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, responseMsg)));
SendMessage(clientId, JsonConvert.SerializeObject(response));
}
catch (Exception ex)
{
Console.WriteLine($"处理未知消息失败: {ex.Message}");
}
}
发送消息基础方法
csharp
/// <summary>
/// 发送消息
/// </summary>
/// <param name="clientId">目标客户端ID</param>
/// <param name="message">JSON格式的消息字符串</param>
private static void SendMessage(string clientId, string message)
{
try
{
ClientInfo clientInfo;
lock (_lock)
{
if (!_clients.TryGetValue(clientId, out clientInfo))
{
Console.WriteLine($"clientId:{clientId},不存在");
return;
}
}
// 检查Socket是否连接
if (!clientInfo.Socket.Connected)
{
Console.WriteLine($"客户端 {clientId} 已断开,跳过消息发送");
RemoveClient(clientId);
return;
}
// 转为 UTF-8 字节数组
byte[] jsonBytes = Encoding.UTF8.GetBytes(message);
// 获取长度并转换为网络字节序
int length = jsonBytes.Length;
int networkOrderLength = IPAddress.HostToNetworkOrder(length);
byte[] lengthBytes = BitConverter.GetBytes(networkOrderLength);
// 拼接长度+内容
byte[] buffer = new byte[4 + jsonBytes.Length];
Array.Copy(lengthBytes, 0, buffer, 0, 4);
Array.Copy(jsonBytes, 0, buffer, 4, jsonBytes.Length);
// 发送
clientInfo.Socket.Send(buffer);
}
catch (SocketException ex)
{
Console.WriteLine($"向客户端 {clientId} 发送消息失败: 网络异常 {ex.SocketErrorCode} - {ex.Message}");
RemoveClient(clientId);
}
catch (Exception ex)
{
Console.WriteLine($"向客户端 {clientId} 发送消息失败: {ex.Message}");
}
}
在线用户管理
csharp
/// <summary>
/// 获取客户端用户名
/// - 无则返回ID
/// </summary>
private static string GetClientName(string clientId)
{
lock (_lock)
{
if (_clients.ContainsKey(clientId) && !string.IsNullOrEmpty(_clients[clientId].ClientName))
{
return _clients[clientId].ClientName;
}
return clientId;
}
}
/// <summary>
/// 处理客户端的在线列表请求
/// </summary>
/// <param name="clientId">请求的客户端ID</param>
private static void HandleListRequest(string clientId)
{
try
{
lock (_lock)
{
// 构建在线列表数据
OnlineListResponseModel listModel = new OnlineListResponseModel
{
TotalCount = _clients.Count,
Users = _clients.Select(c => new OnlineUserModel
{
ClientId = c.Value.ClientId,
UserName = c.Value.ClientName,
LastActiveTime = c.Value.LastActiveTime
}).ToList()
};
// 构建响应消息
MessageStyle responseMsg = new MessageStyle(
MessageTypeEnum.ListRequest,
clientId,
JsonConvert.SerializeObject(listModel)
);
// 发送给请求的客户端
SendMessage(clientId, JsonConvert.SerializeObject(responseMsg));
}
Console.WriteLine($"客户端 {clientId} 请求在线列表,已返回(共{_clients.Count}个在线用户)");
}
catch (Exception ex)
{
Console.WriteLine($"处理在线列表请求失败: {ex.Message}");
// 发送错误提示给客户端
MessageStyle errorMsg = new MessageStyle(
MessageTypeEnum.Text,
clientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", clientId, "获取在线列表失败: " + ex.Message))
);
SendMessage(clientId, JsonConvert.SerializeObject(errorMsg));
}
}
命令行功能实现
csharp
/// <summary>
/// 处理控制台输入
/// </summary>
private static void HandleConsoleInput()
{
Console.WriteLine("\n服务器命令:");
DeaultConsoleLine();
while (true)
{
try
{
string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
continue;
var parts = input.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0) continue;
string command = parts[0].ToUpper();
string[] args = parts.Length > 1 ? parts.Skip(1).ToArray() : new string[0];
switch (command)
{
case "/EXIT":
Console.WriteLine("正在关闭服务器...");
Environment.Exit(0);
break;
case "/LIST":
Console.WriteLine("当前在线客户端:");
lock (_lock)
{
if (_clients.Count == 0)
{
Console.WriteLine(" 暂无客户端连接");
}
else
{
foreach (var client in _clients)
{
string clientName = string.IsNullOrEmpty(client.Value.ClientName)
? "未设置" : client.Value.ClientName;
Console.WriteLine($" ID: {client.Key} | 用户名: {clientName} | 最后活跃: {client.Value.LastActiveTime:HH:mm:ss}");
}
}
}
break;
case "/MSG":
if (args.Length >= 2)
{
string targetClientId = args[0];
string message = string.Join(" ", args.Skip(1));
// 构建服务器文本消息
MessageStyle serverMsg = new MessageStyle(MessageTypeEnum.Text, targetClientId,
JsonConvert.SerializeObject(new StandMessageModel("SERVER", targetClientId, message)));
SendMessage(targetClientId, JsonConvert.SerializeObject(serverMsg));
Console.WriteLine($"已向 {targetClientId} 发送消息: {message}");
}
else
{
Console.WriteLine("命令格式错误,正确格式: /msg clientId message");
}
break;
case "/BROADCAST":
if (args.Length >= 1)
{
string message = string.Join(" ", args);
MessageStyle broadcastMsg = new MessageStyle(MessageTypeEnum.Broadcast, "SERVER",
JsonConvert.SerializeObject(new StandMessageModel("SERVER", "ALL", message)));
string broadcastJson = JsonConvert.SerializeObject(broadcastMsg);
lock (_lock)
{
foreach (var client in _clients)
{
SendMessage(client.Key, broadcastJson);
}
}
Console.WriteLine($"已广播: {message}");
}
else
{
Console.WriteLine("命令格式错误,正确格式: /broadcast message");
}
break;
case "/HELP":
Console.WriteLine("可用命令:");
DeaultConsoleLine();
break;
default:
Console.WriteLine("未知命令,输入 /help 查看可用命令");
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"处理命令时出错: {ex.Message}");
}
}
}
/// <summary>
/// 默认的命令行提示信息
/// </summary>
private static void DeaultConsoleLine()
{
Console.WriteLine(" /list - 查看在线客户端");
Console.WriteLine(" /msg clientId message - 向指定客户端发送消息");
Console.WriteLine(" /broadcast message - 广播消息");
Console.WriteLine(" /exit - 退出服务器");
Console.WriteLine(" /help - 查看帮助\n");
}