C#里创建一个TCP客户端连接类

C#里创建一个TCP客户端连接类

TCP客户端,一般分为两种,一种是同步收发数据,这种需要开发线程来处理。

如果连接比较多,就会消耗比较多线程。

另外一种,就是使用异步连接,这样只需要一个线程,就可以连接很多个。

在这里使用异步的方式来连接,例子的代码如下:

cs 复制代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ModbusTCP.Modbus
{
    class MyTcp : TcpClient
    {
        public delegate void Connect_Resp(); //声明委托
        public delegate void Recv_Resp(byte[] data); //声明委托

        private Connect_Resp _ConnectSucces;
        private Connect_Resp _ConnectFail;
        private Recv_Resp _Recv_Resp;

        public event Action _SendSuccess;
        public event Action _SendFail;

        internal class StateObject
        {
            public TcpClient client = null;
            public int totalBytesRead = 0;
            public const int BufferSize = 1024;
            public string readType = null;
            public byte[] buffer = new byte[BufferSize];
            public StringBuilder messageBuffer = new StringBuilder();
        }

        public string ErrorString { get; set; }

        public MyTcp(Connect_Resp con_succes, Connect_Resp con_fail, Recv_Resp recv)
        {
            _ConnectSucces = con_succes;
            _ConnectFail = con_fail;
            _Recv_Resp = recv;
        }
        public void ClientConnect(string strIP, int port)
        {
            BeginConnect(strIP, port, new AsyncCallback(ConnectCallback), this);
        }

        public virtual void ConnectCallback(IAsyncResult ar)
        {
            MyTcp t = (MyTcp)ar.AsyncState;
            try
            {
                if (t != null && t.Client != null)
                {
                    t.EndConnect(ar);
                    if (t.Connected)
                    {
                        OnConnectSuccess(t);
                    }
                    else
                    {
                        OnConnectFailure("连接失败");
                    }
                }
                else
                {
                    OnConnectFailure("连接对象为空");
                }
            }
            catch (SocketException se)
            {
                OnConnectFailure($"连接发生套接字错误: {se.SocketErrorCode} - {se.Message}");
            }
            catch (Exception ex)
            {
                OnConnectFailure($"连接发生未知错误: {ex.Message}");
            }
        }
        private void OnConnectSuccess(MyTcp tcpClient)
        {
            _ConnectSucces?.Invoke();
            AsyncRead(tcpClient);
        }

        private void OnConnectFailure(string errorMessage)
        {
            ErrorString = errorMessage;
            _ConnectFail?.Invoke();
        }

        /// <summary>
        /// 异步读TCP数据
        /// </summary>
        /// <param name="sock"></param>
        private void AsyncRead(MyTcp sock)
        {
            StateObject state = new StateObject
            {
                client = sock
            };
            NetworkStream stream = sock.GetStream();

            if (stream.CanRead)
            {
                try
                {
                    IAsyncResult ar = stream.BeginRead(state.buffer, 0, StateObject.BufferSize,
                            new AsyncCallback(TCPReadCallBack), state);
                }
                catch (Exception e)
                {
                    ErrorString = "Network IO problem " + e.ToString();
                    _ConnectFail?.Invoke();
                }
            }
        }
        /// <summary>
        /// TCP读数据的回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void TCPReadCallBack(IAsyncResult ar)
        {
            StateObject state = (StateObject)ar.AsyncState;
            //主动断开时
            if ((state.client == null) || (!state.client.Connected))
                return;
            NetworkStream nas = state.client.GetStream();

            try
            {
                int numberOfBytesRead = nas.EndRead(ar);
                if (numberOfBytesRead > 0)
                {
                    state.totalBytesRead += numberOfBytesRead;

                    byte[] dd = new byte[numberOfBytesRead];
                    Array.Copy(state.buffer, 0, dd, 0, numberOfBytesRead);

                    //接收数据
                    _Recv_Resp?.Invoke(dd);

                    nas.BeginRead(state.buffer, 0, StateObject.BufferSize,
                            new AsyncCallback(TCPReadCallBack), state);
                }
                else
                {
                    //被动断开时 
                    nas.Close();
                    state.client.Close();

                    nas = null;
                    state = null;

                    _ConnectFail?.Invoke();
                }
            }
            catch (Exception)
            {
                nas = null;
                state = null;

                _ConnectFail?.Invoke();
            }
        }
        public void Send(byte[] buffer, int offset, int size)
        {
            NetworkStream stream = GetStream();
            if (stream.CanWrite)
            {
                stream.BeginWrite(buffer, offset, size, new AsyncCallback(TCPSendCallBack), this);
            }
        }
        private void TCPSendCallBack(IAsyncResult ar)
        {
            try
            {
                MyTcp tcp = (MyTcp)ar.AsyncState;
                NetworkStream stream = tcp.GetStream();
                stream.EndWrite(ar);
                _SendSuccess?.Invoke();
            }
            catch (Exception ex)
            {
                ErrorString = $"发送数据时发生错误: {ex.Message}";
                _SendFail?.Invoke();
            }
        }
        //组合两个缓冲区的数据,并产生一个新的缓冲区返回
        public static byte[] CombineBytes(byte[] firstBytes, int firstIndex, int firstLength,
            byte[] secondBytes, int secondIndex, int secondLength)
        {
            MemoryStream ms = new MemoryStream();
            ms.Write(firstBytes, firstIndex, firstLength);
            ms.Write(secondBytes, secondIndex, secondLength);
            byte[] bytes = ms.ToArray();
            ms.Close();
            return bytes;
        }

    }
}
相关推荐
wangbing11251 小时前
平台介绍-modbus设备调试
java
黑十1 小时前
PyTorch 报 “no CUDA GPUs are available“ 怎么办?3 步排查
服务器·网络·人工智能·pytorch·python
西索斯coding1 小时前
gpt-image-2.5-sunburst 和 gemini-3.1-flash-image 差多少?60 组项目素材的成功成本评测框架
java·linux·gpt·ai
wuminyu2 小时前
Java字节码学习总结:字节码如何加载、解析和执行
java·linux·c语言·jvm·c++
Flynn Liang2 小时前
大模型怎么自己调函数?Spring AI 2.0 Tool Calling 自动循环原理 + 完整时序图
java·人工智能·spring·agent·函数调用·springai·toolcalling
乌暮3 小时前
请求进门先安检:Spring 拦截器与统一功能实战指南
java·开发语言·后端·学习·spring
学长毕设3 小时前
基于SpringBoot的烘焙商品商品系统-附源码
java·spring boot·后端
updayday8544 小时前
客户附件不该发往旧邮箱,如何在发送前拦截 - Ping64 邮件安全管控
大数据·网络·数据库·安全·智能路由器
其实防守也摸鱼4 小时前
Chrome 扩展安全攻防实录:从攻击面到防御实践
开发语言·前端·网络·chrome·安全·web安全·php
小茬粥4 小时前
QEMU 宿主机网卡实例发现与采集脚本(标准 Linux / Proxmox VE 适配版)COLT_CMDB_QEMU_IFACE.sh
网络