欧姆龙D4BS安全门开关(工控:C#中的串口,网口和PLC通讯)

Posted

篇首语:青春须早为,岂能长少年。本文由小常识网(cha138.com)小编为大家整理,主要介绍了欧姆龙D4BS安全门开关(工控:C#中的串口,网口和PLC通讯)相关的知识,希望对你有一定的参考价值。

欧姆龙D4BS安全门开关(工控:C#中的串口,网口和PLC通讯)

一.串口通讯方式

首先,串口、UART口、COM口、USB口是指的物理接口形式(硬件)。而TTL、RS-232、RS-485是指的电平标准(电信号)。

串口:串口是一个泛称,UART、TTL、RS232、RS485都遵循类似的通信时序协议,因此都被通称为串口

工控中常用的协议:RS232 RS485

RS232:是电子工业协会(Electronic Industries Association,EIA) 制定的异步传输标准接口,同时对应着电平标准和通信协议(时序),其电平标准:+3V~+15V对应0,-3V~-15V对应1。rs232 的逻辑电平和TTL 不一样但是协议一样

RS485:RS485是一种串口接口标准,为了长距离传输采用差分方式传输,传输的是差分信号,抗干扰能力比RS232强很多。两线压差为-(2~6)V表示0,两线压差为+(2~6)V表示1

常见的D型9针串口(通俗说法)。在台式电脑后边都可以看到。这种接口的协议只有两种:RS-232和RS-485

二.网口通讯方式

TCP/IP 是互联网相关的各类协议族的总称,比如:TCP,UDP,IP,FTP,HTTP,ICMP,SMTP 等都属于 TCP/IP 族内的协议。像这样把与互联网相关联的协议集合起来总称为 TCP/IP。也有说法认为,TCP/IP 是指 TCP 和 IP 这两种协议。还有一种说法认为,TCP/IP 是在 IP 协议的通信过程中,使用到的协议族的统称。

工控中常用的通讯有TCP和UDP

这两个区别就是:TCP 用于在传输层有必要实现可靠传输的情况。由于它是面向有链接并具备顺序控制、重发控制等机制的,所以他可以为应用提供可靠的传输。 而在一方面,UDP 主要用于那些对高速传输和实时性有较高要求的通信或广播通信。 我们举一个通过 IP 电话进行通话的例子。如果使用 TCP,数据在传送途中如果丢失会被重发,但这样无法流畅的传输通话人的声音,会导致无法进行正常交流。而采用 UDP,他不会进行重发处理。从而也就不会有声音大幅度延迟到达的问题。即使有部分数据丢失,也支持会影响某一小部分的通话。此外,在多播与广播通信中也是用 UDP 而不是 TCP。

三.确定PLC硬件

首先要确定PLC是否支持网口或者串口通信,大多数都支持RS232,TCP或者UDP,有的可能要购买拓展模块才能进行通信

四.确定PLC通信协议

通信协议:是指双方实体完成通信或服务所必须遵循的规则和约定。通过通信信道和设备互连起来的多个不同地理位置的数据通信系统,要使其能协同工作实现信息交换和资源共享,它们之间必须具有共同的语言。交流什么、怎样交流及何时交流,都必须遵循某种互相都能接受的规则。这个规则就是通信协议。

以下以欧姆龙FINS通信协议为例

一,握手命令
1、客户端向服务器发送命令
00000000。这个命令长20字节,分成5组4字节。分别是:
头(FINS) + 长度(Hex0C) + 命令(00000000)+ 错误码(00000000) + 客户机节点地址。
46494E53是FINS的ASCII码值,即命令头。
0000000C是命令长度20。
00000000是命令码。
00000000是错误码。
00000005是客户节点地址,即电脑IP地址的末位。
在发送区输入:
46494E53 0000000C 00000000 00000000 00000005
点击发送,PLC立即回应:
46494E53 00000010 00000001 00000000 00000005 00000020
到此我们已经成功地完成了第一步!接下来需要的就是之前介绍过的HostLink协议里面FINS的知识了。

图3 网络调试助手 握手成功
2、这个是服务器端(PLC)向客户端(电脑)发送的命令00000001。这个命令长24字节,分成6组4字节。分别是:
头(FINS)+ 长度(Hex10) + 命令(00000001) + 错误码 + 客户机节点地址 + 服务器地址。
上面的命令错误代码为0,客户端ip地址05已被服务器32(hex20)成功记录。
如果发生错误,服务器回应的命令会包含错误码,连接断开,端口立刻关闭。当连接建立之后,不要再次发送这个命令,否则服务器会返回03错误码,即不支持的命令。全部的错误代码如下:
十六进制错误码 含义
00000000 正常
00000001 头不是‘FINS’ (ASCII code)。
00000002 数据太长。
00000003 不支持的命令。
00000020 所有的连接被占用。
00000021 制定的节点已经连接。
00000022 未被指定的IP地址试图访问一个被保护的节点。
00000023 客户端FINS节点地址超范围。
00000024 相同的FINS节点地址已经被使用。
00000025 所有可用的节点地址都已使用。
二、FINS帧发送命令
如果向服务器发送FINS帧,就要用到这个命令。由于FINS帧长度是12-2012,因此命令长度可变,
头(FINS)+长度+命令(00000002)+错误码+FINS帧。
FINS命令帧内容可参考欧姆龙OMRON PLC之HostLink通讯协议-FINS命令W字/位操作篇,里面有存储区代码和操作代码的内容。
例2-1、读DM0开始的2个通道:
发送:
46494E53 0000001A 00000002 00000000 80000200 20000005 00FF0101 82000000 0002
20000005:20是目标地址,05是源地址;
00FF0101 :0101是读操作;
82000000:82是DM存储区代码,000000是起始地址;
0002:是数量。

返回:
46494E53 0000001A 00000002 00000000 C0000200 05000020 00FF0101 00001234 5678
00001234:0000代表操作成功,1234是读回的第一个字,即D0=Hex1234,
5678:D1=Hex5678

例2-2、W210寄存器写入Hex0388:
发送:
46494E53 0000001C 00000002 00000000 80000200 20000005 00FF0102 B100D200 00010388
20000005:
20是目标地址,05是源地址;
00FF0102:0102是写操作代码;
B100D200:B1是W字代码,00D2是起始地址,Hex00D2=212,;
00010388:是写入数量,0388是写入首个内容;
回应:
46494E53 00000016 00000002 00000000 C0000200 05000020 00FF0102 0000
0102后面紧跟的0000代表写入成功。
例2-3、W210寄存器读取:
发送:
46494E53 0000001A 00000002 00000000 80000200 20000005 00FF0101 B100D200 0001
20000005:
20是目标地址,05是源地址;
00FF0101:0101是读操作代码;
B100D200:B1是W字代码,00D2是起始地址,Hex00D2=212,;
0001:是读取数量。
回应:
46494E53 00000018 00000002 00000000 C0000200 05000020 00FF0101 00000388
0102后面紧跟的0000代表读取成功,W210=Hex0388
例2-4、强制W212.01=On:
发送:
46494E53 0000001C 00000002 00000000 80000200 20000005 00FF2301 00010001 3100D401
20000005:
20是目标地址,05是源地址;
00FF2301:2301是强制操作代码;
00010001:前面的0001是数量,后面的0001代表强制置位操作;
3100D401:31是W位代码,00D401是起始地址,Hex00D4.01=212.01。
回应:
46494E53 00000016 00000002 00000000 C0000200 05000020 00FF2301 0000
2301后面紧跟的0000表示操作成功。
注意在CX-Programmer查看窗口中W212.01的值1后面的(强制)字样。

图4 网络调试助手 强制置位

图5 CX-Programmer 强制置位成功
例2-5、强制W212.01=Off:
发送:
46494E53 0000001C 00000002 00000000 80000200 20000005 00FF2301 00010000 3100D401
20000005:
20是目标地址,05是源地址;
00FF2301:2301是强制操作代码;
00010000:0001是数量,0000代表强制复位操作;
3100D401:31是W位代码,00D401是起始地址,Hex00D4.01=212.01。
回应:
46494E53 00000016 00000002 00000000 C0000200 05000020 00FF2301 0000
2301后面紧跟的0000表示操作成功。
例2-6、取消W212.01强制:
发送:
46494E53 0000001C 00000002 00000000 80000200 20000005 00FF2301 0001FFFF 3100D401
20000005:
20是目标地址,05是源地址;
00FF2301:2301是强制操作代码;
0001FFFF:0001是数量,FFFF代表取消强制操作;
3100D401:31是W位代码,00D401是起始地址,Hex00D4.01=212.01。
回应:
46494E53 00000016 00000002 00000000 C0000200 05000020 00FF2301 0000
2301后面紧跟的0000表示操作成功。
注意在CX-Programmer查看窗口中W212.01的值0后面的(强制)字样不见了,表示已经成功地取消了强制。

图6 网络调试助手 取消强制


图7 CX-Programmer 取消强制成功

与CIO不同,对于W、A、H及D 这样的寄存器进行位操作,其实不用强制操作,直接写入更简洁,可以减少操作步骤,下面以W位操作为例介绍。

例2-7、W212.01 按位置位:

发送:
46494E53 0000001B 00000002 00000000 80000200 20000005 00FF0102 3100D401 000101
20000005:
20是目标地址,05是源地址;
00FF0102:0102是寄存器写操作代码;
3100D401:31是W位代码,00D401是地址,Hex00D4.01=212.01;

000101:0001是数量,01代表写入值1;
回应:

46494E53 00000016 00000002 00000000 C0000200 20000005 00FF0102 0000

0102后面紧跟的0000表示操作成功。

例2-8、W212.01 按位复位:
发送:
46494E53 0000001B 00000002 00000000 80000200 20000005 00FF0102 3100D401 000100

20000005:20是目标地址,05是源地址;
00FF0102:0102是寄存器写操作代码;
3100D401:31是W位代码,00D401是地址,Hex00D4.01=212.01;

000100:0001是数量,00代表写入值0;

回应:

46494E53 00000016 00000002 00000000 C0000200 20000005 00 FF0102 0000

0102后面紧跟的0000表示操作成功。

五.使用C#进行通信

1.串口

串口在C#中使用的是SerialPort这个类

要注意通讯协议中报文内容是16进制,还是ASCII码,还是就是普通的字符串,有格式的话注意发送和接收的报文需要转换

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.IO.Ports;using System.Threading;using System.Windows.Forms;public class SerialOP : IDisposable            private SerialPort Comport = new SerialPort();        private AutoResetEvent _manualEvent = new AutoResetEvent(false);        private object _lockRead = new object();        private object _lockWrite = new object();        private byte[] _reivedData;        private string reive=null;        private object onRecive =new object();        public delegate void UpdateByteDelegate(byte[] reive);        public event UpdateByteDelegate UpdateByte;        /// <summary>        /// 打开串口        /// </summary>        /// <param name="com"></param>        /// <param name="bps"></param>        /// <param name="databit"></param>        /// <param name="stopbit"></param>        /// <param name="check"></param>        public bool Open(string com, string bps, string databit, string stopbit, string check)                    try                            if (Comport.IsOpen)                    Comport.Close();                Thread.Sleep(100);                //串口端口号                Comport.PortName = com;                //串口波特率                Comport.BaudRate = int.Parse(bps);                //串口数据位                Comport.DataBits = int.Parse(databit);                //串口停止位                switch (stopbit)                                    case "0":                        Comport.StopBits = StopBits.None;                        break;                    case "1":                        Comport.StopBits = StopBits.One;                        break;                    case "1.5":                        Comport.StopBits = StopBits.OnePointFive;                        break;                    case "2":                        Comport.StopBits = StopBits.Two;                        break;                    default:                        Comport.StopBits = StopBits.None;                        break;                                //串口奇偶校验                switch (check)                                    case "无":                        Comport.Parity = Parity.None;                        break;                    case "奇校验":                        Comport.Parity = Parity.Odd;                        break;                    case "偶校验":                        Comport.Parity = Parity.Even;                        break;                    default:                        Comport.Parity = Parity.None;                        break;                                //Comport.ReceivedBytesThreshold = 1;//1字节触发数据获取                //Comport.DataReceived += new SerialDataReceivedEventHandler(OnReceived);                                       Comport.Open();                Comport.DtrEnable = true;                Comport.RtsEnable = true;                return true;                        catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("连续打开关闭串口出现错误:" + ex.Message,"SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                return false;                            /// <summary>        /// 检测串口是否打开        /// </summary>        /// <returns></returns>        private bool IsOpen()                    try                            if (Comport == null)                    return false;                if (Comport.IsOpen)                    return true;                else                    return false;                        catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("检测串口是否打开出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                return false;                            private void OnReceived(object sender, SerialDataReceivedEventArgs e)                             try                            lock (onRecive)                                    byte[] reive = new byte[Comport.BytesToRead];                    Comport.Read(reive, 0, Comport.BytesToRead);                    UpdateByte.Invoke(reive);                                                      catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("串口接收数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                                      finally                            _manualEvent.Set();                                          /// <summary>        /// 字符串转ASII码发送        /// </summary>        /// <returns></returns>        public void Send_ASCII(string str)                    try                            lock (_lockWrite)                                    var ByteSendW = Encoding.ASCII.GetBytes(str );//把发送数据转换为ASCII数组                    Comport.Write(ByteSendW, 0, ByteSendW.Length);                                        catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("串口发送数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 发送16进制数组,需要用,隔开        /// </summary>        /// <param name="Hex"></param>        /// <param name="check"></param>        public void Send_HEX(string Hex)                    try                            lock (_lockWrite)                                    //16进制字符串转换成16进制数组                    var HEX = Hex.Split(',').Select(temp => "0x" + temp).Select(temp => (byte)Convert.ToInt32(temp, 16)).ToArray();                    Comport.Write(HEX, 0, HEX.Length);                                        catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("串口发送数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 发送字符串不转换        /// </summary>        /// <param name="str"></param>        public void Send_String(string str)                    try                            lock (_lockWrite)                                    Comport.Write(str);                                        catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("串口发送数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 接收ASCII码,并转换成字符串        /// </summary>        /// <param name="str"></param>        public void Read_ASCII(out string str)                    str = "error";            try                            lock (_lockRead)                                    if (Comport.BytesToRead == 0)                                            LogHelper.error("缓存区没有数据");                        return;                                        for (int i = 0; i < 100; i++)//读取100个字节                                            if (Comport.BytesToRead == 0)                                                    str = reive;                            reive = null;                            break;                                                string reivestring = "";                        _reivedData = new byte[1];                        Comport.Read(_reivedData, 0, _reivedData.Length);                        reivestring = Encoding.ASCII.GetString(_reivedData);                                             reive += reivestring;                        //Comport.DiscardInBuffer();                                                                           catch (Exception ex)                            str = ex.ToString();                LogHelper.error(ex.ToString());                MessageBox.Show("串口读取数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 接收字符串,不进行任何转换        /// </summary>        /// <param name="str"></param>        public void Read_String(out string str)                    str = "error";            try                            lock (_lockRead)                                    if (Comport.BytesToRead == 0)                                            LogHelper.error("缓存区没有数据");                        return;                                        for (int i = 0; i < 100; i++)//读取100个字节                                            if (Comport.BytesToRead == 0)                                                    str = reive;                            reive = null;                            break;                                                _reivedData = new byte[1];                        Comport.Read(_reivedData, 0, _reivedData.Length);                                       reive += _reivedData[0].ToString() + " ";                                                            catch (Exception ex)                            str = ex.ToString();                LogHelper.error(ex.ToString());                MessageBox.Show("串口读取数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 接收到16进制,转成字符串        /// </summary>        /// <param name="str"></param>        public void Read_HEX_String(out string str)                    str = "error";            try                            lock (_lockRead)                                    if (Comport.BytesToRead == 0)                                            LogHelper.error("缓存区没有数据");                        return;                                        for (int i = 0; i < 100; i++)//读取100个字节                                            if (Comport.BytesToRead == 0)                                                    reive = reive.Substring(0, reive.Length - 1);//移除最后一位逗号                            str = reive;                            reive = null;                            break;                                                _reivedData = new byte[1];                        Comport.Read(_reivedData, 0, _reivedData.Length);                        reive += _reivedData[0].ToString("x2").ToUpper() + ",";                                                            catch (Exception ex)                            str = ex.ToString();                LogHelper.error(ex.ToString());                MessageBox.Show("串口读取数据出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 关闭串口        /// </summary>        public void Close()                    try                            if (Comport.IsOpen)                    Comport.Close();                        catch (Exception ex)                            LogHelper.error(ex.ToString());                MessageBox.Show("关闭串口出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                            /// <summary>        /// 释放串口        /// </summary>        public void Dispose()                    try                            if (Comport.IsOpen)                    Comport.Close();                Comport.Dispose();                        catch (Exception ex)                                     LogHelper.error(ex.ToString());                MessageBox.Show("释放串口出现错误:" + ex.Message, "SerialPort---Message", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);                        //Comport.DataReceived -= new SerialDataReceivedEventHandler(Comport_DataReceived);                /// <summary>        /// CRC16校验        /// </summary>        /// <param name="data"></param>        /// <returns></returns>        public string CRCCalc(string data)                    string[] datas = data.Split(' ');            List<byte> bytedata = new List<byte>();            foreach (string str in datas)                            bytedata.Add(byte.Parse(str, System.Globalization.NumberStyles.AllowHexSpecifier));                        byte[] crcbuf = bytedata.ToArray();            //计算并填写CRC校验码            int crc = 0xffff;            int len = crcbuf.Length;            for (int n = 0; n < len; n++)                            byte i;                crc = crc ^ crcbuf[n];                for (i = 0; i < 8; i++)                                    int TT;                    TT = crc & 1;                    crc = crc >> 1;                    crc = crc & 0x7fff;                    if (TT == 1)                                            crc = crc ^ 0xa001;                                        crc = crc & 0xffff;                                        string[] redata = new string[2];            redata[1] = Convert.ToString((byte)((crc >> 8) & 0xff), 16);            redata[0] = Convert.ToString((byte)((crc & 0xff)), 16);            return redata[0].ToUpper() + " " + redata[1].ToUpper();            

2.网口

网口分客户端和服务器,协议有TCP和UDP

以下以TCP为例

TCP客户端

   public class TcpClient           public bool connected =false ;        Socket  socketClient;//客户端接口        Task  threadAcceptClient,//客户端接收线程              threadClient; //客户端线程        private string IpAddress = string.Empty;        private int Port = 0;        public TcpClient(string IpAddress, int Port)                    this.IpAddress = IpAddress;            this.Port = Port;            ClientConnectSever();              /// <summary>      /// 客户端连接服务器      /// </summary>        public bool ClientConnectSever()                    IPAddress ip = IPAddress.Parse(IpAddress);            IPEndPoint port = new IPEndPoint(ip, Port);//服务器port            //创建TCP类型端口            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);            try                            socketClient.Connect(port);                connected = true;                return true;                        catch (Exception ex)                            LogHelper.error(IpAddress+"连接服务器失败:" + ex.Message);                return false;                            public void ColseConnect()                    socketClient.Close();                        public bool ClientSendData(string data)                               if (!connected)                            LogHelper.error(IpAddress+"未连接到服务器");                return false;                        byte[] msg = Encoding.Default.GetBytes(data);            try                            NetworkStream netStream = new NetworkStream(socketClient);                           netStream.Write(msg, 0, msg.Length);                netStream.Flush();                return true;                        catch (Exception ex)                            LogHelper.error(IpAddress+"发送失败:" + ex.Message);                return false;                            public string ClientReadData()                    try                            if (!connected)                                    LogHelper.error(IpAddress+"未连接到服务器");                    return "error";                                NetworkStream netStream = new NetworkStream(socketClient);                byte[] dataSize = new byte[1024];                netStream.Read(dataSize, 0, dataSize.Length);                var Result = Encoding.Default.GetString(dataSize).TrimEnd('\\0');                if (Result.Length > 1)                    return Result;                else                    return string.Empty;                //this.rtb_accept1.Rtf = Encoding.Unicode.GetString(message);                        catch (Exception ex)                            LogHelper.error(IpAddress+"读取数据失败:" + ex.Message);                return "error";                               

TCP服务器

  public class TcpServer                  public delegate void UpdateObjectDelegate(object sender);        public event UpdateObjectDelegate UpdataDataString;        public event UpdateObjectDelegate UpdateMessage;        private string IpAddress = string.Empty;        private int Port = 0;        public TcpServer(string IpAddress, int Port)                    this.IpAddress = IpAddress;            this.Port = Port;                static Socket serverSocket;        List<Socket> ClientList = new List<Socket>(); //客户端列表        public bool connected = false;        public void StartListen()                                     Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                         serverSocket = socket;                //ip port                  socket.Bind(new IPEndPoint( IPAddress.Parse(IpAddress), Port));                //listen                  socket.Listen(10);//连接等待队列                             ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptClientConnect), socket);                                        private void AcceptClientConnect(object socket)                    var serverSocket = socket as Socket;            UpdateMessage.Invoke("服务器开始监听");                    while (true)                            try                                    var proxSocket = serverSocket.Accept();                    ClientList.Add(proxSocket);                    UpdateMessage.Invoke((object)("客户端" + proxSocket.RemoteEndPoint.ToString() + "连接上了"));                    //接受消息                      ThreadPool.QueueUserWorkItem(new WaitCallback(this.ReceiveData), proxSocket);                    connected = true;                                catch (Exception e)                                    UpdateMessage.Invoke("服务器监听错误:" + e.ToString());                    connected = false;                                            private void ReceiveData(object obj)                    Socket proxSocket = obj as Socket;            byte[] data = new byte[1024 * 1024];            while (true)                            int readLen = 0;                try                                    readLen = proxSocket.Receive(data, data.Length,0);                                    //if (readLen <= 0)                    //                    //    //客户端正常退出                      //    UpdateMessage.Invoke(string.Format("客户端0正常退出", proxSocket.RemoteEndPoint.ToString()));                    //    ClientList.Remove(proxSocket);                    //    CloseListen(proxSocket);                    //    connected = false;                    //    return;//方法结束->终结当前接受客户端数据的异步线程                      //                    string txt = Encoding.Default.GetString(data, 0, readLen).TrimEnd('\\0');                    if(txt.Length>1)                    UpdataDataString.Invoke(txt);                                catch (Exception ex)                                    //异常退出时                      UpdateMessage.Invoke(string.Format("客户端0非正常退出,原因1", proxSocket.RemoteEndPoint.ToString(), ex.ToString()));                    ClientList.Remove(proxSocket);                    CloseListen(proxSocket);                    connected = false;                    return;                                                                   private void CloseListen(Socket proxSocket)                    try                            if (proxSocket.Connected)                                    proxSocket.Shutdown(SocketShutdown.Both);                    proxSocket.Close(100);                    connected = false;                                        catch (Exception)                            UpdateMessage("服务器关闭发生异常");                connected = false;                            public bool ServerSendData(string msg)                    try                            foreach (Socket s in this.ClientList)                   //服务端广播式发送给客户端                    (s as Socket).Send(Encoding.Default.GetBytes(msg));                                return true;                        catch                            return false;                        

相关参考

广州凌华工控机(强悍如斯可扩展18路串口或6路千兆以太网方案强势来袭)

集微网消息随着工控机应用逐渐从传统的冶金、电力、石化等行业转向储能、自动化、物联网等新兴领域。持续变化的市场也愈发需要与时俱进的工控机方案,一机多网、丰富接口以及高可靠性等成为当下应用端最迫切的诉求。...

施耐德EZD塑壳断路器(电气采购找中晨工控,自动化方案也找中晨工控)

...,与施耐德、驱易、安拓、西门子、德力西、罗克韦尔、欧姆龙、正泰、ABB、魏德米勒、明纬、菲尼克斯、霍尼韦尔、上海二工、三菱、常熟开关、威图

武汉欧姆龙开关(欧姆龙微动开关SS-5GL在体外诊断仪中的应用)

体外诊断医疗器械是指制造商预定用于体外检查从人体取得的样品,包括血液及组织供体的,无论单独使用或是组合使用的任何医疗器械,包括试剂、试剂产品、校准材料、控制材料、成套工具、仪表、装置、设备或系统。体外...

欧姆龙限位开关(欧姆龙微动开关_欧姆龙微动开关D3VJ,实现微波炉联锁监控)

...EC)的规定,所有微波炉出厂必须至少有一个联锁装置,而欧姆龙微动开关,可以实现联锁监控装置,确保人们安全;微波炉的工作原理是什么?欧姆龙微动开关在微波炉中的应用又在哪里呢?一.微波炉的工作原理微波炉,是一...

欧姆龙开关(智能锁携欧姆龙开关让你的家更安全)

现代社会人们对住房的要求也不段在提升高,不再是能遮风挡雨就能满足了,更多考虑的是居家安全.随着智能家居产业蓬勃发展,越来越多的人将目光投向了外观时尚、功能多样化的智能锁。智能锁是近几年在我国家居行业兴起的...

欧姆龙安全开关(欧姆龙开关:欧姆龙微动开关D3VJ在执行器上的应用)

欧姆龙微动开关也是比较全面的,应用于多种场景及领域。开关在我们的生活中是很常见的了,它能够为我们控制各种电器设备的开启和停止;欧姆开关作为发展趋势,已成为世界著名的机械自动化和电子产品生产企业;虽然是...

欧姆龙PLC用锂电池(工控中最常见的7种PLC编程语言,据说精通5种以上就可以月薪过万)

plc编程软件有哪些?1、欧姆龙plc编程软件欧姆龙plc编程软件集成了CX-ProgrammerV9.5,能够为欧姆龙PLC编程提供全面的软件支持,本版本为最新版,全面支持32/64位WIN8系统,为多国语言版,支持简体中文。能为网络、可编程终端及伺...

应用程序的main方法中有以下(C# 中的Async 和 Await 的用法详解)

众所周知C#提供Async和Await关键字来实现异步编程。在本文中,我们将共同探讨并介绍什么是Async和Await,以及如何在C#中使用Async和Await。同样本文的内容也大多是翻译的,只不过加上了自己的理解进行了相关知识点的补充,如果...

欧姆开关(0欧姆电阻在电路中的作用)

我是李工,我来了,今天讲一下0欧姆电阻。0欧姆电阻的阻值是多少?0欧姆电阻即电阻标值为0欧姆的电阻,多用于PCB设计等方面,是一种理想电阻。那0欧姆电阻是表示没有电阻吗?当然不是,0欧姆电阻的阻值不是0欧姆,只是...

德国SIEMENS西门子(工控界的泰山北斗,PLC界的扛把子,西门子PLC介绍以及软件分享)

...言,而是称霸PLC界的三大霸主,S指西门子,F指三菱,C指欧姆龙。这三家PLC几乎占领了中国自动化界白分之九十以上的市场。其中西门子是欧系的代表,三菱时日系的代表,而欧姆龙更像是一个美国大兵娶了日本歌姬集合的产物...