CSharp Socket学习 - 需求分析与创建项目
使用控制台实现服务端和客户端,操作使用命令实现。不使用数据库,尽量不使用第三方插件。
项目初始化
服务端项目:.NET Framework 控制台应用程序

修改项目名称和解决方案 名称
项目名称:Socket_Study_Server
解决方案名称:Socket_Study_OnClieChat

客户端项目:.NET Framework 控制台应用程序
客户端名:Socket_Study_Client
解决方案名称:Socket_Study_OnClieChat


数据结构项目:.NET Framework 类库
名称:Socket_Study_Model
解决方案名称:Socket_Study_OnClieChat

最后创建完毕

第三方引用:Newtonsoft.Json (JSON序列化库)

功能设计
客户端连接
• 客户端标识:使用GUID生成唯一客户端ID
csharp
/// <summary>
/// 生成客户端ID
/// </summary>
static string GenerateClientId()
{
lock (_lock)
{
return $"CLIENT_{Guid.NewGuid():N}";
}
}
• 客户端信息存储:ClientInfo类存储Socket、ID、用户名、活跃时间
csharp
using System;
using System.Net.Sockets;
namespace Socket_Study_Pro
{
/// <summary>
/// 客户端信息类
/// </summary>
public class ClientInfo
{
/// <summary>
/// 客户端id
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// 客户端的用户名
/// </summary>
public string ClientName { get; set; }
/// <summary>
/// socket
/// </summary>
public Socket Socket { get; set; }
/// <summary>
/// 最后上线时间
/// </summary>
public DateTime LastActiveTime { get; set; }
/// <summary>
/// 是否链接
/// </summary>
public bool IsConnected { get; set; }
}
}
• 线程安全的字典:使用锁机制管理客户端列表
/// <summary>
/// 客户端列表
/// </summary>
private static Dictionary<string, ClientInfo> _clients = new Dictionary<string, ClientInfo>();
/// <summary>
/// 线程锁
/// </summary>
private static object _lock = new object();
• 连接状态维护:IsConnected标志位跟踪连接状态
消息协议设计
• 消息头格式:4字节长度标识 + JSON消息体,这样后期也可以发送图片或者文件,4字节长度标识可以发送4GB大小的数据
0xFF 0xFF 0xFF 0xFF {JSON}
• 消息类型:Welcome, Text, Broadcast, PrivateMsg, SetUserName, Heartbeat, ListRequest, Unknown
csharp
namespace Socket_Study_Entity
{
/// <summary>
/// 消息类型枚举
/// </summary>
public enum MessageTypeEnum
{
/// <summary>
/// 未知类型
/// </summary>
Unknown = 0,
/// <summary>
/// 欢迎消息
/// </summary>
Welcome = 1,
/// <summary>
/// 普通文本消息
/// </summary>
Text = 2,
/// <summary>
/// 广播消息
/// </summary>
Broadcast = 3,
/// <summary>
/// 心跳消息
/// </summary>
Heartbeat = 4,
/// <summary>
/// 隐私消息
/// </summary>
PrivateMsg = 5,
/// <summary>
/// 设置自己的用户名
/// </summary>
SetUserName = 6,
/// <summary>
/// 获取用户列表
/// </summary>
ListRequest = 7,
}
}
消息处理
先创建可能用到的方法,后续进行补充。
• 欢迎消息处理:连接时发送欢迎消息和客户端ID, private static void SendWelcomeMessage(string clientId)
• 文本消息处理:普通文本消息的收发 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)
• 心跳检测:保持连接活跃,检测客户端在线状态,private static void HandleHeartbeatMessage(string clientId, MessageStyle message)
• 在线列表查询:客户端可查询当前所有在线用户,private static void HandleListRequest(string clientId)
• 消息格式验证:JSON反序列化验证和异常处理,private static void HandleUnknownMessage(string clientId, MessageStyle message)
消息传输
• 消息分包处理:基于长度的消息完整接收
• 缓冲区管理:复用缓冲区减少内存分配
• 流式读取:使用MemoryStream累积消息数据
• 可靠发送:带长度信息的可靠消息发送
• 连接状态检测:发送前检查Socket连接状态
客户端会话
• 客户端心跳:通过心跳消息维持连接
• 活跃时间更新:每次消息收发更新最后活跃时间
服务器控制台
• 命令行:控制台输入命令解析
• 在线客户端列表:查看所有连接的客户端信息
• 定向消息发送:服务器向指定客户端发送消息
• 服务器广播:服务器向所有客户端广播消息
• 服务器关闭:安全关闭服务器的命令
• 帮助:显示可用命令列表
数据结构
消息模型,需要在Socket_Study_Model 中创建
• MessageStyle:消息基础结构,所有的消息都要被包裹,赋值给message字段
csharp
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Socket_Study_Model
{
/// <summary>
/// 消息基础格式
/// </summary>
public class MessageStyle
{
/// <summary>
/// 消息类型
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public MessageTypeEnum Type { get; set; } = MessageTypeEnum.Unknown;
/// <summary>
/// 发送方的clientid
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; }
public MessageStyle(MessageTypeEnum messageTypeEnum, string clientId, string message)
{
Type = messageTypeEnum;
ClientId = clientId;
Message = message;
}
}
}
• StandMessageModel:标准消息模型,通用的消息模型
csharp
using System;
namespace Socket_Study_Model
{
/// <summary>
/// 标准消息模型
/// </summary>
[Serializable]
public class StandMessageModel
{
/// <summary>
/// 发送方clientid
/// </summary>
public string SenderClientId;
/// <summary>
/// 发送方id
/// </summary>
public string SenderName;
/// <summary>
/// 目标clientid
/// </summary>
public string TargetClientID;
/// <summary>
/// 发送方名称
/// </summary>
public string TargetName;
/// <summary>
/// 消息
/// </summary>
public string Message;
/// <summary>
/// 构建消息
/// </summary>
/// <param name="senderClientId">发送方id</param>
/// <param name="targetClientID">目标id</param>
/// <param name="message">消息内容</param>
public StandMessageModel(string senderClientId, string targetClientID, string message)
{
SenderClientId = senderClientId;
TargetClientID = targetClientID;
Message = message;
}
}
}
• WelComMessageModel:欢迎消息模型
csharp
using System;
namespace Socket_Study_Entity
{
/// <summary>
/// 欢迎消息的model
/// </summary>
[Serializable]
public class WelComMessageModel
{
/// <summary>
/// 欢迎消息
/// </summary>
public string Message;
public WelComMessageModel(string message)
{
Message = message;
}
}
}
• OnlineListResponseModel:在线列表响应模型,OnlineUserModel:在线用户信息模型
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Socket_Study_Model
{
/// <summary>
/// 在线用户信息模型
/// </summary>
public class OnlineUserModel
{
/// <summary>
/// 客户端ID
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// 用户名(未设置则显示"未命名")
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 最后活跃时间
/// </summary>
public DateTime LastActiveTime { get; set; }
}
/// <summary>
/// 在线列表响应模型
/// </summary>
public class OnlineListResponseModel
{
/// <summary>
/// 在线用户总数
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 在线用户列表
/// </summary>
public List<OnlineUserModel> Users { get; set; } = new List<OnlineUserModel>();
}
}
客户端信息
• ClientInfo:包含Socket、ID、用户名、最后活跃时间、连接状态
• 线程安全存储:使用锁保护的字典存储客户端信息
网络异常处理
• Socket异常:连接重置、连接中止、超时等
• IO异常:读写操作异常
• 序列化异常:JSON格式错误处理
• 线程安全异常:并发访问控制