C# TCP通讯(客户端)
一、介绍给大家安利一个我亲手打磨封装的宝藏工具类PTcpClient基于.NET 原生的 TcpClient 撸出来的自用 TCP 客户端自己用着直呼真香索性拿出来分享给大伙。直接帮你把底层 NetworkStream 字节发送、UTF-8 编码全都包办了发消息不用再折腾底层细节还自带连接状态、IP 端口、线程间隔这些全套状态管理省心又好控。支持优雅启停靠着取消令牌和全局运行状态随时能安稳暂停、恢复消息监听不用粗暴断开。内置日志联动调试报错一键打印接收的数据还能通过通知中心自动广播分发其他模块直接就能订阅使用。不管是设备通讯、数据采集还是远程指令交互这种 TCP 长连接场景拿过来就能直接用稳定又省事再也不用每次项目都重复写一套 TCP 客户端逻辑了二、代码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, Dictionarystring, 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 Dictionarystring, 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.创建DLL2.DLL名称3.创建类把代码复制上去PLog 日志、PNotificationCenter观察者、TestDll 测试程序 这些都用得上上一章有说明一种很好用的设计模式https://blog.csdn.net/qq_54122623/article/details/160167275?spm1011.2124.3001.6209引用DLL4.添加按钮创建连接、断开、发送、接收 这几个按钮来调试它。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.接收数据有两种方法一种是加个线程等待数据。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。发布事件订阅事件PNotificationCenter.Instance().AddObserver(tcpid, this.OnNotification);接收事件public void OnNotification(string name, object sender, Dictionarystring, object userInfo) { if (name tcpid) { string mess userInfo[message].ToString(); PLog.Instance.Log( mess); } }五、效果C# TCP通讯客户端例子