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, 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.添加按钮
创建连接、断开、发送、接收 这几个按钮来调试它。
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, Dictionary<string, object> userInfo) { if (name == tcpid) { string mess = userInfo["message"].ToString(); PLog.Instance.Log( mess); } }五、效果
C# TCP通讯(客户端)例子
