一、序言

C#-网络通讯框架(一)-HPSocket_System

1、HPSocket.Net介绍

(1)HPSocket是一套高性能TCP/UDP/HTTP通信框架(适用于Windows、Linux和OSX的HP Socket),包括服务器、客户端和代理组件。

(2)它被广泛应用于各种场景中的TCP/UDP/HTTP通信应用。它提供了C/C++、C#、Delphi、Java、Python等编程语言接口。HP Socket完全封装了通信层,应用程序不需要关注通信层的任何细节。

(3)HPSocket支持的平台:Windows 7+x86/x64、Linux内核2.6.32+x86/x64、mac操作系统10.12+x64、树莓派4B。

(4)HPSocket除了TCP/UDP/HTTP协议,还支持HTTP、WebSocket等协议。

(5)HP-Socket 在设计上充分考虑性能、使用场景、复杂性和易用性等因素,作出以下几点设计决策: Client 组件:基于 Event Select 通信模型,在单独线程中执行通信操作,避免与主线程或其他线程相互干扰。每个组件对象管理一个 Socket 连接。 Server 组件:基于 IOCP 通信模型,并结合缓存池、私有堆(Private Heap)等技术,支持超大规模连接,在高并发场景下实现高效内存管理。 Agent 组件:对于代理服务器或中转服务器等应用场景,服务器自身也作为客户端向其它服务器发起大规模连接,一个 Agent 组件对象同时可管理多个 Socket 连接;Agent 组件与 Server 组件采用相同的技术架构,可以用作代理服务器或中转服务器的客户端部件。

(6)官方示例地址: https://gitee.com/int2e/HPSocket.Net/tree/develop/demo

2、HPSocket.Net相对于System.Net.Sockets具有的优势

(1)HPSocket提供了更多的协议支持,如TCP、UDP、HTTP、WebSocket等,而System.Net.Sockets只支持TCP、UDP等基本协议。

(2)HPSocket的性能更高,可以处理更多的并发连接,支持更高的吞吐量和更低的延迟。

(3)HPSocket提供了更多的高级功能,如SSL加密、压缩、心跳包等,而System.Net.Sockets只提供了基本的网络通信功能。

(4)HPSocket比System.Net.Sockets跨平台支持的早,兼容性或许更好。

(5)HPSocket提供了好多的扩展功能,比如:TCP协议处理分包、组包、粘包、维护连接列表等,UDP协议处理丢包、乱序等,可设置Socket通讯的线程、缓存等性能优化相关的配置。

(6)HPSocket作者对TCPServer、TCPClient的事件回调函数做了线程优化,不需要我们再考虑这些问题。

3、与HPSocket差不多的Socket框架

(1)DotNetty(博客有讲)

(2)SuperSocket(可选)

二、基础使用

  代码地址: csharp_networkprotocol_hpsocket

  视频演示: C#-网络通讯框架_HPSocket TCP演示

C#-网络通讯框架(一)-HPSocket_System_02

  • TCP基础组件:
  • ITcpServer
  • ITcpAgent
  • ITcpClient
  • ITcpPullServer
  • ITcpPullAgent
  • ITcpPullClient
  • ITcpPackServer(重点;解决TCP粘包问题,需配合ITcpPackClient使用)
  • ITcpPackAgent(重点;Multi-Client组件,与Server组件采用相同的技术架构。可同时建立和高效处理大规模Socket连接。适用于代理,转发,网关等需要建立大量客户端连接的场景)
  • ITcpPackClient(重点;解决TCP粘包问题,需配合ITcpPackServer使用)
  • UDP
  • IUdpServer
  • IUdpClient
  • IUdpCast
  • IUdpArqServer(重点;可靠UDP)
  • IUdpArqClient(重点;可靠UDP)
  • IUdpNode
  • SSL
  • ISslServer
  • ISslAgent
  • ISslClient
  • ISslPullServer
  • ISslPullAgent
  • ISslPullClient
  • ISslPackServer
  • ISslPackAgent
  • ISslPackClient
  • HTTP
  • IHttpServer
  • IHttpsServer
  • IHttpAgent
  • IHttpsAgent
  • IHttpClient
  • IHttpsClient
  • IHttpSyncClient
  • IHttpsSyncClient
  • ThreadPool(HPSocket.Thread.ThreadPool)
  • ThreadPool

1、TCP

  这里我演示TCPServerTCPClient基础类的使用,代码地址: csharp_networkprotocol_hpsocket;在平时使用中,推荐下面两种方案:

  • ITcpServer<TRequestBodyType>ITcpClient<TRequestBodyType>ITcpAgent<TRequestBodyType>”+“TCP数据接收适配器组件(BinaryDataReceiveAdapter)”;
  • ITcpPackServerITcpPackClientITcpPackAgent”;
(1)TcpServer使用示例

C#-网络通讯框架(一)-HPSocket_Text_03

 TCPServerOld.Designer.cs

查看代码

namespace csharp_networkprotocol_hpsocket
{
    partial class TCPServerOld
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            label3 = new Label();
            txtPort = new TextBox();
            panel1 = new Panel();
            btnOpenCloseTCP = new Button();
            btnSendMsg = new Button();
            txtMsg = new TextBox();
            txtIPAddress = new TextBox();
            label4 = new Label();
            rTxtInfo = new RichTextBox();
            panel1.SuspendLayout();
            SuspendLayout();
            // 
            // label3
            // 
            label3.AutoSize = true;
            label3.Location = new Point(10, 48);
            label3.Margin = new Padding(2, 0, 2, 0);
            label3.Name = "label3";
            label3.Size = new Size(44, 17);
            label3.TabIndex = 33;
            label3.Text = "消息:";
            // 
            // txtPort
            // 
            txtPort.Location = new Point(228, 11);
            txtPort.Name = "txtPort";
            txtPort.Size = new Size(77, 23);
            txtPort.TabIndex = 32;
            txtPort.Text = "8085";
            // 
            // panel1
            // 
            panel1.Controls.Add(btnOpenCloseTCP);
            panel1.Location = new Point(449, 11);
            panel1.Margin = new Padding(2, 3, 2, 3);
            panel1.Name = "panel1";
            panel1.Size = new Size(166, 57);
            panel1.TabIndex = 30;
            // 
            // btnOpenCloseTCP
            // 
            btnOpenCloseTCP.Location = new Point(16, 9);
            btnOpenCloseTCP.Margin = new Padding(2, 3, 2, 3);
            btnOpenCloseTCP.Name = "btnOpenCloseTCP";
            btnOpenCloseTCP.Size = new Size(134, 38);
            btnOpenCloseTCP.TabIndex = 10;
            btnOpenCloseTCP.Text = "开启监听";
            btnOpenCloseTCP.UseVisualStyleBackColor = true;
            btnOpenCloseTCP.Click += btnOpenCloseTCP_Click;
            // 
            // btnSendMsg
            // 
            btnSendMsg.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
            btnSendMsg.Location = new Point(330, 20);
            btnSendMsg.Margin = new Padding(2, 3, 2, 3);
            btnSendMsg.Name = "btnSendMsg";
            btnSendMsg.Size = new Size(73, 38);
            btnSendMsg.TabIndex = 29;
            btnSendMsg.Text = "广播";
            btnSendMsg.UseVisualStyleBackColor = true;
            btnSendMsg.Click += btnSendMsg_Click;
            // 
            // txtMsg
            // 
            txtMsg.Location = new Point(70, 45);
            txtMsg.Margin = new Padding(2, 3, 2, 3);
            txtMsg.Name = "txtMsg";
            txtMsg.Size = new Size(235, 23);
            txtMsg.TabIndex = 28;
            // 
            // txtIPAddress
            // 
            txtIPAddress.Location = new Point(70, 11);
            txtIPAddress.Margin = new Padding(2, 3, 2, 3);
            txtIPAddress.Name = "txtIPAddress";
            txtIPAddress.Size = new Size(153, 23);
            txtIPAddress.TabIndex = 27;
            txtIPAddress.Text = "127.0.0.1";
            // 
            // label4
            // 
            label4.AutoSize = true;
            label4.Location = new Point(10, 14);
            label4.Margin = new Padding(2, 0, 2, 0);
            label4.Name = "label4";
            label4.Size = new Size(54, 17);
            label4.TabIndex = 26;
            label4.Text = "TCP地址";
            // 
            // rTxtInfo
            // 
            rTxtInfo.Location = new Point(10, 77);
            rTxtInfo.Name = "rTxtInfo";
            rTxtInfo.Size = new Size(605, 293);
            rTxtInfo.TabIndex = 34;
            rTxtInfo.Text = "";
            // 
            // TCPServerOld
            // 
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(622, 382);
            Controls.Add(rTxtInfo);
            Controls.Add(label3);
            Controls.Add(txtPort);
            Controls.Add(panel1);
            Controls.Add(btnSendMsg);
            Controls.Add(txtMsg);
            Controls.Add(txtIPAddress);
            Controls.Add(label4);
            MaximizeBox = false;
            Name = "TCPServerOld";
            Text = "TCP服务端_Old";
            Load += TCPServerOld_Load;
            panel1.ResumeLayout(false);
            ResumeLayout(false);
            PerformLayout();
        }

        #endregion

        private Label label3;
        private TextBox txtPort;
        private Panel panel1;
        private Button btnOpenCloseTCP;
        private Button btnSendMsg;
        private TextBox txtMsg;
        private TextBox txtIPAddress;
        private Label label4;
        private RichTextBox rTxtInfo;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.

 TCPServerOld.cs

