/** *┌──────────────────────────────────────────────────────────────┐ *│ 描 述:HPSocket的TCPServer、TCPClient通讯相关的工具类(类库提供的方法、属性学习) *│ 作 者:执笔小白 *│ 版 本:1.0 *│ 创建时间:2023-6-13 10:40:56 *└──────────────────────────────────────────────────────────────┘ *┌──────────────────────────────────────────────────────────────┐ *│ 命名空间: ZhibiXiaobai *│ 类 名:HPSocket_TCPServerHelper、HPSocket_TcpClientHelper *└──────────────────────────────────────────────────────────────┘ */ using HPSocket; using HPSocket.Tcp; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; namespace csharp_networkprotocol_hpsocket { /// /// HPSocket_TCPServer示例帮助类(类库提供的方法、属性学习) /// System.Net.Sockets类库 /// TcpServer /// public class HPSocket_TCPServerHelper { #region 接收端(服务端) /// /// 侦听来自 TCP 网络客户端的连接 /// public ITcpServer _server = null; #region 创建时的设置项 /// /// 要绑定的服务器地址 /// public string Address { get { return _server.Address; } set { _server.Address = value; } } /// /// 要绑定的服务器端口 /// public ushort Port { get { return _server.Port; } set { _server.Port = value; } } /// /// 设置最大连接数(组件会根据设置值预分配内存,因此需要根据实际情况设置,不宜过大) /// public uint MaxConnectionCount { get { return _server.MaxConnectionCount; } set { _server.MaxConnectionCount = value; } } /// /// 读取或设置是否标记静默时间 /// (设置为 true 时 DisconnectSilenceConnections() 和 GetSilencePeriod()才有效,默认:false) /// public bool IsMarkSilence { get { return _server.IsMarkSilence; } set { _server.IsMarkSilence = value; } } /// /// 获取或设置数据发送策略 /// public SendPolicy SendPolicy { get {return _server.SendPolicy; } set { _server.SendPolicy = value; } } /// /// 获取或设置 OnSend 事件同步策略 /// public OnSendSyncPolicy OnSendSyncPolicy { get { return _server.OnSendSyncPolicy; } set { _server.OnSendSyncPolicy = value; } } /// /// 获取或设置地址重用选项 /// public ReuseAddressPolicy ReuseAddressPolicy { get {return _server.ReuseAddressPolicy; } set { _server.ReuseAddressPolicy = value; } } /// /// 获取或设置是否开启 nodelay 模式 (默认: false, 不开启) /// public bool NoDelay { get {return _server.NoDelay; } set { _server.NoDelay = value; } } #region 心跳检测 /// /// 读取或设置心跳包间隔(毫秒,0 则不发送心跳包) /// public uint KeepAliveTime { get {return _server.KeepAliveTime; } set { _server.KeepAliveTime = value; } } /// /// 读取或设置心跳确认包检测间隔(毫秒,0 不发送心跳包,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线) /// public uint KeepAliveInterval { get { return _server.KeepAliveInterval; } set { _server.KeepAliveInterval = value; } } #endregion 心跳检测 #region 性能优化 /// /// 读取或设置 Accept 预投递数量(根据负载调整设置,Accept 预投递数量越大则支持的并发连接请求越多) /// public uint AcceptSocketCount { get { return _server.AcceptSocketCount; } set { _server.AcceptSocketCount = value; } } /// /// 读取或设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为 1024 的倍数) /// public uint SocketBufferSize { get { return _server.SocketBufferSize; } set { _server.SocketBufferSize = value; } } /// /// 读取或设置监听 Socket 的等候队列大小(根据并发连接数量调整设置) /// public uint SocketListenQueue { get { return _server.SocketListenQueue; } set { _server.SocketListenQueue = value; } } /// /// 读取或设置工作线程数量(通常设置为 2 * CPU + 2) /// public uint WorkerThreadCount { get { return _server.WorkerThreadCount; } set { _server.WorkerThreadCount = value; } } /// /// 读取或设置 Socket 缓存对象锁定时间(毫秒,在锁定期间该 Socket 缓存对象不能被获取使用) /// public uint FreeSocketObjLockTime { get { return _server.FreeSocketObjLockTime; } set { _server.FreeSocketObjLockTime = value; } } /// /// 读取或设置 Socket 缓存池大小(通常设置为平均并发连接数量的 1/3 - 1/2) /// public uint FreeSocketObjPool { get { return _server.FreeSocketObjPool; } set { _server.FreeSocketObjPool = value; } } /// /// 读取或设置内存块缓存池大小(通常设置为 Socket 缓存池大小的 2 - 3 倍) /// public uint FreeBufferObjPool { get { return _server.FreeBufferObjPool; } set { _server.FreeBufferObjPool = value; } } /// /// 读取或设置内存块缓存池大小(通常设置为 Socket 缓存池大小的 2 - 3 倍) /// public uint FreeSocketObjHold { get { return _server.FreeSocketObjHold; } set { _server.FreeSocketObjHold = value; } } /// /// 读取或设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍) /// public uint FreeBufferObjHold { get { return _server.FreeBufferObjHold; } set { _server.FreeBufferObjHold = value; } } #endregion 性能优化 #endregion 创建时的设置项 #region 常用属性 /// /// 获取是否启动 /// public bool HasStarted => _server.HasStarted; /// /// 获取状态 /// public ServiceState State => _server.State; /// /// 获取连接数 /// public uint ConnectionCount => _server.ConnectionCount; /// /// 是否为安全连接(SSL/HTTPS) /// public bool IsSecure => _server.IsSecure; #endregion 常用属性 #region 常用方法 /// /// 启动服务 /// /// public bool Start() => _server.Start(); /// /// 停止服务 /// /// public bool Stop() => _server.Stop(); #region 附加信息 /// /// 获取所有附加数据 /// /// public ConcurrentDictionary GetAllExtra() => _server.GetAllExtra(); /// /// 获取附加数据 /// /// /// /// public T GetExtra(IntPtr connId) => _server.GetExtra(connId); /// /// 获取连接附加数据, 非托管版本, hp-socket自带方法;非特殊需求不要使用这个方法, 请直接使用 GetExtra(); /// /// /// /// public bool NativeGetConnectionExtra(IntPtr connId, out IntPtr extra) => _server.NativeGetConnectionExtra(connId, out extra); /// /// 设置附加数据 /// /// /// /// public bool SetExtra(IntPtr connId, object obj) => _server.SetExtra(connId, obj); /// /// 设置连接附加数据, 非托管版本, hp-socket自带方法;非特殊需求不要使用这个方法, 请直接使用 SetExtra(); /// /// /// /// public bool NativeSetConnectionExtra(IntPtr connId, IntPtr extra) => _server.NativeSetConnectionExtra(connId, extra); /// /// 删除附加数据 /// /// /// public bool RemoveExtra(IntPtr connId) => _server.RemoveExtra(connId); #endregion 附加信息 #region 发送数据 /// /// 发送数据 /// /// 连接id /// 数据源 /// 数据长度 /// public bool Send(IntPtr connId, byte[] bytes, int length) => _server.Send(connId, bytes, length); /// /// 发送数据-指针偏移 /// /// /// /// 对bytes的偏移 /// 发多大 /// public bool Send(IntPtr connId, byte[] bytes, int offset, int length) => _server.Send(connId, bytes, offset, length); /// /// 发送多组数据 向指定连接发送多组数据 TCP - 顺序发送所有数据包 /// /// 连接 ID /// 发送缓冲区数组 /// true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendPackets(IntPtr connId, Wsabuf[] buffers) => SendPackets(connId, buffers); #endregion 发送数据 #region 发送本地小文件 /// /// 发送本地小文件 /// 向指定连接发送 4096 KB 以下的小文件 /// /// /// 文件路径 /// 头部附加数据 /// 尾部附加数据 /// true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(IntPtr connId, string filePath, ref Wsabuf head, ref Wsabuf tail) => _server.SendSmallFile(connId, filePath, ref head, ref tail); /// /// 发送本地小文件 /// 向指定连接发送 4096 KB 以下的小文件 /// /// /// 文件路径 /// 头部附加数据,可以为null /// 尾部附加数据,可以为null /// true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(IntPtr connId, string filePath, byte[] head, byte[] tail) => _server.SendSmallFile(connId, filePath, head, tail); #endregion 发送本地小文件 #region 查询服务器信息 /// /// 获取监听socket的地址信息 /// /// /// /// public bool GetListenAddress(out string ip, out ushort port) => _server.GetListenAddress(out ip, out port); #endregion 查询服务器信息 #region 查询客户端信息 /// /// 获取所有连接 /// /// public List GetAllConnectionIds() => _server.GetAllConnectionIds(); /// /// 获取某客户端连接是否有效 /// /// /// public bool IsConnected(IntPtr connId) => _server.IsConnected(connId); /// /// 获取某客户端连接的接收状态 /// /// /// public ReceiveState GetReceiveState(IntPtr connId) => _server.GetReceiveState(connId); /// /// 获取某个连接的本地地址信息 /// /// /// /// /// public bool GetLocalAddress(IntPtr connId, out string ip, out ushort port) => _server.GetLocalAddress(connId, out ip, out port); /// /// 获取某个连接的远程地址信息 /// /// /// /// /// public bool GetRemoteAddress(IntPtr connId, out string ip, out ushort port) => _server.GetRemoteAddress(connId, out ip, out port); /// /// 获取指定连接的连接时长(毫秒) /// /// /// /// public bool GetConnectPeriod(IntPtr connId, out uint period) => _server.GetConnectPeriod(connId, out period); /// /// 获取某个连接静默时间(毫秒) /// /// /// /// public bool GetSilencePeriod(IntPtr connId, out uint period) => _server.GetSilencePeriod(connId, out period); /// /// 获取连接中未发出数据的长度 /// /// /// /// public bool GetPendingDataLength(IntPtr connId, out int length) => _server.GetPendingDataLength(connId, out length); #endregion 查询客户端信息 #region 断开与客户端的连接 /// /// 断开与某个客户的连接 /// /// /// 是否强制断开 /// public bool Disconnect(IntPtr connId, bool force = true) => _server.Disconnect(connId, force); /// /// 断开超过指定时间的连接 /// /// 毫秒 /// 强制 /// public bool DisconnectLongConnections(uint period, bool force = true) => _server.DisconnectLongConnections(period, force); /// /// 断开超过指定时长的静默连接 /// /// 毫秒 /// 强制 /// public bool DisconnectSilenceConnections(uint period, bool force = true) => _server.DisconnectSilenceConnections(period, force); #endregion 断开与客户端的连接 #region 暂停/唤醒接收某客户端 /// /// 暂停接收 /// /// /// public bool PauseReceive(IntPtr connId) => _server.PauseReceive(connId); /// /// 唤醒接收 /// /// /// public bool ResumeReceive(IntPtr connId) => _server.ResumeReceive(connId); #endregion 暂停/唤醒接收某客户端 #endregion 常用方法 #region 创建侦听的方法与示例方法(后使用Start()开启侦听) /// /// 创建侦听 /// /// 地址 /// 端口 /// public ITcpServer CreateTcpServer() { _server = new TcpServer(); return _server; } /// /// 创建TCP侦听 -示例 /// /// 地址 /// 端口 /// public ITcpServer CreateTcpServerDemo(IPAddress localAddr, int port) { // <1> 创建服务器对象 _server = new TcpServer(); // <2> 设置socket接收长度 _server.SocketBufferSize = 4096; // 4K _server.Address = "192.168.10.11"; _server.Port = 8085; // <3> 绑定事件 //event ServerAcceptEventHandler OnAccept; // TCP连接准备事件 //event ServerHandShakeEventHandler OnHandShake; // TCP握手成功事件 //event ServerPrepareListenEventHandler OnPrepareListen; // 监听事件 //event ServerSendEventHandler OnSend; // 数据包发送事件 //event ServerReceiveEventHandler OnReceive; // 数据包到达事件 //event ServerCloseEventHandler OnClose; // TCP连接关闭事件 //event ServerShutdownEventHandler OnShutdown; // TCP服务器关闭事件 _server.OnAccept += OnAccept; // TCP连接准备事件-使用附加数据处理黏包 _server.OnHandShake += OnHandShake; // TCP握手成功事件 _server.OnPrepareListen += OnPrepareListen; // 监听事件 _server.OnSend += OnSend; // 数据包发送事件 _server.OnReceive += OnReceive; // 数据包接收事件 _server.OnClose += OnClose; // TCP连接关闭事件 _server.OnShutdown += OnShutdown; // TCP服务器关闭事件 return _server; } #region TCP事件 /// /// TCP连接事件(连接前)-使用附加数据处理黏包,不可异步 /// /// 服务器对象 /// 连接ID /// 如果为 TCP 连接,pClient为 SOCKET 句柄;如果为 UDP 连接,pClient为 SOCKADDR 指针; /// private HandleResult OnAccept(IServer sender, IntPtr connId, IntPtr client) { // 获取客户端地址 string ip = string.Empty; ushort port = 0; if (!sender.GetRemoteAddress(connId, out ip, out port)) { return HandleResult.Error; } // 设置附加数据(用来做粘包处理) sender.SetExtra(connId, string.Empty); // 初始化附加信息 //ShowLog(string.Format("TCP客户端接入({0}), ip: {1}, port: {2}", connId, ip, port)); return HandleResult.Ok; } /// /// TCP握手成功事件 /// /// 服务器对象 /// 连接ID /// private HandleResult OnHandShake(IServer sender, IntPtr connId) { // 一般用不到 return HandleResult.Ok; } /// /// 监听事件 /// /// 服务器对象 /// 连接ID /// private HandleResult OnPrepareListen(IServer server, IntPtr intPtr) { //ShowLog(string.Format("TCP服务器开启监听({0}:{1}), listen:{2}", server.Address, server.Port, intPtr)); return HandleResult.Ok; } /// /// 数据包发送事件 /// /// 服务器对象 /// 连接ID /// 数据包 /// private HandleResult OnSend(IServer sender, IntPtr connId, byte[] data) { string ip = string.Empty; ushort port = 0; sender.GetRemoteAddress(connId, out ip, out port); // 获取客户端地址 //ShowLog(string.Format("TCP服务器发送数据[ID:{0},客户端地址:‘{1}:{2}’];数据[长度{3}]:{4}", connId, ip ?? "未找到IP", port, data.Length, Encoding.ASCII.GetString(data))); return HandleResult.Ok; } /// /// 数据包接收事件 /// /// 服务器对象 /// 连接ID /// 数据包 /// private HandleResult OnReceive(IServer sender, IntPtr connId, byte[] data) { // <1> 获取客户端地址 string ip = string.Empty; ushort port = 0; if (!sender.GetRemoteAddress(connId, out ip, out port)) { return HandleResult.Error; } // <2> 获取附加数据对象 var extraDataStr = sender.GetExtra(connId); if (extraDataStr == null) { return HandleResult.Error; } // <3> 将接收数据转换成字符串 string msg = Encoding.ASCII.GetString(data); extraDataStr += msg; // 添加数据到缓存_不合格的数据添加到缓存区(用于粘包、拆包) // <4> 显示信息 //ShowLog(string.Format("TCP服务器接收客户端[ID:{0},IP:‘{1}:{2}’]的信息;数据:[长度{3}]: {4}", connId, ip, port, data.Length, msg)); // <5> 处理数据 HandleResult result; string _endsWith = "\r\n"; // TCP包的数据结束符 while (true) { int index = extraDataStr.IndexOf(_endsWith); if (index == -1) // 数据接收不完整,忽略后等待下一次接收 { result = HandleResult.Ignore; break; } else { string validMsg = extraDataStr.Remove(0, index); // <6> 业务处理-异步(validMsg内容解析时的格式校验属于业务范畴) // <7> 移除已取出数据 extraDataStr = extraDataStr.Remove(0, index + _endsWith.Length); } } // <8> 保存PacketData数据 if (extraDataStr.Length > _server.SocketBufferSize) // 可选-控制长度为4096(注:实际所占控件大小>4096) { int length_Delete = extraDataStr.Length - Convert.ToInt32(_server.SocketBufferSize); extraDataStr = extraDataStr.Remove(0, length_Delete); // 清除长度超标数据 } sender.SetExtra(connId, extraDataStr); // 初始化附加信息 return result; } /// /// TCP连接关闭事件 /// /// 服务器对象 /// 连接ID /// 关闭的类型 /// 错误时的错误代码 /// private HandleResult OnClose(IServer sender, IntPtr connId, SocketOperation socketOperation, int errorCode) { // <1> 获取客户端地址 string ip = string.Empty; ushort port = 0; if (!sender.GetRemoteAddress(connId, out ip, out port)) { return HandleResult.Ignore; } // <2> 释放附加数据 if (sender.GetExtra(connId) != null) { sender.RemoveExtra(connId); // 删除附加数据 } // <3> 显示信息 //ShowLog(string.Format("TCP客户端连接断开(ID {0},地址 {1}:{2}), 断开类型: {3},错误代码: {4}", connId, ip, port, socketOperation.ToString(), errorCode)); return HandleResult.Ok; } /// /// TCP服务器关闭事件 /// /// 服务器对象 /// private HandleResult OnShutdown(IServer sender) { //ShowLog(string.Format("TCP服务器关闭({0}:{1})", sender.Address, sender.Port)); return HandleResult.Ok; } #endregion TCP事件 #endregion 创建侦听的方法与示例方法(后使用Start()开启侦听) #endregion 接收端(服务端) } /// /// HPSocket_TcpClient示例帮助类(示例学习) /// System.Net.Sockets类库 /// TcpClient /// public class HPSocket_TcpClientHelper { #region 发送端(客户端) /// /// TCP客户端 /// public ITcpClient _client = new TcpClient(); /// /// 本地绑定到哪个ip /// public string BindAddress { get { return _client.BindAddress; } set { _client.BindAddress = value; } } /// /// 本地绑定到哪个端口 /// public ushort BindPort { get { return _client.BindPort; } set { _client.BindPort = value; } } /// /// 远程服务器地址 /// public string Address { get { return _client.Address; } set { _client.Address = value; } } /// /// 远程服务器端口 /// public ushort Port { get { return _client.Port; } set { _client.Port = value; } } #region 创建时的设置项 /// /// 是否异步连接,默认为真 /// public bool Async { get { return _client.Async; } set { _client.Async = value; } } /// /// 读取或设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为:(N * 1024) - sizeof(TBufferObj)) /// public uint SocketBufferSize { get { return _client.SocketBufferSize; } set { _client.SocketBufferSize = value; } } /// /// 连接超时时间, 默认操作系统默认值 /// 单位: 毫秒 /// 异常:T:System.InvalidOperationException:同步连接、.NET Framework2.0以及设置小于100毫秒会引发此异常 /// public int ConnectionTimeout { get { return _client.ConnectionTimeout; } set { _client.ConnectionTimeout = value; } } /// /// 附加数据 /// 赋值:client.ExtraData = myObj; /// 取值:var data = ExtraData as MyData; /// public object ExtraData { get { return _client.ExtraData; } set { _client.ExtraData = value; } } /// /// 获取或设置是否开启 nodelay 模式 (默认: false, 不开启) /// public bool NoDelay { get { return _client.NoDelay; } set { _client.NoDelay = value; } } #region 心跳 /// /// 读取或设置心跳包间隔(毫秒,0 则不发送心跳包) /// public uint KeepAliveTime { get { return _client.KeepAliveTime; } set { _client.KeepAliveTime = value; } } /// /// 读取或设置心跳确认包检测间隔(毫秒,0 不发送心跳包,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线) /// public uint KeepAliveInterval { get { return _client.KeepAliveInterval; } set { _client.KeepAliveInterval = value; } } #endregion 心跳 /// /// 获取或设置暂停接收状态,设置状态时,不允许设置为ReceiveState.Unknown, /// public ReceiveState PauseReceive { get { return _client.PauseReceive; } set { _client.PauseReceive = value; } } /// /// 获取或设置地址重用选项 /// public ReuseAddressPolicy ReuseAddressPolicy { get { return _client.ReuseAddressPolicy; } set { _client.ReuseAddressPolicy = value; } } /// /// 代理列表 /// public List ProxyList { get { return _client.ProxyList; } set { _client.ProxyList = value; } } #region 性能优化 /// /// 读取或设置内存块缓存池大小(通常设置为 -> PUSH 模型:5 - 10;PULL 模型:10 - 20 ) /// public uint FreeBufferPoolSize { get { return _client.FreeBufferPoolSize; } set { _client.FreeBufferPoolSize = value; } } /// /// 读取或设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍) /// public uint FreeBufferPoolHold { get { return _client.FreeBufferPoolHold; } set { _client.FreeBufferPoolHold = value; } } #endregion 性能优化 #endregion 创建时的设置项 #region 常用属性 /// /// 检查通信组件是否已启动 /// public bool HasStarted => _client.HasStarted; /// /// 状态 /// public ServiceState State => _client.State; /// /// 是否已连接 /// public bool IsConnected => _client.IsConnected; /// /// 是否为安全连接(SSL/HTTPS) /// public bool IsSecure => _client.IsSecure; /// /// 获取该组件对象的连接Id /// public IntPtr ConnectionId => _client.ConnectionId; #endregion 常用属性 #region 常用方法 #region 启动并连接到服务器 /// /// 启动通讯组件并连接到服务器 /// /// public bool Connect() => _client.Connect(); /// /// 启动通讯组件并连接到服务器 /// /// 远程服务器地址 /// 远程服务器端口 /// public bool Connect(string address, ushort port) => _client.Connect(address, port); #endregion 启动并连接到服务器 /// /// 停止服务 /// /// public bool Stop() => _client.Stop(); #region 发送数据 /// /// 发送数据 /// /// 数据包 /// 数据包长度 /// public bool Send(byte[] bytes, int length) => _client.Send(bytes, length); /// /// 发送数据 /// /// 数据包 /// 针对bytes的偏移 /// 数据包长度 /// public bool Send(byte[] bytes, int offset, int length) => _client.Send(bytes, offset, length); /// /// 发送多组数据 向指定连接发送多组数据 TCP - 顺序发送所有数据包 /// /// 发送缓冲区数组 /// 发送缓冲区数目 /// true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendPackets(Wsabuf[] buffers, int count) => _client.SendPackets(buffers, count); #endregion 发送数据 #region 发送本地小文件 /// /// 发送本地小文件 // 向指定连接发送 4096 KB 以下的小文件 /// /// 文件路径 /// 头部附加数据 /// 尾部附加数据 /// true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(string filePath, ref Wsabuf head, ref Wsabuf tail) => _client.SendSmallFile(filePath, ref head, ref tail); /// /// 发送本地小文件 /// 向指定连接发送 4096 KB 以下的小文件 /// /// 文件路径 /// 头部附加数据,可以为null /// 尾部附加数据,可以为null /// true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(string filePath, byte[] head, byte[] tail) => _client.SendSmallFile(filePath, head, tail); #endregion 发送本地小文件 #region 查询连接信息 /// /// 获取监听socket的地址信息 /// /// /// /// public bool GetListenAddress(out string host, out ushort port) => _client.GetListenAddress(out host, out port); /// /// 获取连接的远程主机信息 /// /// /// /// public bool GetRemoteHost(out string host, out ushort port) => _client.GetRemoteHost(out host, out port); /// /// 获取连接中未发出数据的长度 /// /// /// public bool GetPendingDataLength(out int length) => _client.GetPendingDataLength(out length); #endregion 查询连接信息 /// /// 等待代理结果 /// /// 连接成功返回true, 连接失败返回false //public async Task WaitProxyAsync() => await _client.WaitProxyAsync(); #endregion 常用方法 #region 创建TCPClient并连接示例 /// /// 创建TCP侦听 -示例 /// /// 地址 /// 端口 /// public ITcpClient CreateTcpServerDemo(string localAddr, int port) { // <2>配置TCPServer的参数 _client.Address = localAddr; // IP _client.Port = (ushort)port; // 端口 _client.SocketBufferSize = 4096; // 缓存4K //_client.BindAddress = ""; // 本地绑定到哪个ip //_client.BindPort = 0; // 本地绑定到哪个端口 // <3> 绑定事件 //event ClientPrepareConnectEventHandler OnPrepareConnect; // 准备连接了事件 //event ClientConnectEventHandler OnConnect; // 连接事件 //event ClientHandShakeEventHandler OnHandShake; // TCP握手成功事件 //event ClientSendEventHandler OnSend; // 数据包发送事件 //event ClientReceiveEventHandler OnReceive; // 数据包到达事件 //event ClientCloseEventHandler OnClose; // TCP连接关闭事件 _client.OnPrepareConnect += OnPrepareConnect; // 准备连接了事件 _client.OnConnect += OnConnect; // 连接事件 _client.OnHandShake += OnHandShake; // TCP握手成功事件 _client.OnSend += OnSend; // 数据包发送事件 _client.OnReceive += OnReceive; // 数据包到达事件 _client.OnClose += OnClose; // TCP连接关闭事件 //_client.Connect(); // 连接 return _client; } #region 事件 /// /// 准备连接了事件 /// /// 客户端 /// 客户端Id /// private HandleResult OnPrepareConnect(IClient sender, IntPtr socket) { sender.ExtraData = string.Empty; // 设置附加数据(用来做粘包处理) return HandleResult.Ok; } /// /// 连接事件 /// /// 客户端 /// private HandleResult OnConnect(IClient sender) { //ShowLog(string.Format("TCP客户端([{0}]{1}:{2})接入TCP服务器{3}:{4}", sender.ConnectionId, sender.BindAddress, sender.BindPort, sender.Address, sender.Port)); return HandleResult.Ok; } /// /// TCP握手成功事件 /// /// 客户端 /// private HandleResult OnHandShake(IClient sender) { // 一般用不到 return HandleResult.Ok; } /// /// 数据包发送事件 /// /// 客户端 /// 数据 /// private HandleResult OnSend(IClient sender, byte[] data) { //ShowLog(string.Format("TCP客户端发送数据到TCP服务器[{0}]{1}:{2};数据内容[长度{3}]:{4}", sender.ConnectionId, sender.Address, sender.Port, data.Length, Encoding.UTF8.GetString(data))); return HandleResult.Ok; } /// /// 数据包到达事件 /// /// 客户端 /// 数据 /// private HandleResult OnReceive(IClient sender, byte[] data) { // <1> 获取附加数据对象 if (!(sender.ExtraData is string)) { return HandleResult.Error; } string extraDataStr = (string)sender.ExtraData; // <2> 将接收数据转换成字符串 string msg = Encoding.UTF8.GetString(data); extraDataStr += msg; // 添加数据到缓存_不合格的数据添加到缓存区(用于粘包、拆包) // <3> 显示信息 //ShowLog(string.Format("TCP客户端接收到TCP服务器[ID:{0},IP:‘{1}:{2}’]的信息;数据:[长度{3}]: {4}", sender.ConnectionId, sender.Address, sender.Port, data.Length, msg)); // <4> 处理数据 HandleResult result; string _endsWith = "\r\n"; while (true) { int index = extraDataStr.IndexOf(_endsWith); if (index == -1) // 数据接收不完整,忽略后等待下一次接收 { result = HandleResult.Ignore; break; } else { string validMsg = extraDataStr.Remove(0, index); // <6> 业务处理-异步(validMsg内容解析时的格式校验属于业务范畴) // <7> 移除已取出数据 extraDataStr = extraDataStr.Remove(0, index + _endsWith.Length); } } // <5> 保存PacketData数据 if (extraDataStr.Length > _client.SocketBufferSize) // 可选-控制长度为4096(注:实际所占空间大小>4096) { int length_Delete = extraDataStr.Length - Convert.ToInt32(_client.SocketBufferSize); extraDataStr = extraDataStr.Remove(0, length_Delete); // 清除长度超标数据 } sender.ExtraData = extraDataStr; // 初始化附加信息 return result; } /// /// TCP连接关闭事件 /// /// 客户端 /// 关闭类型 /// 错误代码 /// private HandleResult OnClose(IClient sender, SocketOperation socketOperation, int errorCode) { sender.ExtraData = null; // 删除附加数据 //ShowLog(string.Format("TCP客户端断开与TCP服务器[{0}] {1}:{2}的连接, 断开类型: {3},错误代码: {4}", sender.ConnectionId, sender.Address, sender.Port, socketOperation.ToString(), errorCode)); return HandleResult.Ok; } #endregion 事件 #endregion 创建TCPClient并连接示例 #endregion 发送端(客户端) } }