C# 工业设备通讯系列(持续更新中...) 文章目录C# 工业设备通讯系列技术博文持续更新...第一篇【C# 工业通讯】封装一个健壮的 TCP Socket 客户端基类心跳与异常处理核心痛点解决方案通用客户端基类设计关键技术点核心代码实现设计要点总结总结C# 工业设备通讯系列技术博文持续更新…系列说明 本系列基于实际工业机械臂控制项目分享 C# 底层 Socket 通讯封装、设计模式应用、高频数据异步读取以及单通道通讯设计的实战经验。第一篇【C# 工业通讯】封装一个健壮的 TCP Socket 客户端基类心跳与异常处理在工业自动化开发中与机械臂、PLC 等设备的 TCP 通讯是基础。本文分享一个基于 C# Socket 封装的通用客户端基类重点解决了连接状态探测Poll、KeepAlive 心跳保活以及异常断开的统一处理。核心痛点在使用原生 Socket 开发工业设备通讯时我们经常遇到以下问题•假连接 socket.Connected 属性并不总是准确的网线被拔了可能还是返回 true。•心跳保活 长时间无数据传输路由器或防火墙可能会切断连接导致对端认为你已离线。•代码复用 每个设备都写一套连接、断开、发送逻辑维护成本高且容易出现遗漏。解决方案通用客户端基类设计我设计了一个抽象类作为底层通讯基类将通用的连接管理逻辑抽离出来子类只需关注具体的业务协议。关键技术点•精准的状态检测 使用 Poll 方法配合 SelectMode.SelectRead 来探测连接是否真实有效。•底层 KeepAlive 通过 IOControl 设置 TCP 层的保活机制防止连接被静默断开。•事件驱动 定义 NetworkErrorEvent将网络异常统一抛给上层处理。核心代码实现usingSystem;usingSystem.Net;usingSystem.Net.Sockets;usingSystem.Runtime.InteropServices;usingSystem.Text;namespaceJupiter.Device{/// summary/// 设备客户端基类 - 封装底层 Socket 通讯细节/// 所有机械臂/PLC等设备的通讯类均应继承此类/// /summarypublicabstractclassDeviceClient{privateSocketmSocketClientnewSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);publicstringIP{get;privateset;}publicintPort{get;privateset;}/// summary/// 连接设备入口方法处理重复连接和地址变更/// /summarypublicboolConnect(stringstrIp,intiPort){// 如果已连接且地址未变直接返回避免重复建连if(null!mSocketClientIsConnected()){if(strIp!this.IP||iPort!this.Port){this.Disconnect();}else{returntrue;}}returnthis.ConnectDeviceServer(strIp,iPort);}/// summary/// 真实连接状态检测/// 解决 Connected 属性不准的问题网线拔了可能还是 true/// /summarypublicboolIsConnected(){try{if(mSocketClientnull||!mSocketClient.Connected)returnfalse;// 核心使用 Poll 探测连接状态// 如果 SelectRead 为 true 且 Available 为 0说明连接已被对端关闭boolstateChangedmSocketClient.Poll(1000,SelectMode.SelectRead);if(stateChangedmSocketClient.Available0){returnfalse;}returntrue;}catch(Exceptionex){LogHelper.Error(DeviceClient,ex,连接检测异常);returnfalse;}}/// summary/// 建立物理连接并开启 KeepAlive/// /summaryprivateboolConnectDeviceServer(stringstrIp,intiPort){try{this.IPstrIp;this.PortiPort;mSocketClientnewSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);mSocketClient.Connect(newIPEndPoint(IPAddress.Parse(strIp),iPort));// 【重点】开启 TCP KeepAlive 防止连接被静默断开// 参数说明启用(1) 首次探测时间(5000ms) 探测间隔(500ms)uintdummy0;byte[]optValnewbyte[Marshal.SizeOf(dummy)*3];BitConverter.GetBytes((uint)1).CopyTo(optVal,0);BitConverter.GetBytes((uint)5000).CopyTo(optVal,Marshal.SizeOf(dummy));BitConverter.GetBytes((uint)500).CopyTo(optVal,Marshal.SizeOf(dummy)*2);mSocketClient.IOControl(IOControlCode.KeepAliveValues,optVal,null);OnConnected(mSocketClient);returntrue;}catch(Exceptionex){LogHelper.Error(DeviceClient,ex,连接失败);returnfalse;}}/// summary/// 发送数据UTF-8 文本协议/// /summaryprotectedboolSendData(stringstr){try{byte[]dataEncoding.UTF8.GetBytes(str);return(mSocketClient.Send(data)data.Length);}catch(SocketExceptionex){// 发送失败且连接断开触发网络错误事件if(!IsConnected())NetworkErrorEvent?.Invoke(this,ex.SocketErrorCode);returnfalse;}}/// summary/// 断开连接/// /summarypublicvoidDisconnect(){try{if(mSocketClient!nullmSocketClient.Connected){mSocketClient.Shutdown(SocketShutdown.Both);mSocketClient.Close();}}catch(Exceptionex){LogHelper.Error(DeviceClient,ex,断开连接异常);}finally{OnDisconnected();}}/// summary/// 网络异常事件供上层订阅/// /summarypublicdelegatevoidOnNetworkError(DeviceClientsender,SocketErroriErrCode);publiceventOnNetworkErrorNetworkErrorEvent;// 抽象方法强制子类实现连接成功/断开后的业务逻辑protectedabstractvoidOnConnected(Socketsock);protectedabstractvoidOnDisconnected();}}设计要点总结设计点说明IsConnected() 重写用 Poll Available 替代简单的 Connected 属性判断能准确检测网线拔出等物理断开TCP KeepAlive通过 IOControl 设置底层保活参数首次探测 5s 后开始间隔 500ms有效防止路由器/防火墙切断空闲连接抽象方法隔离OnConnected / OnDisconnected 交由子类实现基类只负责连接生命周期管理事件驱动异常NetworkErrorEvent 让上层决定如何处理异常重试、告警、降级等基类不耦合具体策略总结通过封装这个通用客户端基类我们将繁琐的 Socket 状态管理、字节流转换和异常捕获下沉到了基类。后续开发具体的机械臂控制类时只需要继承它并实现 OnConnected 即可大大提升了代码的可维护性。

