当前位置: 首页 > news >正文

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通讯(客户端)例子

http://www.cnnetsun.cn/news/2684718.html

相关文章:

  • Keil MDK与CMSIS-Build构建差异分析与解决方案
  • 保险业AI落地实战:破解数据、技术与组织三大核心挑战
  • 别再死记硬背了!用购物车和订单系统实战,5分钟搞懂UML类图的6种关系
  • 从被动到主动:构建智能Slack机器人的架构演进与实践
  • 从保温杯到电路板:聊聊‘导热系数’这个参数,以及我们怎么在实验室里测它
  • SpringBoot项目里时间传参总乱套?手把手教你用@JsonFormat和@DateTimeFormat搞定前后端日期格式
  • 《HarmonyOS技术精讲》五:实战项目 ── 智能支架助手
  • 保姆级教程:在VMware里给openEuler虚拟机扩容磁盘,不重启搞定LVM分区
  • 告别模型降级与频繁断联:企业级 API 中转选型实测复盘及 Claude 避坑指南
  • C语言:文件操作(2)
  • LabVIEW 2021生成EXE后报表报错7?手把手教你添加NIReport.llb和LVClass文件
  • 监控画面总有雪花噪点?深入拆解海思/安霸芯片里的3D降噪技术到底是怎么工作的
  • LaMa图像修复模型训练避坑指南:从动态掩膜生成到损失函数调参
  • 从Cadence Tempus到Synopsys PT:手把手教你搞定两大神器下的check_timing检查
  • Flutter集成OpenAI API:构建流式AI对话应用的全栈实践
  • BK7231U SPI烧录避坑指南:从玄学Python脚本到稳定一键操作的进化之路
  • 超越基础教程:手把手教你用Niagara模块组合,打造更真实的游戏场景烟雾(含SubImageIndex随机技巧)
  • 避坑指南:动手仿真增量调制(∆M)过载与量化噪声(附MATLAB/Python代码)
  • 告别塑料玩具:聊聊工业级DLP光机在3D打印与扫描中如何‘扛’住产线环境
  • 基于GPT与Pytest的API自动化测试生成实践
  • Shell脚本进阶:用mapfile的-C回调函数,实现大文件读取的实时进度条
  • Arduino Uno + THB6128驱动板:从光耦限流计算到完整接线,搞定两相四线步进电机的保姆级避坑教程
  • 医疗AI智能体:从架构设计到临床落地的核心路径
  • 从晶体对称性到代码实现:高阶力常数插值中那些被你忽略的‘约束’到底怎么用?
  • 别再只聊NeRF了!3DGS实战:用Colmap+3D Gaussian Splatting快速重建你的房间(附完整代码)
  • 告别nRF Mesh APP:用ESP32自制BLE Mesh配网器,深入理解Provisioner底层事件与回调
  • 别再死记硬背了!用Input.GetAxis搞定Unity角色移动与旋转,附完整代码避坑
  • 倍福CX5130控制松下伺服:EtherCAT组网与轴参数调试避坑全记录
  • 别再手动调轮廓线了!分享一个我优化过的UE4高亮材质,直接拖进项目就能用
  • 别再乱编译OpenSSL了!CentOS 8/RHEL 8用户必须知道的系统库兼容性‘潜规则’