C# TCP通讯(客户端)

一、介绍

给大家安利一个我亲手打磨封装的宝藏工具类 PTcpClient基于.NET 原生的 TcpClient 撸出来的自用 TCP 客户端,自己用着直呼真香,索性拿出来分享给大伙。

直接帮你把底层 NetworkStream 字节发送、UTF-8 编码全都包办了,发消息不用再折腾底层细节;还自带连接状态、IP 端口、线程间隔这些全套状态管理,省心又好控。支持优雅启停,靠着取消令牌和全局运行状态,随时能安稳暂停、恢复消息监听,不用粗暴断开。内置日志联动,调试报错一键打印,接收的数据还能通过通知中心自动广播分发,其他模块直接就能订阅使用。

不管是设备通讯、数据采集还是远程指令交互这种 TCP 长连接场景,拿过来就能直接用,稳定又省事,再也不用每次项目都重复写一套 TCP 客户端逻辑了~

二、代码

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

namespace PiFramework
{
    public class PTcpClient
    {
        private Thread receiveThread;
        private int ReceiveThreadSleep = 150;
        private TcpClient client;
        private NetworkStream stream;
        private string serverIp = null;
        private int serverPort = 0;
        private bool m_IsRunConnect = false;
        
        public string objectname { get; set; }
        protected CancellationTokenSource _cts = new CancellationTokenSource();
        private string _NowReceivedMessage = "";
        
        public string NowReceivedMessage
        {
            get
            {
                while (!_cts.IsCancellationRequested )
                {
                    //string.IsNullOrEmpty(_NowReceivedMessage)
                    Thread.Sleep(ReceiveThreadSleep);
                    if (string.IsNullOrEmpty(_NowReceivedMessage))
                    {
                        continue;
                    }
                    string temp = _NowReceivedMessage;
                    _NowReceivedMessage = "";
                     return temp;
                }
               throw (new Exception("线程停止"));
            }
        }

        public bool IsRunConnect
        {
            get
            {
                return m_IsRunConnect;
            }
            set
            {
                m_IsRunConnect = value;
            }
        }
        public string Ip
        {
            get
            {
                return serverIp;
            }
            set
            {
                serverIp = value;
            }

        }
        public int Port
        {
            get
            {
                return serverPort;
            }
            set
            {
                serverPort = value;
            }

        }
        public string Name
        {
            get
            {
                return objectname;
            }
            set
            {
                objectname = value;
            }
        }
        public int ThreadSleepTime
        {
            get
            {
                return ReceiveThreadSleep;

            }
            set
            {
                ReceiveThreadSleep = value;
            }
        }


        public PTcpClient(string ip, int port, string name, int threadSleepTime = 150)
        {
            serverIp = ip;
            serverPort = port;
            ReceiveThreadSleep = threadSleepTime;
            objectname = name;
            PNotificationCenter.Instance().AddObserver("SysRunstatus", this.OnNotification);
        }


        public bool Connect()
        {
            CloseConnection();
            client = new TcpClient();

            if (client != null && client.Connected)
            {
                PLog.Instance.Debug("已连接到服务器。");
                return true;
            }
            if (serverIp == null || serverPort == 0)
            {
                PLog.Instance.Warning("服务器地址或端口错误。");
                return false;
            }
            try
            {
                PLog.Instance.Debug("正在连接服务器...");
                IAsyncResult result = client.BeginConnect(serverIp, serverPort, null, null);
                bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
                if (!success)
                {
                    // 连接超时,关闭连接并抛出异常或者进行其他处理
                    client.Close();
                    throw new Exception("连接超时");
                }
                else
                {
                    // 连接成功,结束连接操作
                    client.EndConnect(result);
                    stream = client.GetStream();
                    PLog.Instance.Debug("已连接到服务器。");
                    receiveThread = new Thread(ReceiveLoop);
                    receiveThread.IsBackground = true;
                    receiveThread.Start();
                    m_IsRunConnect = true;
                    _cts = new CancellationTokenSource();
                    return true;
                }
            }
            catch (Exception ex)
            {
                PLog.Instance.Error($"连接错误: {ex.Message}");
                return false;
            }
        }

        public bool isConnected()
        {
            if (client != null && client.Connected)
            {
                //  PLog.Instance.Debug("已连接到服务器。");
                return true;
            }
            return false;
        }
        public void SendData(string message)
        {
            if (client == null || !client.Connected)
            {
                PLog.Instance.Error("未连接到服务器。");
                return;
            }
            try
            {
                byte[] data = Encoding.UTF8.GetBytes(message);
                stream.Write(data, 0, data.Length);
                PLog.Instance.Debug($"已发送: {message}");
            }
            catch (Exception ex)
            {
                PLog.Instance.Error($"发送错误: {ex.Message}");
            }
        }

        public void OnNotification(string name, object sender, Dictionary<string, object> userInfo)
        {
            if (name == "SysRunstatus")
            {
                bool sysStatus = Convert.ToBoolean(userInfo["status"]);
                PLog.Instance.Debug("接受到信号:" + sysStatus);
                if (sysStatus)
                {
                    _cts = new CancellationTokenSource();
                    return;
                }
                _cts.Cancel();
            }
        }