相关新闻

最新新闻

OCR如何成为LLM应用的数据入口:从图片到结构化输出的完整实践

OCR如何成为LLM应用的数据入口:从图片到结构化输出的完整实践

如果你最近在做 AI 应用,尤其是 RAG(检索增强生成)、文档问答、知识库建设这类方向,大概率会遇到一个非常现实的问题:喂给大模型的知识,很多根本不是"文本文件"。 项目合同是扫描件,…

2026/8/28 22:35:46
OpenAI下调GPT-5.6价格:先算清成本账再切换模型

OpenAI下调GPT-5.6价格:先算清成本账再切换模型

OpenAI 下调 GPT 5.6 Sol 价格的消息传出来后,很多人第一反应是“省钱了”,第二反应是“我要不要把 API 调用都切过去”。我的看法不太一样:如果只是盯着单次调用便宜了多少,大概率会错过这次调整真正值得做的事情。 价格下调当然…

2026/8/28 22:35:46
C++运算符重载实践:为复数类实现“大于号”比较与浮点数精度处理

C++运算符重载实践:为复数类实现“大于号”比较与浮点数精度处理

1. 项目概述:当复数遇上“大于号”在C的世界里,运算符重载是个老生常谈却又魅力无穷的话题。它让自定义类型也能像内置类型(如int,double)一样,使用,-,*,/甚至&#xff0…

2026/8/28 22:35:46
课程培训实战指南:从选型到落地的完整技术方案解析

课程培训实战指南:从选型到落地的完整技术方案解析

课程培训实战指南:从选型到落地的完整技术方案解析 在当前的数字化学习环境中,搭建一套完整的课程培训系统,往往是许多企业和教育机构面临的共性需求。从技术选型到终落地,背后涉及用户端、管理端、支付与内容分发等多个环节。本文…

2026/8/28 22:35:46
最小截平方和法(LTS):高崩溃点稳健回归原理与Python实现

最小截平方和法(LTS):高崩溃点稳健回归原理与Python实现

1. 项目概述:从“拟合”到“稳健”的回归进化在数据分析和数学建模的世界里,回归分析是当之无愧的基石。无论是预测房价、分析广告点击率,还是研究药物剂量与疗效的关系,我们都在试图用一个或多个变量(自变量&#xff…

2026/8/28 22:35:46
AI创作者如何融合艺术设计科学,构建稳定高效创作工作流

AI创作者如何融合艺术设计科学,构建稳定高效创作工作流

AI 工具在这两年的迭代速度,已经让“会不会用”成了一道很低的门槛。最明显的例子是 AI 绘画和 AI 编程:以前要花几个月才能掌握的技能,现在用自然语言描述清楚需求,就能得到可用的结果。但门槛降下来之后,创作者之间的…

2026/8/28 22:30:46