using HPSocket;
using HPSocket.Base;
using HPSocket.Tcp;
using Newtonsoft.Json;
using System;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace csharp_networkprotocol_hpsocket
{
    public partial class TCPServerOld : Form
    {
        /// <summary>
        /// HPSocket_TCPServer示例帮助类(示例学习)
        /// </summary>
        public HPSocket_TCPServerHelper _HPSocket_TCPServerHelper = new HPSocket_TCPServerHelper();

        /// <summary>
        /// 包数据结束符
        /// </summary>
        private readonly string _endsWith = "\r\n";

        public TCPServerOld()
        {
            InitializeComponent();
        }
        private void TCPServerOld_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 打开或关闭TCP
        /// </summary>
        private async void btnOpenCloseTCP_Click(object sender, EventArgs e)
        {
            try
            {
                if (btnOpenCloseTCP.Text == "开启监听")  // 开启监听
                {
                    // 检查地址
                    if (!CheckServerUrl())
                    {
                        return;
                    }

                    string localAddr = txtIPAddress.Text.Trim();  //IPAddress localAddr = IPAddress.Parse(txtIPAddress.Text.Trim());  // IP
                    int port = int.Parse(txtPort.Text);  // 端口

                    if (_HPSocket_TCPServerHelper._server == null || _HPSocket_TCPServerHelper.State != ServiceState.Started)
                    {
                        // <1>创建TCPServer对象
                        _HPSocket_TCPServerHelper.CreateTcpServer();  // 创建TcpServer
                        // <2>配置TCPServer的参数
                        _HPSocket_TCPServerHelper.Address = localAddr;      // IP
                        _HPSocket_TCPServerHelper.Port = (ushort)port;      // 端口
                        _HPSocket_TCPServerHelper.SocketBufferSize = 4096;  // 缓存4K
                        // <3>配置TCPServer的回调事件
                        _HPSocket_TCPServerHelper._server.OnAccept += OnAccept;                // TCP连接准备事件-使用附加数据处理黏包
                        _HPSocket_TCPServerHelper._server.OnHandShake += OnHandShake;          // TCP握手成功事件
                        _HPSocket_TCPServerHelper._server.OnPrepareListen += OnPrepareListen;  // 监听事件
                        _HPSocket_TCPServerHelper._server.OnSend += OnSend;                    // 数据包发送事件
                        _HPSocket_TCPServerHelper._server.OnReceive += OnReceive;              // 数据包接收事件
                        _HPSocket_TCPServerHelper._server.OnClose += OnClose;                  // TCP连接关闭事件
                        _HPSocket_TCPServerHelper._server.OnShutdown += OnShutdown;            // TCP服务器关闭事件
                    }
                    // <4>开启TCPServer服务
                    if (_HPSocket_TCPServerHelper.Start())
                    {
                        ShowBtnOpenCloseTCP(true, "关闭监听");
                    }
                    else
                    {
                        MessageBox.Show("开启监听失败!", "提示");
                    }
                }
                else  // 关闭监听
                {
                    _HPSocket_TCPServerHelper.Stop();
                    _HPSocket_TCPServerHelper._server.OnAccept -= OnAccept;                // TCP连接准备事件-使用附加数据处理黏包
                    _HPSocket_TCPServerHelper._server.OnHandShake -= OnHandShake;          // TCP握手成功事件
                    _HPSocket_TCPServerHelper._server.OnPrepareListen -= OnPrepareListen;  // 监听事件
                    _HPSocket_TCPServerHelper._server.OnSend -= OnSend;                    // 数据包发送事件
                    _HPSocket_TCPServerHelper._server.OnReceive -= OnReceive;              // 数据包接收事件
                    _HPSocket_TCPServerHelper._server.OnClose -= OnClose;                  // TCP连接关闭事件
                    _HPSocket_TCPServerHelper._server.OnShutdown -= OnShutdown;            // TCP服务器关闭事件

                    ShowBtnOpenCloseTCP(false, "开启监听");
                }
            }
            catch (Exception ex)
            {
                ShowBtnOpenCloseTCP(false, "开启监听");
                ShowLog($"开启/关闭监听失败,错误信息: {ex.Message}");
            }
        }

        /// <summary>
        /// 广播按钮
        /// </summary>
        private async void btnSendMsg_Click(object sender, EventArgs e)
        {
            try
            {
                // 检查地址
                if (!CheckServerUrl())
                {
                    return;
                }

                string hostname = txtIPAddress.Text;
                int port = int.Parse(txtPort.Text);
                string sendMsg = txtMsg.Text;  // 
                if (string.IsNullOrEmpty(sendMsg))
                {
                    ShowLog("发送信息不可为空!");
                    return;
                }

                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg + _endsWith);
                int length = bytes.Length;

                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendLine(string.Concat("TCPServer服务器广播了内容:“", sendMsg, "”"));

                List<IntPtr> connIds = _HPSocket_TCPServerHelper.GetAllConnectionIds();
                stringBuilder.AppendLine($"  客户端个数为{connIds.Count};客户端接收结果如下:");
                foreach (IntPtr connId in connIds)
                {
                    try
                    {
                        if (!_HPSocket_TCPServerHelper.GetLocalAddress(connId, out string ip, out ushort port1))
                        {
                            stringBuilder.AppendLine(string.Concat($"    客户端[{connId}]", ",接收结果:失败!连接已断开!"));
                            continue;
                        }
                        bool resultData_TCP = _HPSocket_TCPServerHelper.Send(connId, bytes, length);  // 连接并发送
                        //stringBuilder.AppendLine(string.Concat($"    客户端[{connId}]{ip}:{port1}", ",接收结果:", resultData_TCP, "_", $"[{_HPSocket_TCPServerHelper._server.ErrorCode}]", _HPSocket_TCPServerHelper._server.ErrorMessage));
                    }
                    catch (Exception ex)
                    {
                        stringBuilder.AppendLine(string.Concat($"    客户端[{connId}]", ",接收结果:失败! 错误信息:", ex.Message));
                    }
                }
                ShowLog(stringBuilder.ToString());
            }
            catch (Exception ex)
            {
                ShowLog("TCPServer服务器广播内容中止!错误信息:" + ex.Message);
            }
        }

        #region TCP事件
        /// <summary>
        /// TCP连接事件(连接前)-使用附加数据处理黏包,不可异步
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="client">如果为 TCP 连接,pClient为 SOCKET 句柄;如果为 UDP 连接,pClient为 SOCKADDR 指针;</param>
        /// <returns></returns>
        private HandleResult OnAccept(IServer sender, IntPtr connId, IntPtr client)
        {
            // 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Error;
            }

            // 设置附加数据(用来做粘包处理)
            sender.SetExtra(connId, string.Empty);  // 初始化附加信息

            ShowLog(string.Format("TCP客户端接入({0}), ip: {1}, port: {2}", connId, ip, port));
            return HandleResult.Ok;
        }

        /// <summary>
        /// TCP握手成功事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <returns></returns>
        private HandleResult OnHandShake(IServer sender, IntPtr connId)
        {
            // 一般用不到
            return HandleResult.Ok;
        }

        /// <summary>
        /// 监听事件
        /// </summary>
        /// <param name="server">服务器对象</param>
        /// <param name="intPtr">连接ID</param>
        /// <returns></returns>
        private HandleResult OnPrepareListen(IServer server, IntPtr intPtr)
        {
            ShowLog(string.Format("TCP服务器开启监听({0}:{1}), listen:{2}", server.Address, server.Port, intPtr));
            return HandleResult.Ok;
        }

        /// <summary>
        /// 数据包发送事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="data">数据包</param>
        /// <returns></returns>
        private HandleResult OnSend(IServer sender, IntPtr connId, byte[] data)
        {
            sender.GetRemoteAddress(connId, out string ip, out ushort port);  // 获取客户端地址

            ShowLog(string.Format("TCP服务器发送数据[ID:{0},客户端地址:‘{1}:{2}’];数据[长度{3}]:{4}", connId, ip ?? "未找到IP", port, data.Length, Encoding.UTF8.GetString(data)));
            return HandleResult.Ok;
        }

        /// <summary>
        /// 数据包接收事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="data">数据包</param>
        /// <returns></returns>
        private HandleResult OnReceive(IServer sender, IntPtr connId, byte[] data)
        {
            // <1> 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Error;
            }
            // <2> 获取附加数据对象
            var extraDataStr = sender.GetExtra<string>(connId);
            if (extraDataStr == null)
            {
                return HandleResult.Error;
            }
            // <3> 将接收数据转换成字符串
            string msg = Encoding.UTF8.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;
            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 > _HPSocket_TCPServerHelper.SocketBufferSize)  // 可选-控制长度为4096(注:实际所占空间大小>4096)
            {
                int length_Delete = extraDataStr.Length - Convert.ToInt32(_HPSocket_TCPServerHelper.SocketBufferSize);
                extraDataStr = extraDataStr.Remove(0, length_Delete);  // 清除长度超标数据
            }
            sender.SetExtra(connId, extraDataStr);  // 初始化附加信息

            return result;
        }

        /// <summary>
        /// TCP连接关闭事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="socketOperation">关闭的类型</param>
        /// <param name="errorCode">错误时的错误代码</param>
        /// <returns></returns>
        private HandleResult OnClose(IServer sender, IntPtr connId, SocketOperation socketOperation, int errorCode)
        {
            // <1> 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Ignore;
            }
            // <2> 释放附加数据
            if (sender.GetExtra<string>(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;
        }

        /// <summary>
        /// TCP服务器关闭事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <returns></returns>
        private HandleResult OnShutdown(IServer sender)
        {
            ShowLog(string.Format("TCP服务器关闭({0}:{1})", sender.Address, sender.Port));
            return HandleResult.Ok;
        }
        #endregion TCP事件

        #region 方法
        /// <summary>
        /// 检查连接是否正常
        /// </summary>
        /// <returns>true为通过</returns>
        private bool CheckServerUrl()
        {
            if (string.IsNullOrEmpty(txtIPAddress.Text))  // 
            {
                ShowLog("发送信息不可为空!");
                return false;
            }
            if (string.IsNullOrEmpty(txtPort.Text))  // 
            {
                ShowLog("端口不可为空!");
                return false;
            }
            return true;
        }
        #endregion 方法

        #region 操控页面控件
        /// <summary>
        /// 开关按钮刷新
        /// </summary>
        /// <param name="msg">信息</param>
        public void ShowBtnOpenCloseTCP(bool isSuccess, string text)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<bool, string>(ShowBtnOpenCloseTCP), isSuccess, text);
                return;
            }

            btnOpenCloseTCP.BackColor = isSuccess ? Color.FromArgb(128, 255, 128) : Color.FromArgb(255, 128, 128);
            btnOpenCloseTCP.Text = text;  // isSuccess? "关闭监听-控制线程" : "开启监听-控制线程";
        }

        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="msg">信息</param>
        public void ShowLog(string msg)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>(ShowLog), msg);
                return;
            }

            if (rTxtInfo.Text.Length > 2000)
            {
                rTxtInfo.Text = string.Empty;
            }
            rTxtInfo.AppendText(string.Concat("\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "->", msg));
        }
        #endregion 操控页面控件
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
  • 312.
  • 313.
  • 314.
  • 315.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
  • 333.
  • 334.
  • 335.
  • 336.
  • 337.
  • 338.
  • 339.
  • 340.
  • 341.
  • 342.
  • 343.
  • 344.
  • 345.
  • 346.
  • 347.
  • 348.
  • 349.
  • 350.
  • 351.
  • 352.
  • 353.
  • 354.
  • 355.
  • 356.
  • 357.
  • 358.
  • 359.
  • 360.
  • 361.
  • 362.
  • 363.
  • 364.
  • 365.
  • 366.
  • 367.
  • 368.
  • 369.
  • 370.
  • 371.
  • 372.
  • 373.
  • 374.
  • 375.
  • 376.
(2)TcpClient使用示例

C#-网络通讯框架(一)-HPSocket_System_04

 TCPClientOld.Designer.cs

查看代码

namespace HPSocket_Client
{
    partial class TCPClientOld
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            button1 = new Button();
            rtxtInfo = new RichTextBox();
            label2 = new Label();
            txtPort = new TextBox();
            btnSendMsg = new Button();
            txtMsg = new TextBox();
            txtIPAddress = new TextBox();
            label1 = new Label();
            txtPort2 = new TextBox();
            txtIP2 = new TextBox();
            checkBox1 = new CheckBox();
            SuspendLayout();
            // 
            // button1
            // 
            button1.Location = new Point(317, 38);
            button1.Name = "button1";
            button1.Size = new Size(57, 23);
            button1.TabIndex = 43;
            button1.Text = "连接";
            button1.UseVisualStyleBackColor = true;
            button1.Click += button1_Click;
            // 
            // rtxtInfo
            // 
            rtxtInfo.Location = new Point(12, 97);
            rtxtInfo.Name = "rtxtInfo";
            rtxtInfo.Size = new Size(598, 278);
            rtxtInfo.TabIndex = 42;
            rtxtInfo.Text = "";
            // 
            // label2
            // 
            label2.AutoSize = true;
            label2.Location = new Point(12, 72);
            label2.Margin = new Padding(2, 0, 2, 0);
            label2.Name = "label2";
            label2.Size = new Size(44, 17);
            label2.TabIndex = 41;
            label2.Text = "消息:";
            // 
            // txtPort
            // 
            txtPort.Location = new Point(251, 38);
            txtPort.Name = "txtPort";
            txtPort.Size = new Size(60, 23);
            txtPort.TabIndex = 40;
            txtPort.Text = "8085";
            // 
            // btnSendMsg
            // 
            btnSendMsg.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
            btnSendMsg.Location = new Point(400, 12);
            btnSendMsg.Margin = new Padding(2, 3, 2, 3);
            btnSendMsg.Name = "btnSendMsg";
            btnSendMsg.Size = new Size(209, 46);
            btnSendMsg.TabIndex = 39;
            btnSendMsg.Text = "发送";
            btnSendMsg.UseVisualStyleBackColor = true;
            btnSendMsg.Click += btnSendMsg_Click;
            // 
            // txtMsg
            // 
            txtMsg.Location = new Point(67, 69);
            txtMsg.Margin = new Padding(2, 3, 2, 3);
            txtMsg.Name = "txtMsg";
            txtMsg.Size = new Size(542, 23);
            txtMsg.TabIndex = 38;
            // 
            // txtIPAddress
            // 
            txtIPAddress.Location = new Point(82, 38);
            txtIPAddress.Margin = new Padding(2, 3, 2, 3);
            txtIPAddress.Name = "txtIPAddress";
            txtIPAddress.Size = new Size(164, 23);
            txtIPAddress.TabIndex = 37;
            txtIPAddress.Text = "127.0.0.1";
            // 
            // label1
            // 
            label1.AutoSize = true;
            label1.Location = new Point(12, 41);
            label1.Margin = new Padding(2, 0, 2, 0);
            label1.Name = "label1";
            label1.Size = new Size(66, 17);
            label1.TabIndex = 36;
            label1.Text = "TCP服务器";
            // 
            // txtPort2
            // 
            txtPort2.Location = new Point(323, 6);
            txtPort2.Name = "txtPort2";
            txtPort2.Size = new Size(60, 23);
            txtPort2.TabIndex = 46;
            txtPort2.Text = "8086";
            // 
            // txtIP2
            // 
            txtIP2.Location = new Point(154, 6);
            txtIP2.Margin = new Padding(2, 3, 2, 3);
            txtIP2.Name = "txtIP2";
            txtIP2.Size = new Size(164, 23);
            txtIP2.TabIndex = 45;
            txtIP2.Text = "127.0.0.1";
            // 
            // checkBox1
            // 
            checkBox1.AutoSize = true;
            checkBox1.Location = new Point(16, 8);
            checkBox1.Name = "checkBox1";
            checkBox1.Size = new Size(133, 21);
            checkBox1.TabIndex = 48;
            checkBox1.Text = "绑定TCP客户端地址";
            checkBox1.UseVisualStyleBackColor = true;
            // 
            // TCPClientOld
            // 
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(620, 387);
            Controls.Add(checkBox1);
            Controls.Add(txtPort2);
            Controls.Add(txtIP2);
            Controls.Add(button1);
            Controls.Add(rtxtInfo);
            Controls.Add(label2);
            Controls.Add(txtPort);
            Controls.Add(btnSendMsg);
            Controls.Add(txtMsg);
            Controls.Add(txtIPAddress);
            Controls.Add(label1);
            Name = "TCPClientOld";
            Text = "TCPClientOld";
            ResumeLayout(false);
            PerformLayout();
        }

        #endregion

        private Button button1;
        private RichTextBox rtxtInfo;
        private Label label2;
        private TextBox txtPort;
        private Button btnSendMsg;
        private TextBox txtMsg;
        private TextBox txtIPAddress;
        private Label label1;
        private TextBox txtPort2;
        private TextBox txtIP2;
        private CheckBox checkBox1;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.

 TCPClientOld.cs

using csharp_networkprotocol_hpsocket;
using HPSocket;
using HPSocket.Base;
using HPSocket.Sdk;
using System;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace HPSocket_Client
{
    public partial class TCPClientOld : Form
    {
        /// <summary>
        ///  HPSocket_TCPServer示例帮助类(示例学习)
        /// </summary>
        HPSocket_TcpClientHelper _HPSocket_TcpClientHelper = new HPSocket_TcpClientHelper();

        /// <summary>
        /// 包数据结束符
        /// </summary>
        private readonly string _endsWith = "\r\n";

        public TCPClientOld()
        {
            InitializeComponent();
        }

        private void TCPClientOld_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 连接
        /// </summary>
        private async void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (button1.Text == "连接")  // 开启监听
                {
                    // 检查地址
                    if (!CheckServerUrl())
                    {
                        return;
                    }

                    string address = txtIPAddress.Text.Trim();        // IP
                    ushort port = ushort.Parse(txtPort.Text.Trim());  // 端口

                    // <2>配置TCPServer的参数
                    _HPSocket_TcpClientHelper.Address = address;        // IP
                    _HPSocket_TcpClientHelper.Port = port;              // 端口
                    _HPSocket_TcpClientHelper.SocketBufferSize = 4096;  // 缓存4K
                    if (checkBox1.Checked)
                    {
                        _HPSocket_TcpClientHelper.BindAddress = txtIP2.Text.Trim();  // 本地绑定到哪个ip
                        _HPSocket_TcpClientHelper.BindPort = (ushort)Convert.ToInt32(txtPort2.Text.Trim());   // 本地绑定到哪个端口
                    }

                    // <3> 绑定事件
                    //event ClientPrepareConnectEventHandler OnPrepareConnect;  // 准备连接了事件
                    //event ClientConnectEventHandler OnConnect;      // 连接事件
                    //event ClientHandShakeEventHandler OnHandShake;  // TCP握手成功事件
                    //event ClientSendEventHandler OnSend;            // 数据包发送事件
                    //event ClientReceiveEventHandler OnReceive;      // 数据包到达事件
                    //event ClientCloseEventHandler OnClose;          // TCP连接关闭事件
                    _HPSocket_TcpClientHelper._client.OnPrepareConnect += OnPrepareConnect;  // 准备连接了事件
                    _HPSocket_TcpClientHelper._client.OnConnect += OnConnect;                // 连接事件
                    _HPSocket_TcpClientHelper._client.OnHandShake += OnHandShake;            // TCP握手成功事件
                    _HPSocket_TcpClientHelper._client.OnSend += OnSend;                      // 数据包发送事件
                    _HPSocket_TcpClientHelper._client.OnReceive += OnReceive;                // 数据包到达事件
                    _HPSocket_TcpClientHelper._client.OnClose += OnClose;                    // TCP连接关闭事件

                    bool connResult = _HPSocket_TcpClientHelper.Connect();  // 连接
                    if (connResult)
                    {
                        Showbutton1(true, "断开");
                    }
                    else
                    {
                        Showbutton1(false, "连接");
                    }
                }
                else  // 关闭监听
                {
                    _HPSocket_TcpClientHelper.Stop();
                    _HPSocket_TcpClientHelper._client.OnPrepareConnect -= OnPrepareConnect;  // 准备连接了事件
                    _HPSocket_TcpClientHelper._client.OnConnect -= OnConnect;                // 连接事件
                    _HPSocket_TcpClientHelper._client.OnHandShake -= OnHandShake;            // TCP握手成功事件
                    _HPSocket_TcpClientHelper._client.OnSend -= OnSend;                      // 数据包发送事件
                    _HPSocket_TcpClientHelper._client.OnReceive -= OnReceive;                // 数据包到达事件
                    _HPSocket_TcpClientHelper._client.OnClose -= OnClose;                    // TCP连接关闭事件

                    Showbutton1(false, "连接");
                }
            }
            catch (Exception ex)
            {
                ShowLog($"连接/关闭TCP客户端 {txtIPAddress.Text}:{txtPort.Text} 失败,错误信息:" + ex.Message);
            }
        }

        /// <summary>
        /// 发送
        /// </summary>
        private async void btnSendMsg_Click(object sender, EventArgs e)
        {
            try
            {
                // 检查地址
                if (!_HPSocket_TcpClientHelper._client.IsConnected || _HPSocket_TcpClientHelper._client.State != ServiceState.Started)
                {
                    ShowLog("TCP客户端未连接到任何TCP服务器!");
                    return;
                }
                string sendMsg = txtMsg.Text;  // 
                if (string.IsNullOrEmpty(sendMsg))
                {
                    ShowLog("发送信息不可为空!");
                    return;
                }
                byte[] bytes = Encoding.UTF8.GetBytes(sendMsg);
                int length = bytes.Length;

                bool resultData_TCP = _HPSocket_TcpClientHelper.Send(bytes, length);  // 发送
                // 显示信息-略
            }
            catch (Exception ex)
            {
                ShowLog("发送信息错误,错误信息:" + ex.Message);
            }
        }

        #region 事件
        /// <summary>
        /// 准备连接了事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="socket">客户端Id</param>
        /// <returns></returns>
        private HandleResult OnPrepareConnect(IClient sender, IntPtr socket)
        {
            sender.ExtraData = string.Empty;  // 设置附加数据(用来做粘包处理)

            return HandleResult.Ok;
        }
        /// <summary>
        /// 连接事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// TCP握手成功事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <returns></returns>
        private HandleResult OnHandShake(IClient sender)
        {
            // 一般用不到
            return HandleResult.Ok;
        }
        /// <summary>
        /// 数据包发送事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="data">数据</param>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// 数据包到达事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="data">数据</param>
        /// <returns></returns>
        private HandleResult OnReceive(IClient sender, byte[] data)
        {
            // <1> 获取附加数据对象
            if (!(sender.ExtraData is string extraDataStr))
            {
                return HandleResult.Error;
            }

            // <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;
            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 > _HPSocket_TcpClientHelper.SocketBufferSize)  // 可选-控制长度为4096(注:实际所占空间大小>4096)
            {
                int length_Delete = extraDataStr.Length - Convert.ToInt32(_HPSocket_TcpClientHelper.SocketBufferSize);
                extraDataStr = extraDataStr.Remove(0, length_Delete);  // 清除长度超标数据
            }
            sender.ExtraData = extraDataStr;  // 初始化附加信息

            return result;
        }
        /// <summary>
        /// TCP连接关闭事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="socketOperation">关闭类型</param>
        /// <param name="errorCode">错误代码</param>
        /// <returns></returns>
        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 事件

        #region 方法
        /// <summary>
        /// 开关按钮刷新
        /// </summary>
        /// <param name="msg">信息</param>
        public void Showbutton1(bool isSuccess, string text)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<bool, string>(Showbutton1), isSuccess, text);
                return;
            }

            button1.BackColor = isSuccess ? Color.FromArgb(128, 255, 128) : Color.FromArgb(255, 128, 128);
            button1.Text = text;  // isSuccess? "关闭监听-控制线程" : "开启监听-控制线程";
        }

        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="msg">信息</param>
        public void ShowLog(string msg)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>(ShowLog), msg);
                return;
            }
            if (rtxtInfo.Text.Length > 2000)
            {
                rtxtInfo.Text = string.Empty;
            }
            rtxtInfo.AppendText(string.Concat("\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "->", msg));
        }

        /// <summary>
        /// 检查连接是否正常
        /// </summary>
        /// <returns>true为通过</returns>
        private bool CheckServerUrl()
        {

            if (string.IsNullOrEmpty(txtIPAddress.Text))  // 
            {
                ShowLog("发送信息不可为空!");
                return false;
            }
            if (string.IsNullOrEmpty(txtPort.Text))  // 
            {
                ShowLog("端口不可为空!");
                return false;
            }
            return true;
        }
        #endregion 方法
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
(3)HPSocket的TCPServer、 TCPServer类学习Helper(类库提供的方法、属性学习)

查看代码

/**
*┌──────────────────────────────────────────────────────────────┐
*│ 描    述:HPSocket的TCPServer、TCPClient通讯相关的工具类(类库提供的方法、属性学习)
*│ 作    者:执笔小白
*│ 版    本:1.0
*│ 创建时间:2023-6-13 10:40:56
*└──────────────────────────────────────────────────────────────┘
*┌──────────────────────────────────────────────────────────────┐
*│ 命名空间: ZhibiXiaobai
*│ 类    名:HPSocket_TCPServerHelper、HPSocket_TcpClientHelper
*└──────────────────────────────────────────────────────────────┘
*/
using HPSocket;
using HPSocket.Base;
using HPSocket.Sdk;
using HPSocket.Tcp;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace csharp_networkprotocol_hpsocket
{
    /// <summary>
    /// HPSocket_TCPServer示例帮助类(类库提供的方法、属性学习)
    /// System.Net.Sockets类库
    /// TcpServer
    /// </summary>
    public class HPSocket_TCPServerHelper
    {
        #region 接收端(服务端)
        /// <summary>
        /// 侦听来自 TCP 网络客户端的连接
        /// </summary>
        public ITcpServer _server = null;
        #region 创建时的设置项
        /// <summary>
        /// 要绑定的服务器地址
        /// </summary>
        public string Address
        {
            get => _server.Address;
            set => _server.Address = value;
        }

        /// <summary>
        /// 要绑定的服务器端口
        /// </summary>
        public ushort Port
        {
            get => _server.Port;
            set => _server.Port = value;
        }

        /// <summary>
        /// 设置最大连接数(组件会根据设置值预分配内存,因此需要根据实际情况设置,不宜过大)
        /// </summary>
        public uint MaxConnectionCount
        {
            get => _server.MaxConnectionCount;
            set => _server.MaxConnectionCount = value;
        }

        /// <summary>
        /// 读取或设置是否标记静默时间
        /// (设置为 true 时 DisconnectSilenceConnections() 和 GetSilencePeriod()才有效,默认:false)
        /// </summary>   
        public bool IsMarkSilence
        {
            get => _server.IsMarkSilence;
            set => _server.IsMarkSilence = value;
        }

        /// <summary>
        /// 获取或设置数据发送策略
        /// </summary>
        public SendPolicy SendPolicy
        {
            get => _server.SendPolicy;
            set => _server.SendPolicy = value;
        }

        /// <summary>
        /// 获取或设置 OnSend 事件同步策略
        /// </summary>
        public OnSendSyncPolicy OnSendSyncPolicy
        {
            get => _server.OnSendSyncPolicy;
            set => _server.OnSendSyncPolicy = value;
        }

        /// <summary>
        /// 获取或设置地址重用选项
        /// </summary>
        public ReuseAddressPolicy ReuseAddressPolicy
        {
            get => _server.ReuseAddressPolicy;
            set => _server.ReuseAddressPolicy = value;
        }

        /// <summary>
        /// 获取或设置是否开启 nodelay 模式 (默认: false, 不开启)
        /// </summary>
        public bool NoDelay
        {
            get => _server.NoDelay;
            set => _server.NoDelay = value;
        }

        #region 心跳检测
        /// <summary>
        /// 读取或设置心跳包间隔(毫秒,0 则不发送心跳包)
        /// </summary>
        public uint KeepAliveTime
        {
            get => _server.KeepAliveTime;
            set => _server.KeepAliveTime = value;
        }


        /// <summary>
        /// 读取或设置心跳确认包检测间隔(毫秒,0 不发送心跳包,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线)
        /// </summary>
        public uint KeepAliveInterval
        {
            get => _server.KeepAliveInterval;
            set => _server.KeepAliveInterval = value;
        }

        #endregion 心跳检测

        #region 性能优化
        /// <summary>
        /// 读取或设置 Accept 预投递数量(根据负载调整设置,Accept 预投递数量越大则支持的并发连接请求越多)
        /// </summary>
        public uint AcceptSocketCount
        {
            get => _server.AcceptSocketCount;
            set => _server.AcceptSocketCount = value;
        }


        /// <summary>
        /// 读取或设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为 1024 的倍数)
        /// </summary>
        public uint SocketBufferSize
        {
            get => _server.SocketBufferSize;
            set => _server.SocketBufferSize = value;
        }


        /// <summary>
        /// 读取或设置监听 Socket 的等候队列大小(根据并发连接数量调整设置)
        /// </summary>
        public uint SocketListenQueue
        {
            get => _server.SocketListenQueue;
            set => _server.SocketListenQueue = value;
        }


        /// <summary>
        /// 读取或设置工作线程数量(通常设置为 2 * CPU + 2)
        /// </summary>
        public uint WorkerThreadCount
        {
            get => _server.WorkerThreadCount;
            set => _server.WorkerThreadCount = value;
        }


        /// <summary>
        /// 读取或设置 Socket 缓存对象锁定时间(毫秒,在锁定期间该 Socket 缓存对象不能被获取使用)
        /// </summary>
        public uint FreeSocketObjLockTime
        {
            get => _server.FreeSocketObjLockTime;
            set => _server.FreeSocketObjLockTime = value;
        }


        /// <summary>
        /// 读取或设置 Socket 缓存池大小(通常设置为平均并发连接数量的 1/3 - 1/2)
        /// </summary>
        public uint FreeSocketObjPool
        {
            get => _server.FreeSocketObjPool;
            set => _server.FreeSocketObjPool = value;
        }


        /// <summary>
        /// 读取或设置内存块缓存池大小(通常设置为 Socket 缓存池大小的 2 - 3 倍)
        /// </summary>
        public uint FreeBufferObjPool
        {
            get => _server.FreeBufferObjPool;
            set => _server.FreeBufferObjPool = value;
        }

        /// <summary>
        /// 读取或设置内存块缓存池大小(通常设置为 Socket 缓存池大小的 2 - 3 倍)
        /// </summary>
        public uint FreeSocketObjHold
        {
            get => _server.FreeSocketObjHold;
            set => _server.FreeSocketObjHold = value;
        }

        /// <summary>
        /// 读取或设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍)
        /// </summary>
        public uint FreeBufferObjHold
        {
            get => _server.FreeBufferObjHold;
            set => _server.FreeBufferObjHold = value;
        }

        #endregion 性能优化
        #endregion 创建时的设置项

        #region 常用属性
        /// <summary>
        /// 获取是否启动
        /// </summary>
        public bool HasStarted => _server.HasStarted;

        /// <summary>
        /// 获取状态
        /// </summary>
        public ServiceState State => _server.State;

        /// <summary>
        /// 获取连接数
        /// </summary>
        public uint ConnectionCount => _server.ConnectionCount;

        /// <summary>
        /// 是否为安全连接(SSL/HTTPS)
        /// </summary>
        public bool IsSecure => _server.IsSecure;
        #endregion 常用属性

        #region 常用方法
        /// <summary>
        /// 启动服务
        /// </summary>
        /// <returns></returns>
        public bool Start() => _server.Start();

        /// <summary>
        /// 停止服务
        /// </summary>
        /// <returns></returns>
        public bool Stop() => _server.Stop();

        #region 附加信息
        /// <summary>
        /// 获取所有附加数据
        /// </summary>
        /// <returns></returns>
        public ConcurrentDictionary<IntPtr, object> GetAllExtra() => _server.GetAllExtra();

        /// <summary>
        /// 获取附加数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="connId"></param>
        /// <returns></returns>
        public T GetExtra<T>(IntPtr connId) => _server.GetExtra<T>(connId);

        /// <summary>
        /// 获取连接附加数据, 非托管版本, hp-socket自带方法;非特殊需求不要使用这个方法, 请直接使用 GetExtra();
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="extra"></param>
        /// <returns></returns>
        public bool NativeGetConnectionExtra(IntPtr connId, out IntPtr extra) => _server.NativeGetConnectionExtra(connId, out extra);

        /// <summary>
        /// 设置附加数据
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool SetExtra(IntPtr connId, object obj) => _server.SetExtra(connId, obj);

        /// <summary>
        /// 设置连接附加数据, 非托管版本, hp-socket自带方法;非特殊需求不要使用这个方法, 请直接使用 SetExtra();
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="extra"></param>
        /// <returns></returns>
        public bool NativeSetConnectionExtra(IntPtr connId, IntPtr extra) => _server.NativeSetConnectionExtra(connId, extra);

        /// <summary>
        /// 删除附加数据
        /// </summary>
        /// <param name="connId"></param>
        /// <returns></returns>
        public bool RemoveExtra(IntPtr connId) => _server.RemoveExtra(connId);
        #endregion 附加信息

        #region 发送数据
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="connId">连接id</param>
        /// <param name="bytes">数据源</param>
        /// <param name="length">数据长度</param>
        /// <returns></returns>
        public bool Send(IntPtr connId, byte[] bytes, int length) => _server.Send(connId, bytes, length);

        /// <summary>
        /// 发送数据-指针偏移
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="bytes"></param>
        /// <param name="offset">对bytes的偏移</param>
        /// <param name="length">发多大</param>
        /// <returns></returns>
        public bool Send(IntPtr connId, byte[] bytes, int offset, int length) => _server.Send(connId, bytes, offset, length);
        /// <summary>
        /// 发送多组数据 向指定连接发送多组数据 TCP - 顺序发送所有数据包
        /// </summary>
        /// <param name="connId">连接 ID</param>
        /// <param name="buffers">发送缓冲区数组</param>
        /// <returns>true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码</returns>
        public bool SendPackets(IntPtr connId, Wsabuf[] buffers) => SendPackets(connId, buffers);
        #endregion 发送数据

        #region 发送本地小文件
        /// <summary>
        /// 发送本地小文件
        /// 向指定连接发送 4096 KB 以下的小文件
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="filePath">文件路径</param>
        /// <param name="head">头部附加数据</param>
        /// <param name="tail">尾部附加数据</param>
        /// <returns>true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码</returns>
        public bool SendSmallFile(IntPtr connId, string filePath, ref Wsabuf head, ref Wsabuf tail) => _server.SendSmallFile(connId, filePath, ref head, ref tail);

        /// <summary>
        /// 发送本地小文件
        /// 向指定连接发送 4096 KB 以下的小文件
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="filePath">文件路径</param>
        /// <param name="head">头部附加数据,可以为null</param>
        /// <param name="tail">尾部附加数据,可以为null</param>
        /// <returns>true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码</returns>
        public bool SendSmallFile(IntPtr connId, string filePath, byte[] head, byte[] tail) => _server.SendSmallFile(connId, filePath, head, tail);
        #endregion 发送本地小文件

        #region 查询服务器信息
        /// <summary>
        /// 获取监听socket的地址信息
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool GetListenAddress(out string ip, out ushort port) => _server.GetListenAddress(out ip, out port);
        #endregion 查询服务器信息

        #region 查询客户端信息
        /// <summary>
        /// 获取所有连接
        /// </summary>
        /// <returns></returns>
        public List<IntPtr> GetAllConnectionIds() => _server.GetAllConnectionIds();

        /// <summary>
        /// 获取某客户端连接是否有效
        /// </summary>
        /// <param name="connId"></param>
        /// <returns></returns>
        public bool IsConnected(IntPtr connId) => _server.IsConnected(connId);

        /// <summary>
        /// 获取某客户端连接的接收状态
        /// </summary>
        /// <param name="connId"></param>
        /// <returns></returns>
        public ReceiveState GetReceiveState(IntPtr connId) => _server.GetReceiveState(connId);

        /// <summary>
        /// 获取某个连接的本地地址信息
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool GetLocalAddress(IntPtr connId, out string ip, out ushort port) => _server.GetLocalAddress(connId, out ip, out port);

        /// <summary>
        /// 获取某个连接的远程地址信息
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool GetRemoteAddress(IntPtr connId, out string ip, out ushort port) => _server.GetRemoteAddress(connId, out ip, out port);

        /// <summary>
        /// 获取指定连接的连接时长(毫秒)
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="period"></param>
        /// <returns></returns>
        public bool GetConnectPeriod(IntPtr connId, out uint period) => _server.GetConnectPeriod(connId, out period);

        /// <summary>
        /// 获取某个连接静默时间(毫秒)
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="period"></param>
        /// <returns></returns>
        public bool GetSilencePeriod(IntPtr connId, out uint period) => _server.GetSilencePeriod(connId, out period);

        /// <summary>
        /// 获取连接中未发出数据的长度
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public bool GetPendingDataLength(IntPtr connId, out int length) => _server.GetPendingDataLength(connId, out length);

        #endregion 查询客户端信息

        #region 断开与客户端的连接
        /// <summary>
        /// 断开与某个客户的连接
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="force">是否强制断开</param>
        /// <returns></returns>
        public bool Disconnect(IntPtr connId, bool force = true) => _server.Disconnect(connId, force);

        /// <summary>
        /// 断开超过指定时间的连接
        /// </summary>
        /// <param name="period">毫秒</param>
        /// <param name="force">强制</param>
        /// <returns></returns>
        public bool DisconnectLongConnections(uint period, bool force = true) => _server.DisconnectLongConnections(period, force);

        /// <summary>
        /// 断开超过指定时长的静默连接
        /// </summary>
        /// <param name="period">毫秒</param>
        /// <param name="force">强制</param>
        /// <returns></returns>
        public bool DisconnectSilenceConnections(uint period, bool force = true) => _server.DisconnectSilenceConnections(period, force);
        #endregion 断开与客户端的连接

        #region 暂停/唤醒接收某客户端
        /// <summary>
        /// 暂停接收
        /// </summary>
        /// <param name="connId"></param>
        /// <returns></returns>
        public bool PauseReceive(IntPtr connId) => _server.PauseReceive(connId);

        /// <summary>
        /// 唤醒接收
        /// </summary>
        /// <param name="connId"></param>
        /// <returns></returns>
        public bool ResumeReceive(IntPtr connId) => _server.ResumeReceive(connId);
        #endregion 暂停/唤醒接收某客户端
        #endregion 常用方法

        #region 创建侦听的方法与示例方法(后使用Start()开启侦听)
        /// <summary>
        /// 创建侦听
        /// </summary>
        /// <param name="localAddr">地址</param>
        /// <param name="port">端口</param>
        /// <returns></returns>
        public ITcpServer CreateTcpServer()
        {
            _server = new TcpServer();
            return _server;
        }
        /// <summary>
        /// 创建TCP侦听 -示例
        /// </summary>
        /// <param name="localAddr">地址</param>
        /// <param name="port">端口</param>
        /// <returns></returns>
        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事件
        /// <summary>
        /// TCP连接事件(连接前)-使用附加数据处理黏包,不可异步
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="client">如果为 TCP 连接,pClient为 SOCKET 句柄;如果为 UDP 连接,pClient为 SOCKADDR 指针;</param>
        /// <returns></returns>
        private HandleResult OnAccept(IServer sender, IntPtr connId, IntPtr client)
        {
            // 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Error;
            }

            // 设置附加数据(用来做粘包处理)
            sender.SetExtra(connId, string.Empty);  // 初始化附加信息

            //ShowLog(string.Format("TCP客户端接入({0}), ip: {1}, port: {2}", connId, ip, port));
            return HandleResult.Ok;
        }

        /// <summary>
        /// TCP握手成功事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <returns></returns>
        private HandleResult OnHandShake(IServer sender, IntPtr connId)
        {
            // 一般用不到
            return HandleResult.Ok;
        }

        /// <summary>
        /// 监听事件
        /// </summary>
        /// <param name="server">服务器对象</param>
        /// <param name="intPtr">连接ID</param>
        /// <returns></returns>
        private HandleResult OnPrepareListen(IServer server, IntPtr intPtr)
        {
            //ShowLog(string.Format("TCP服务器开启监听({0}:{1}), listen:{2}", server.Address, server.Port, intPtr));
            return HandleResult.Ok;
        }

        /// <summary>
        /// 数据包发送事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="data">数据包</param>
        /// <returns></returns>
        private HandleResult OnSend(IServer sender, IntPtr connId, byte[] data)
        {
            sender.GetRemoteAddress(connId, out string ip, out ushort port);  // 获取客户端地址

            //ShowLog(string.Format("TCP服务器发送数据[ID:{0},客户端地址:‘{1}:{2}’];数据[长度{3}]:{4}", connId, ip ?? "未找到IP", port, data.Length, Encoding.ASCII.GetString(data)));
            return HandleResult.Ok;
        }

        /// <summary>
        /// 数据包接收事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="data">数据包</param>
        /// <returns></returns>
        private HandleResult OnReceive(IServer sender, IntPtr connId, byte[] data)
        {
            // <1> 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Error;
            }
            // <2> 获取附加数据对象
            var extraDataStr = sender.GetExtra<string>(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;
        }

        /// <summary>
        /// TCP连接关闭事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="socketOperation">关闭的类型</param>
        /// <param name="errorCode">错误时的错误代码</param>
        /// <returns></returns>
        private HandleResult OnClose(IServer sender, IntPtr connId, SocketOperation socketOperation, int errorCode)
        {
            // <1> 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Ignore;
            }
            // <2> 释放附加数据
            if (sender.GetExtra<string>(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;
        }

        /// <summary>
        /// TCP服务器关闭事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <returns></returns>
        private HandleResult OnShutdown(IServer sender)
        {
            //ShowLog(string.Format("TCP服务器关闭({0}:{1})", sender.Address, sender.Port));
            return HandleResult.Ok;
        }
        #endregion TCP事件
        #endregion 创建侦听的方法与示例方法(后使用Start()开启侦听)
        #endregion 接收端(服务端)
    }

    /// <summary>
    /// HPSocket_TcpClient示例帮助类(示例学习)
    /// System.Net.Sockets类库
    /// TcpClient
    /// </summary>
    public class HPSocket_TcpClientHelper
    {
        #region 发送端(客户端)
        /// <summary>
        /// TCP客户端
        /// </summary>
        public ITcpClient _client = new TcpClient();

        /// <summary>
        /// 本地绑定到哪个ip
        /// </summary>
        public string BindAddress
        {
            get => _client.BindAddress;
            set => _client.BindAddress = value;
        }
        /// <summary>
        /// 本地绑定到哪个端口
        /// </summary>
        public ushort BindPort
        {
            get => _client.BindPort;
            set => _client.BindPort = value;
        }

        /// <summary>
        /// 远程服务器地址
        /// </summary>
        public string Address
        {
            get => _client.Address;
            set => _client.Address = value;
        }
        /// <summary>
        /// 远程服务器端口
        /// </summary>
        public ushort Port
        {
            get => _client.Port;
            set => _client.Port = value;
        }

        #region 创建时的设置项
        /// <summary>
        /// 是否异步连接,默认为真
        /// </summary>
        public bool Async
        {
            get => _client.Async;
            set => _client.Async = value;
        }

        /// <summary>
        /// 读取或设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为:(N * 1024) - sizeof(TBufferObj))
        /// </summary>
        public uint SocketBufferSize
        {
            get => _client.SocketBufferSize;
            set => _client.SocketBufferSize = value;
        }

        /// <summary>
        /// 连接超时时间, 默认操作系统默认值
        /// 单位: 毫秒
        /// 异常:T:System.InvalidOperationException:同步连接、.NET Framework2.0以及设置小于100毫秒会引发此异常
        /// </summary>
        public int ConnectionTimeout
        {
            get => _client.ConnectionTimeout;
            set => _client.ConnectionTimeout = value;
        }

        /// <summary>
        /// 附加数据
        /// 赋值:client.ExtraData = myObj;
        /// 取值:var data = ExtraData as MyData;
        /// </summary>
        public object ExtraData
        {
            get => _client.ExtraData;
            set => _client.ExtraData = value;
        }

        /// <summary>
        /// 获取或设置是否开启 nodelay 模式 (默认: false, 不开启)
        /// </summary>
        public bool NoDelay
        {
            get => _client.NoDelay;
            set => _client.NoDelay = value;
        }

        #region 心跳
        /// <summary>
        /// 读取或设置心跳包间隔(毫秒,0 则不发送心跳包)
        /// </summary>
        public uint KeepAliveTime
        {
            get => _client.KeepAliveTime;
            set => _client.KeepAliveTime = value;
        }
        /// <summary>
        /// 读取或设置心跳确认包检测间隔(毫秒,0 不发送心跳包,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线)
        /// </summary>
        public uint KeepAliveInterval
        {
            get => _client.KeepAliveInterval;
            set => _client.KeepAliveInterval = value;
        }
        #endregion 心跳

        /// <summary>
        /// 获取或设置暂停接收状态,设置状态时,不允许设置为ReceiveState.Unknown,
        /// </summary>
        public ReceiveState PauseReceive
        {
            get => _client.PauseReceive;
            set => _client.PauseReceive = value;
        }

        /// <summary>
        /// 获取或设置地址重用选项
        /// </summary>
        public ReuseAddressPolicy ReuseAddressPolicy
        {
            get => _client.ReuseAddressPolicy;
            set => _client.ReuseAddressPolicy = value;
        }

        /// <summary>
        /// 代理列表
        /// </summary>
        public List<IProxy> ProxyList
        {
            get => _client.ProxyList;
            set => _client.ProxyList = value;
        }

        #region 性能优化
        /// <summary>
        /// 读取或设置内存块缓存池大小(通常设置为 -> PUSH 模型:5 - 10;PULL 模型:10 - 20 )
        /// </summary>
        public uint FreeBufferPoolSize
        {
            get => _client.FreeBufferPoolSize;
            set => _client.FreeBufferPoolSize = value;
        }

        /// <summary>
        /// 读取或设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍)
        /// </summary>
        public uint FreeBufferPoolHold
        {
            get => _client.FreeBufferPoolHold;
            set => _client.FreeBufferPoolHold = value;
        }
        #endregion 性能优化
        #endregion 创建时的设置项

        #region 常用属性
        /// <summary>
        /// 检查通信组件是否已启动
        /// </summary>
        public bool HasStarted => _client.HasStarted;

        /// <summary>
        /// 状态
        /// </summary>
        public ServiceState State => _client.State;

        /// <summary>
        /// 是否已连接
        /// </summary>
        public bool IsConnected => _client.IsConnected;

        /// <summary>
        /// 是否为安全连接(SSL/HTTPS)
        /// </summary>
        public bool IsSecure => _client.IsSecure;

        /// <summary>
        /// 获取该组件对象的连接Id
        /// </summary>
        public IntPtr ConnectionId => _client.ConnectionId;
        #endregion 常用属性

        #region 常用方法
        #region 启动并连接到服务器
        /// <summary>
        /// 启动通讯组件并连接到服务器
        /// </summary>
        /// <returns></returns>
        public bool Connect() => _client.Connect();

        /// <summary>
        /// 启动通讯组件并连接到服务器
        /// </summary>
        /// <param name="address">远程服务器地址</param>
        /// <param name="port">远程服务器端口</param>
        /// <returns></returns>
        public bool Connect(string address, ushort port) => _client.Connect(address, port);
        #endregion 启动并连接到服务器

        /// <summary>
        /// 停止服务
        /// </summary>
        /// <returns></returns>
        public bool Stop() => _client.Stop();

        #region 发送数据
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="bytes">数据包</param>
        /// <param name="length">数据包长度</param>
        /// <returns></returns>
        public bool Send(byte[] bytes, int length) => _client.Send(bytes, length);

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="bytes">数据包</param>
        /// <param name="offset">针对bytes的偏移</param>
        /// <param name="length">数据包长度</param>
        /// <returns></returns>
        public bool Send(byte[] bytes, int offset, int length) => _client.Send(bytes, offset, length);

        /// <summary>
        /// 发送多组数据 向指定连接发送多组数据 TCP - 顺序发送所有数据包
        /// </summary>
        /// <param name="buffers">发送缓冲区数组</param>
        /// <param name="count">发送缓冲区数目</param>
        /// <returns>true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码</returns>
        public bool SendPackets(Wsabuf[] buffers, int count) => _client.SendPackets(buffers, count);
        #endregion 发送数据

        #region 发送本地小文件
        /// <summary>
        /// 发送本地小文件
        //  向指定连接发送 4096 KB 以下的小文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="head">头部附加数据</param>
        /// <param name="tail">尾部附加数据</param>
        /// <returns>true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码</returns>
        public bool SendSmallFile(string filePath, ref Wsabuf head, ref Wsabuf tail) => _client.SendSmallFile(filePath, ref head, ref tail);

        /// <summary>
        /// 发送本地小文件
        /// 向指定连接发送 4096 KB 以下的小文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="head">头部附加数据,可以为null</param>
        /// <param name="tail">尾部附加数据,可以为null</param>
        /// <returns>true.成功,false.失败,可通过 SYSGetLastError() 获取 Windows 错误代码</returns>
        public bool SendSmallFile(string filePath, byte[] head, byte[] tail) => _client.SendSmallFile(filePath, head, tail);
        #endregion 发送本地小文件

        #region 查询连接信息
        /// <summary>
        /// 获取监听socket的地址信息
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool GetListenAddress(out string host, out ushort port) => _client.GetListenAddress(out host, out port);

        /// <summary>
        /// 获取连接的远程主机信息
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool GetRemoteHost(out string host, out ushort port) => _client.GetRemoteHost(out host, out port);

        /// <summary>
        /// 获取连接中未发出数据的长度
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public bool GetPendingDataLength(out int length) => _client.GetPendingDataLength(out length);
        #endregion 查询连接信息

        /// <summary>
        /// 等待代理结果
        /// </summary>
        /// <returns>连接成功返回true, 连接失败返回false</returns>
        public async Task<bool> WaitProxyAsync() => await _client.WaitProxyAsync();
        #endregion 常用方法

        #region 创建TCPClient并连接示例    
        /// <summary>
        /// 创建TCP侦听 -示例
        /// </summary>
        /// <param name="localAddr">地址</param>
        /// <param name="port">端口</param>
        /// <returns></returns>
        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 事件
        /// <summary>
        /// 准备连接了事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="socket">客户端Id</param>
        /// <returns></returns>
        private HandleResult OnPrepareConnect(IClient sender, IntPtr socket)
        {
            sender.ExtraData = string.Empty;  // 设置附加数据(用来做粘包处理)

            return HandleResult.Ok;
        }
        /// <summary>
        /// 连接事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// TCP握手成功事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <returns></returns>
        private HandleResult OnHandShake(IClient sender)
        {
            // 一般用不到
            return HandleResult.Ok;
        }
        /// <summary>
        /// 数据包发送事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="data">数据</param>
        /// <returns></returns>
        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;
        }
        /// <summary>
        /// 数据包到达事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="data">数据</param>
        /// <returns></returns>
        private HandleResult OnReceive(IClient sender, byte[] data)
        {
            // <1> 获取附加数据对象
            if (!(sender.ExtraData is string extraDataStr))
            {
                return HandleResult.Error;
            }

            // <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;
        }
        /// <summary>
        /// TCP连接关闭事件
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="socketOperation">关闭类型</param>
        /// <param name="errorCode">错误代码</param>
        /// <returns></returns>
        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 发送端(客户端)
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
  • 312.
  • 313.
  • 314.
  • 315.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
  • 333.
  • 334.
  • 335.
  • 336.
  • 337.
  • 338.
  • 339.
  • 340.
  • 341.
  • 342.
  • 343.
  • 344.
  • 345.
  • 346.
  • 347.
  • 348.
  • 349.
  • 350.
  • 351.
  • 352.
  • 353.
  • 354.
  • 355.
  • 356.
  • 357.
  • 358.
  • 359.
  • 360.
  • 361.
  • 362.
  • 363.
  • 364.
  • 365.
  • 366.
  • 367.
  • 368.
  • 369.
  • 370.
  • 371.
  • 372.
  • 373.
  • 374.
  • 375.
  • 376.
  • 377.
  • 378.
  • 379.
  • 380.
  • 381.
  • 382.
  • 383.
  • 384.
  • 385.
  • 386.
  • 387.
  • 388.
  • 389.
  • 390.
  • 391.
  • 392.
  • 393.
  • 394.
  • 395.
  • 396.
  • 397.
  • 398.
  • 399.
  • 400.
  • 401.
  • 402.
  • 403.
  • 404.
  • 405.
  • 406.
  • 407.
  • 408.
  • 409.
  • 410.
  • 411.
  • 412.
  • 413.
  • 414.
  • 415.
  • 416.
  • 417.
  • 418.
  • 419.
  • 420.
  • 421.
  • 422.
  • 423.
  • 424.
  • 425.
  • 426.
  • 427.
  • 428.
  • 429.
  • 430.
  • 431.
  • 432.
  • 433.
  • 434.
  • 435.
  • 436.
  • 437.
  • 438.
  • 439.
  • 440.
  • 441.
  • 442.
  • 443.
  • 444.
  • 445.
  • 446.
  • 447.
  • 448.
  • 449.
  • 450.
  • 451.
  • 452.
  • 453.
  • 454.
  • 455.
  • 456.
  • 457.
  • 458.
  • 459.
  • 460.
  • 461.
  • 462.
  • 463.
  • 464.
  • 465.
  • 466.
  • 467.
  • 468.
  • 469.
  • 470.
  • 471.
  • 472.
  • 473.
  • 474.
  • 475.
  • 476.
  • 477.
  • 478.
  • 479.
  • 480.
  • 481.
  • 482.
  • 483.
  • 484.
  • 485.
  • 486.
  • 487.
  • 488.
  • 489.
  • 490.
  • 491.
  • 492.
  • 493.
  • 494.
  • 495.
  • 496.
  • 497.
  • 498.
  • 499.
  • 500.
  • 501.
  • 502.
  • 503.
  • 504.
  • 505.
  • 506.
  • 507.
  • 508.
  • 509.
  • 510.
  • 511.
  • 512.
  • 513.
  • 514.
  • 515.
  • 516.
  • 517.
  • 518.
  • 519.
  • 520.
  • 521.
  • 522.
  • 523.
  • 524.
  • 525.
  • 526.
  • 527.
  • 528.
  • 529.
  • 530.
  • 531.
  • 532.
  • 533.
  • 534.
  • 535.
  • 536.
  • 537.
  • 538.
  • 539.
  • 540.
  • 541.
  • 542.
  • 543.
  • 544.
  • 545.
  • 546.
  • 547.
  • 548.
  • 549.
  • 550.
  • 551.
  • 552.
  • 553.
  • 554.
  • 555.
  • 556.
  • 557.
  • 558.
  • 559.
  • 560.
  • 561.
  • 562.
  • 563.
  • 564.
  • 565.
  • 566.
  • 567.
  • 568.
  • 569.
  • 570.
  • 571.
  • 572.
  • 573.
  • 574.
  • 575.
  • 576.
  • 577.
  • 578.
  • 579.
  • 580.
  • 581.
  • 582.
  • 583.
  • 584.
  • 585.
  • 586.
  • 587.
  • 588.
  • 589.
  • 590.
  • 591.
  • 592.
  • 593.
  • 594.
  • 595.
  • 596.
  • 597.
  • 598.
  • 599.
  • 600.
  • 601.
  • 602.
  • 603.
  • 604.
  • 605.
  • 606.
  • 607.
  • 608.
  • 609.
  • 610.
  • 611.
  • 612.
  • 613.
  • 614.
  • 615.
  • 616.
  • 617.
  • 618.
  • 619.
  • 620.
  • 621.
  • 622.
  • 623.
  • 624.
  • 625.
  • 626.
  • 627.
  • 628.
  • 629.
  • 630.
  • 631.
  • 632.
  • 633.
  • 634.
  • 635.
  • 636.
  • 637.
  • 638.
  • 639.
  • 640.
  • 641.
  • 642.
  • 643.
  • 644.
  • 645.
  • 646.
  • 647.
  • 648.
  • 649.
  • 650.
  • 651.
  • 652.
  • 653.
  • 654.
  • 655.
  • 656.
  • 657.
  • 658.
  • 659.
  • 660.
  • 661.
  • 662.
  • 663.
  • 664.
  • 665.
  • 666.
  • 667.
  • 668.
  • 669.
  • 670.
  • 671.
  • 672.
  • 673.
  • 674.
  • 675.
  • 676.
  • 677.
  • 678.
  • 679.
  • 680.
  • 681.
  • 682.
  • 683.
  • 684.
  • 685.
  • 686.
  • 687.
  • 688.
  • 689.
  • 690.
  • 691.
  • 692.
  • 693.
  • 694.
  • 695.
  • 696.
  • 697.
  • 698.
  • 699.
  • 700.
  • 701.
  • 702.
  • 703.
  • 704.
  • 705.
  • 706.
  • 707.
  • 708.
  • 709.
  • 710.
  • 711.
  • 712.
  • 713.
  • 714.
  • 715.
  • 716.
  • 717.
  • 718.
  • 719.
  • 720.
  • 721.
  • 722.
  • 723.
  • 724.
  • 725.
  • 726.
  • 727.
  • 728.
  • 729.
  • 730.
  • 731.
  • 732.
  • 733.
  • 734.
  • 735.
  • 736.
  • 737.
  • 738.
  • 739.
  • 740.
  • 741.
  • 742.
  • 743.
  • 744.
  • 745.
  • 746.
  • 747.
  • 748.
  • 749.
  • 750.
  • 751.
  • 752.
  • 753.
  • 754.
  • 755.
  • 756.
  • 757.
  • 758.
  • 759.
  • 760.
  • 761.
  • 762.
  • 763.
  • 764.
  • 765.
  • 766.
  • 767.
  • 768.
  • 769.
  • 770.
  • 771.
  • 772.
  • 773.
  • 774.
  • 775.
  • 776.
  • 777.
  • 778.
  • 779.
  • 780.
  • 781.
  • 782.
  • 783.
  • 784.
  • 785.
  • 786.
  • 787.
  • 788.
  • 789.
  • 790.
  • 791.
  • 792.
  • 793.
  • 794.
  • 795.
  • 796.
  • 797.
  • 798.
  • 799.
  • 800.
  • 801.
  • 802.
  • 803.
  • 804.
  • 805.
  • 806.
  • 807.
  • 808.
  • 809.
  • 810.
  • 811.
  • 812.
  • 813.
  • 814.
  • 815.
  • 816.
  • 817.
  • 818.
  • 819.
  • 820.
  • 821.
  • 822.
  • 823.
  • 824.
  • 825.
  • 826.
  • 827.
  • 828.
  • 829.
  • 830.
  • 831.
  • 832.
  • 833.
  • 834.
  • 835.
  • 836.
  • 837.
  • 838.
  • 839.
  • 840.
  • 841.
  • 842.
  • 843.
  • 844.
  • 845.
  • 846.
  • 847.
  • 848.
  • 849.
  • 850.
  • 851.
  • 852.
  • 853.
  • 854.
  • 855.
  • 856.
  • 857.
  • 858.
  • 859.
  • 860.
  • 861.
  • 862.
  • 863.
  • 864.
  • 865.
  • 866.
  • 867.
  • 868.
  • 869.
  • 870.
  • 871.
  • 872.
  • 873.
  • 874.
  • 875.
  • 876.
  • 877.
  • 878.
  • 879.
  • 880.
  • 881.
  • 882.
  • 883.
  • 884.
  • 885.
  • 886.
  • 887.
  • 888.
  • 889.
  • 890.
  • 891.
  • 892.
  • 893.
  • 894.
  • 895.
  • 896.
  • 897.
  • 898.
  • 899.
  • 900.
  • 901.
  • 902.
  • 903.
  • 904.
  • 905.
  • 906.
  • 907.
  • 908.
  • 909.
  • 910.
  • 911.
  • 912.
  • 913.
  • 914.
  • 915.
  • 916.
  • 917.
  • 918.
  • 919.
  • 920.
  • 921.
  • 922.
  • 923.
  • 924.
  • 925.
  • 926.
  • 927.
  • 928.
  • 929.
  • 930.
  • 931.
  • 932.
  • 933.
  • 934.
  • 935.
  • 936.
  • 937.
  • 938.
  • 939.
  • 940.
  • 941.
  • 942.
  • 943.
  • 944.
  • 945.
  • 946.
  • 947.
  • 948.
  • 949.
  • 950.
  • 951.
  • 952.
  • 953.
  • 954.
  • 955.
  • 956.
  • 957.
  • 958.
  • 959.
  • 960.
  • 961.
  • 962.
  • 963.
  • 964.
  • 965.
  • 966.
  • 967.
  • 968.
  • 969.
  • 970.
  • 971.
  • 972.
  • 973.
  • 974.
  • 975.
  • 976.
  • 977.
  • 978.
  • 979.
  • 980.
  • 981.
  • 982.
  • 983.
  • 984.
  • 985.
  • 986.
  • 987.
  • 988.
  • 989.
  • 990.
  • 991.
  • 992.
  • 993.
  • 994.
  • 995.
  • 996.
  • 997.
  • 998.
  • 999.
  • 1000.
  • 1001.
  • 1002.
  • 1003.
  • 1004.
  • 1005.
  • 1006.
  • 1007.
  • 1008.
  • 1009.
  • 1010.
  • 1011.
  • 1012.
  • 1013.
  • 1014.
  • 1015.
  • 1016.
  • 1017.
  • 1018.
  • 1019.
  • 1020.
  • 1021.
  • 1022.
  • 1023.
  • 1024.
  • 1025.
  • 1026.
  • 1027.
  • 1028.
  • 1029.
  • 1030.
  • 1031.
  • 1032.
  • 1033.
  • 1034.
  • 1035.
  • 1036.
  • 1037.
  • 1038.
  • 1039.
  • 1040.
  • 1041.
  • 1042.
  • 1043.
  • 1044.
  • 1045.
  • 1046.
  • 1047.
  • 1048.
  • 1049.
  • 1050.
  • 1051.
  • 1052.
  • 1053.
  • 1054.
  • 1055.
  • 1056.
  • 1057.
  • 1058.
  • 1059.
  • 1060.
  • 1061.
  • 1062.
  • 1063.
  • 1064.
  • 1065.
  • 1066.
  • 1067.
  • 1068.
  • 1069.
  • 1070.
  • 1071.
  • 1072.
  • 1073.
  • 1074.
  • 1075.
  • 1076.
  • 1077.
  • 1078.
  • 1079.
  • 1080.
  • 1081.
  • 1082.
  • 1083.
  • 1084.
  • 1085.
  • 1086.
  • 1087.
  • 1088.
  • 1089.
  • 1090.
  • 1091.
  • 1092.
  • 1093.
  • 1094.
  • 1095.
  • 1096.
  • 1097.
  • 1098.
  • 1099.
  • 1100.
  • 1101.
  • 1102.
  • 1103.
  • 1104.
  • 1105.
  • 1106.
  • 1107.
  • 1108.
  • 1109.
  • 1110.
  • 1111.
  • 1112.
  • 1113.
  • 1114.
  • 1115.
  • 1116.
  • 1117.
  • 1118.
  • 1119.
  • 1120.
  • 1121.
  • 1122.
  • 1123.
  • 1124.
  • 1125.
  • 1126.
  • 1127.
  • 1128.
  • 1129.

2、UDP(IUdpArqServer(重点)IUdpArqClient(重点)

  略;HPSocket.Net作者的Demo中有示例,见: Demo/udp/UdpArqServer-TestEcho与Demo/udp/UUdpArqClient-TestEcho

三、与线程池一起使用(演示案例为:ITCPPackServer)

  略;HPSocket.Net作者的Demo中有示例,见: Demo/TcpPackServer-TestEcho与TcpPackClient-TestEcho

四、HPSocket扩展Easy组件(部分)

  HPSocket.Net目前提供6个Easy组件和2个WebSocket组件

  • ITcpPortForwarding
  • IHttpEasyServer
  • IHttpsEasyServer
  • IHttpEasyAgent
  • IHttpsEasyAgent
  • IHttpEasyClient
  • IHttpsEasyClient
  • IWebSocketServer
  • IWebSocketAgent
  • ITcpServer<TRequestBodyType>
  • ITcpClient<TRequestBodyType>
  • ITcpAgent<TRequestBodyType>
  • ISslServer<TRequestBodyType>
  • ISslClient<TRequestBodyType>
  • ISslAgent<TRequestBodyType>
  • AsyncQueue

1、TCP端口转发(ITcpPortForwarding)

private readonly ITcpPortForwarding _portForwarding = new HPSocket.Tcp.TcpPortForwarding();

 // tcp端口转发组件是支持通过代理连接到目标服务器的, http和socks5代理可以同时混用, 会随机挑选代理服务器, 支持无限多个
  /*
  _portForwarding.ProxyList = new List<IProxy>
  {
      // 支持http隧道代理
      new HttpProxy
      {
          Host = "127.0.0.1",
          Port = 1080,
          // 支持帐号和密码, 可选
          // UserName = "admin",
          // Password = "pass"
      },
      // 也支持socks5代理
      new Socks5Proxy
      {
          Host = "127.0.0.1",
          Port = 1080,
          // 支持帐号和密码, 可选
          // UserName = "admin",
          // Password = "pass"
      }
  };
  */

  // 事件绑定, 如果你不需要处理数据包和连接黑名单等业务, 只是纯做tcp转发, 事件也无需绑定, 直接[启动按钮]事件的代码设置好属性, 然后start()就ok了
  // 转发组件内部server组件的事件
  _portForwarding.OnServerAccept += OnServerAccept;
  _portForwarding.OnServerReceive += OnServerReceive;
  _portForwarding.OnServerClose += OnServerClose;
  // 转发组件内部agent组件的事件
  _portForwarding.OnAgentConnect += OnAgentConnect;
  _portForwarding.OnAgentReceive += OnAgentReceive;
  _portForwarding.OnAgentClose += OnAgentClose;

...
#region 方法
        // ReSharper disable once MemberCanBeMadeStatic.Local
        private HandleResult OnServerReceive(IServer sender, IntPtr connId, byte[] data)
        {
            AddLog($"OnServerReceive({connId}), data length: {data.Length}");
            return HandleResult.Ok;
        }

        // ReSharper disable once MemberCanBeMadeStatic.Local
        private HandleResult OnServerClose(IServer sender, IntPtr connId, SocketOperation socketOperation, int errorCode)
        {
            AddLog($"OnServerClose({connId}), socket operation: {socketOperation}, error code: {errorCode}");
            return HandleResult.Ok;
        }

        // ReSharper disable once MemberCanBeMadeStatic.Local
        private HandleResult OnAgentConnect(IAgent sender, IntPtr connId, IProxy proxy)
        {
            AddLog($"OnAgentConnect({connId})");
            return HandleResult.Ok;
        }

        // ReSharper disable once MemberCanBeMadeStatic.Local
        private HandleResult OnAgentReceive(IAgent sender, IntPtr connId, byte[] data)
        {
            AddLog($"OnAgentReceive({connId}), data length: {data.Length}");
            return HandleResult.Ok;
        }

        // ReSharper disable once MemberCanBeMadeStatic.Local
        private HandleResult OnAgentClose(IAgent sender, IntPtr connId, SocketOperation socketOperation, int errorCode)
        {
            AddLog($"OnAgentClose({connId}), socket operation: {socketOperation}, error code: {errorCode}");
            return HandleResult.Ok;
        }
#endregion
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.

官方Dome样式

C#-网络通讯框架(一)-HPSocket_TCP_05

2、Http-Easy通讯组件-IHttpEasyServer、IHttpEasyAgent与IHttpEasyClient

// 创建 HttpEasyServer 的实例
using(IHttpEasyServer httpServer = new HttpEasyServer())
{
    // ...其他设置

    // 绑定 OnEasyMessageData 事件
    httpServer.OnEasyMessageData += (sender, id, data) => 
    {
        // data 参数每次都是一个完整的数据包
        // ... 处理 data

        return HttpParseResult.Ok;
    };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
// 创建 HttpEasyAgent 的实例
using(IHttpEasyAgent httpAgent = new HttpEasyAgent())
{
    // ...其他设置

    // 绑定 OnEasyMessageData 事件
    httpAgent.OnEasyMessageData += (sender, id, data) => 
    {
        // data 参数每次都是一个完整的数据包
        // ... 处理 data

        return HttpParseResult.Ok;
    };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
// 创建 HttpEasyClient 的实例
using(IHttpEasyClient httpClient = new HttpEasyClient())
{
    // ...其他设置

    // 绑定 OnEasyMessageData 事件
    httpClient.OnEasyMessageData += (sender, data) => 
    {
        // data 参数每次都是一个完整的数据包
        // ... 处理 data

        return HttpParseResult.Ok;
    };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

3、WebSocket-Easy通讯组件IWebSocketServerIWebSocketAgent

  略

4、TCP数据接收适配器组件(BinaryDataReceiveAdapter-必学)

  数据接收适配器组件比HP-Socket的Pack组件更加灵活。  

  • ITcpServer<TRequestBodyType>/ITcpClient<TRequestBodyType>/ITcpAgent<TRequestBodyType>
  • ISslServer<TRequestBodyType>/ISslClient<TRequestBodyType>/ISslAgent<TRequestBodyType>

    注:<TRequestBodyType>泛型类型对象将在‘数据接收适配器组件’的OnParseRequestBody事件中回调。

以下举例为:ITcpServer<TRequestBodyType> + DataReceiveAdapter定长包数据接收适配器

using (ITcpServer<byte[]> server = new TcpServer<byte[]>
    {
        // 指定数据接收适配器-
        DataReceiveAdapter = new BinaryDataReceiveAdapter(),
    })
{
    // 不需要绑定OnReceive事件
    // 这里解析的请求体事件的data就是BinaryDataReceiveAdapter.ParseRequestBody()返回的数据
    // data的类型就是ITcpServer<byte[]>实例化时指定的byte[]
    server.OnParseRequestBody += (sender, id, data) =>
    {
        Console.WriteLine($"OnParseRequestBody({id}) -> data length: {data.Length}");

        return HandleResult.Ok;
    };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
(1)FixedHeaderDataReceiveAdapter固定包头数据接收适配器

使用场景:数据包的包头长度固定且包头含包体长度。

示例:前4字节标识包体长度(小端字节序)。0x00000003表示包体长度为3字节{ 0x61, 0x62 0x63 }为包体。

{ 0x03, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63 }
  • 1.

FixedHeaderDataReceiveAdapter专为这种结构设计

using System;
using System.Text;
using HPSocket.Adapter;
using Models;
using Newtonsoft.Json;

namespace TcpServerTestEchoAdapter.DataReceiveAdapter
{
    /// <summary>
    /// 固定包头数据接收适配器
    /// ① 子类继承FixedHeaderDataReceiveAdapter;
    /// ② 在自身的构造函数中调用父类构造函数,传入包头长度和最大允许的封包长度; 
    /// ③ 覆盖GetBodySize()方法, 其参数header的长度为构造函数中指定的包头长度, 需用户解析这个参数, 返回实际的body长度 
    /// ④ 覆盖ParseRequestBody()方法, 将当前的bytes反序列化为泛型类型(<TRequestBodyType>)对象
    /// </summary>
    public class PacketDataReceiveAdapter : FixedHeaderDataReceiveAdapter<Packet>
    {
        /// <summary>
        /// 调用父类构造函数,指定固定包头的长度及最大封包长度
        /// </summary>
        public PacketDataReceiveAdapter()
            : base(
                headerSize: 4,        // 这里指定4字节包头
                maxPacketSize: 0x1000 // 这里指定最大封包长度不能超过4K
                )
        {

        }

        /// <summary>
        /// 获取请求体长度
        /// <remarks>子类必须覆盖此方法</remarks>
        /// </summary>
        /// <param name="header">包头,header的长度是构造函数里指定的长度,当接收到了指定长度的包头再调用此方法</param>
        /// <returns>返回包体长度</returns>
        protected override int GetBodySize(byte[] header)
        {
            // 根据业务场景来适配字节序, 两端字节序要保持一致

            // 如果当前环境不是小端字节序
            if (!BitConverter.IsLittleEndian)
            {
                // 转换为小端字节序
                Array.Reverse(header);
            }

            // 因为包头是4字节,所以直接转int并返回
            return BitConverter.ToInt32(header, 0);
        }

        /// <summary>
        /// 解析请求体
        /// <remarks>子类必须覆盖此方法</remarks>
        /// </summary>
        /// <param name="header">包头</param>
        /// <param name="data">包体</param>
        /// <returns></returns>
        protected override Packet ParseRequestBody(byte[] header, byte[] data)
        {
            // 将data反序列化为对象
            // 这里是Packet类的对象
            return JsonConvert.DeserializeObject<Packet>(Encoding.UTF8.GetString(data));
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
(2)FixedSizeDataReceiveAdapter定长包数据接收适配器

包长度固定,每个包都是同样大小,使用这种适配器。

FixedSizeDataReceiveAdapter专为这种结构设计

using HPSocket.Adapter;

namespace TcpServerTestEchoAdapter.DataReceiveAdapter
{
    /// <summary>
    /// 定长包数据接收适配器
    /// </summary>
    public class BinaryDataReceiveAdapter : FixedSizeDataReceiveAdapter<byte[]>
    {
        /// <summary>
        /// 调用父类构造函数,指定定长包长度
        /// </summary>
        public BinaryDataReceiveAdapter()
            : base(
                packetSize: 1024 // 定长包包长1K字节
            )
        {
        }

        /// <summary>
        /// 解析请求体
        /// <remarks>子类必须覆盖此方法</remarks>
        /// </summary>
        /// <param name="data">父类处理好的定长数据</param>
        /// <returns></returns>
        protected override byte[] ParseRequestBody(byte[] data)
        {
            // 因为继承自FixedSizeDataReceiveAdapter<byte[]>,所以这里直接返回了,如果是其他类型请做完转换工作再返回
            return data;
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
(3)TerminatorDataReceiveAdapter结束符数据接收适配器

包头无特征, 包尾使用特定标志作为结束符,使用这种适配器

示例:下面这种包结构以\r\n结尾

hello world 1\r\n
hello world 2\r\n
hello world 3\r\n
  • 1.
  • 2.
  • 3.

TerminatorDataReceiveAdapter专为这种结构设计

using System.Text;
using HPSocket.Adapter;

namespace TcpServerTestEchoAdapter.DataReceiveAdapter
{
    /// <summary>
    /// 结束符数据接收适配器
    /// </summary>
    public class TextDataReceiveAdapter : TerminatorDataReceiveAdapter<string>
    {
        /// <summary>
        /// 调用父类构造函数,指定结束符
        /// </summary>
        public TextDataReceiveAdapter()
            : base(
                terminator: Encoding.UTF8.GetBytes("\r\n") // 指定结束符为\r\n,也就是说每条数据以\r\n结尾,注意编码问题,要两端保持一致
                )
        {
        }

        /// <summary>
        /// 解析请求体
        /// <remarks>子类必须覆盖此方法</remarks>
        /// </summary>
        /// <param name="data">父类已经处理好的不含结束符的数据</param>
        /// <returns></returns>
        protected override string ParseRequestBody(byte[] data)
        {
            // 转换成请求对象, 注意字符编码,要两端保持一致
            return Encoding.UTF8.GetString(data);
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
(4)BetweenAndDataReceiveAdapter区间数据接收适配器

示例:数据包头以某特征符号开始,包尾以其它某特征符号结束

##hello world!## // ##开头,##结尾##hello world!|| // ##开头,||结尾**hello world!|##| // **开头,|##|结尾
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

BetweenAndDataReceiveAdapter专为这种结构设计

using System.Text;
using HPSocket.Adapter;

namespace TcpServerTestEchoAdapter.DataReceiveAdapter
{
    /// <summary>
    /// 区间数据接收适配器
    /// </summary>
    public class HeadTailDataReceiveAdapter : BetweenAndDataReceiveAdapter<string>
    {
        /// <summary>
        /// 调用父类构造函数,指定区间开始和结束特征字符
        /// </summary>
        public HeadTailDataReceiveAdapter() 
            : base( // 例如数据格式是"#*123456*#",其中以#*开头,以*#结尾,中间123456部分是真实数据
                start : Encoding.UTF8.GetBytes("#*"), // 区间起始标志,这里以#*开始,注意编码问题,要两端保持一致
                end : Encoding.UTF8.GetBytes("*#")  // 区间结束标志,这里以*#结束,注意编码问题,要两端保持一致
                )
        {
        }

        /// <summary>
        /// 解析请求体
        /// <remarks>子类必须覆盖此方法</remarks>
        /// </summary>
        /// <param name="data">父类已处理好的不含区间起始标识符的数据</param>
        /// <returns></returns>
        protected override string ParseRequestBody(byte[] data)
        {
            // 转换成请求对象,注意编码问题,要两端保持一致
            return Encoding.UTF8.GetString(data);
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

补充:

1、Event select模型:

  select模型主要用于解决传统tcp通信线程过多的问题,而EventSelect模型则用于解决select模型的效率问题,因为select模型的内部是使用Sleep函数来阻塞线程,然后消耗系统时间片,从而降低了效率,而event+select模型则使用WSAEVENT的通知机制。

2、IOCP 通信模型:

  IOCP(I/O Completion Port),常称I/O完成端口。 IOCP模型属于一种 通讯模型,适用于能控制并发执行的高负载服务器的一个技术。 通俗一点说,就是用于高效处理很多很多的客户端进行数据交换的一个模型。或者可以说,就是能异步I/O操作的模型。优化线程池调度,提高CPU和内存缓冲的命中率。

作者:꧁执笔小白꧂