        protected void ReceiveLoop()
        {
            try
            {
                while (client != null && client.Connected)
                {
                    if (stream.DataAvailable)
                    {
                        byte[] buffer = new byte[1024];
                        int bytesRead = stream.Read(buffer, 0, buffer.Length);
                        if (bytesRead > 0)
                        {
                            string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                            _NowReceivedMessage = receivedMessage;
                            PLog.Instance.Debug(this.objectname +"收到: " + receivedMessage);
                            PNotificationCenter.Instance().PostNotification(objectname, this, new Dictionary<string, object> { { "message", receivedMessage } });
                        }
                    }
                    Thread.Sleep(ReceiveThreadSleep);
                }
            }
            catch (Exception ex)
            {
                PLog.Instance.Error($"接收错误: {ex.Message}");
            }
        }
        public void CloseConnection()
        {
            try
            {
                stream?.Close();
                client?.Close();
                m_IsRunConnect = false;
                PLog.Instance.Debug("连接已关闭。");
            }
            catch (Exception ex)
            {
                PLog.Instance.Error($"关闭错误: {ex.Message}");
            }
        }
    }
}

三、主要接口 说明

public PTcpClient(string ip, int port, string name, int threadSleepTime = 150)

ip:服务器 IP 地址。

port:服务器端口。

name:客户端标识名称,用于通知消息的发送者名称。

threadSleepTime:接收线程的休眠间隔(毫秒),默认 150ms。值越小,消息响应越快,但 CPU 占用越高。

public void SendData(string message)

功能:向服务器发送 UTF-8 编码的字符串消息。

条件:必须已连接,否则记录错误并返回。

异常:发送过程中异常会被捕获并记录。

public void CloseConnection()

功能:关闭网络流和 TcpClient,将 IsRunConnect 设为 false。

注意:该方法不会自动停止接收线程,但接收线程中的 client.Connected 检测会因连接关闭而退出循环。

public bool isConnected()

功能:返回当前是否处于连接状态(基于 TcpClient.Connected 属性)

四、使用

1.创建DLL

2.DLL名称

3.创建类

把代码复制上去,PLog (日志)、PNotificationCenter(观察者)、TestDll (测试程序) 这些都用得上,上一章有说明

一种很好用的设计模式https://blog.csdn.net/qq_54122623/article/details/160167275?spm=1011.2124.3001.6209

引用DLL

4.添加按钮

创建连接、断开、发送、接收 这几个按钮来调试它。

cs 复制代码
       PTcpClient pTcpClient = null;
       private void Form1_Load(object sender, EventArgs e)
       {
           //创建对象
           pTcpClient = new PTcpClient("127.0.0.1",8080,"myClient");
       }

       private void button5_Click(object sender, EventArgs e)
       {

           //  连接服务器
           bool isok  =  pTcpClient.Connect();
           if (isok)
           {
               PLog.Instance.Debug("连接成功过");
               return;
           }
           PLog.Instance.Error("连接失败!");
           return ;
       }

       private void button7_Click(object sender, EventArgs e)
       {

           //  发送数据
           bool isok = pTcpClient.isConnected();
           if (!isok) {

               PLog.Instance.Error("未连接!");
               return;
           }
           pTcpClient.SendData(pTcpClient.Name + "发送了数据");
       }

       private void button6_Click(object sender, EventArgs e)
       {
           //断开连接
           pTcpClient.CloseConnection();
       }

       private void button8_Click(object sender, EventArgs e)
       {
           //接收数据
           Task task = Task.Run(DoWork);
       }

       void DoWork()
       {
           string mess = pTcpClient.NowReceivedMessage;
           if (mess == "A") {
               PLog.Instance.Log("接受到我想要的信息:" + mess);
           }
       }

5.接收数据有两种方法

一种是加个线程等待数据。

cs 复制代码
    private void button8_Click(object sender, EventArgs e)
    {
        //接收数据
        Task task = Task.Run(DoWork);
    }

    void DoWork()
    {
        string mess = pTcpClient.NowReceivedMessage;
        if (mess == "A") {
            PLog.Instance.Log("接受到我想要的信息:" + mess);
        }
    }

另一种是PNotificationCenter。

发布事件

订阅事件

cs 复制代码
      PNotificationCenter.Instance().AddObserver(tcpid, this.OnNotification);

接收事件

cs 复制代码
    public void OnNotification(string name, object sender, Dictionary<string, object> userInfo)
    {

        if (name == tcpid) { 
        
        
            string mess = userInfo["message"].ToString();

            PLog.Instance.Log( mess);


        }

    }

五、效果

C# TCP通讯(客户端)例子

相关推荐
CDN3601 小时前
360CDN日志分析避坑指南:如何通过upstream_response_time精准定位源站瓶颈
网络·php·运维开发
microxiaoxiao2 小时前
Deepin桌面环境配置TigerVNC远程桌面完整指南
linux·服务器·网络·windows
仍然.2 小时前
传输层协议UDP
网络·网络协议·udp
艾莉丝努力练剑2 小时前
【Linux网络】Linux 网络编程:HTTP(一)协议初识
linux·运维·服务器·网络·tcp/ip·计算机网络·http
Yang96112 小时前
小型化高稳定,IN902 喇叭天线赋能铁路高速运维
网络
思麟呀2 小时前
在C++基础上理解CSharp-3
开发语言·c++·c#
Anastasiozzzz2 小时前
深度解析 AI 时代的“TCP/IP协议”:Agent-to-Agent (A2A) 通信架构与多智能体协同底层逻辑
大数据·开发语言·网络·数据库·网络协议·tcp/ip·架构
艾莉丝努力练剑2 小时前
【Linux网络】Linux 网络编程:HTTP(二)HTTP协议请求应答宏观格式(附代码演示)
linux·运维·服务器·网络·tcp/ip·计算机网络
xlq223222 小时前
56.自定义协议
linux·服务器·网络·网络协议