S7netplus v0.9.0中IsAvailable属性的改进方法
在对PLC在线检测的时候,可能会用到IsAvailable属性,但是这个属性在S7netplus v0.9.0版本中并不能让人放心使用。
1、问题所在
通过查看S7netplus v0.9.0的源码,可以得知在IsAvailable属性中调用了Connect方法,这就相当于重新建立了连接,使得原来的连接失效。在代码中含有“TODO: Fix This”的注释,可见源码也认为这样写代码不妥。
/// <summary> /// Returns true if a connection to the PLC can be established /// </summary> public bool IsAvailable { //TODO: Fix This get { try { OpenAsync().GetAwaiter().GetResult(); return true; } catch { return false; } } }
2、问题解决
在旧版本(S7netplus v0.1.9 2018/5/14)的源码中,是通过Socket连接来验证PLC是否可用的,如下所示。
/// <summary> /// Returns true if a connection to the plc can be established /// </summary> public bool IsAvailable { get { #if NETFX_CORE return (!string.IsNullOrWhiteSpace(IP)); #else using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { return Connect(socket) == ErrorCode.NoError; } #endif } }
根据这个版本的IsAvailable属性的实现代码,可以在S7netplus v0.9.0的基础上自己封装相同作用的IsAvailable属性代码,以解决当前版本的问题。
/// <summary> /// PLC连接是否可用 /// <remarks>PLC初始化以后才有连接意义,返回ping结果</remarks> /// <remarks>该版本中Plc的IsAvailable属性等价于Open,因此不能在连接后使用该属性</remarks> /// </summary> public bool IsAvailable { get { if (_plc == null || string.IsNullOrWhiteSpace(_plc.IP)) { return false; } using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { string errorMessage; var ret = Connect(socket, _plc.IP, _plc.Port, out errorMessage) == ErrorCode.NoError; if (!ret) { LastErrorMsg = errorMessage; } return ret; } } } /// <summary> /// 连接Socket /// </summary> /// <param name="socket">socket对象</param> /// <param name="ip">IP地址</param> /// <param name="port">端口</param> /// <param name="errorMessage">错误信息</param> /// <returns>连接状态码</returns> private static ErrorCode Connect(Socket socket, string ip, int port, out string errorMessage) { var errorCode = ErrorCode.NoError; errorMessage = string.Empty; try { var server = new IPEndPoint(IPAddress.Parse(ip), port); socket.Connect(server); return errorCode; } catch (SocketException sex) { // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx errorCode = sex.SocketErrorCode == SocketError.TimedOut ? ErrorCode.IPAddressNotAvailable : ErrorCode.ConnectionError; errorMessage = sex.Message; } catch (Exception ex) { errorCode = ErrorCode.ConnectionError; errorMessage = ex.Message; } return errorCode; }
3、问题延申
在上面实现的IsAvailable属性代码中,使用Socket连接的方法固然能够实现PLC的连接测试,但是要想控制连接超时时间就不容易了,这里主要解决超时时间的问题。
C#中有Ping对象,可以直接通过IP来和目标机器进行连接,也能够设置超时时间,因此是个不错的选择。需要注意的是,这个方法并不能判断指定端口是否打开,因此只能在PLC建立连接之后使用。
/// <summary> /// 使用ping判断PLC是否在线 /// <remarks>这个方法不能测试端口是否开放</remarks> /// </summary> public bool IsPlcOnline { get { if (_plc == null || string.IsNullOrWhiteSpace(_plc.IP)) { return false; } return PingPlc(_plc.IP); } } /// <summary> /// 对PLC进行ping操作 /// </summary> /// <param name="ip">IP地址</param> /// <returns>是否可以ping通</returns> private static bool PingPlc(string ip) { var ping = new Ping(); var reply = ping.Send(ip, 1000); return reply != null && reply.Status == IPStatus.Success; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器