在工控领域,用到网络的地方有两个,一是跟平台通信(把现场数据上传到平台、服务器),二是读取一些用网线连接的仪器。两个方面在使用Socket的时候,有某些需要注意的地方。
一、跟平台通信
跟平台通信使用TCP连接。如果工控机性能不错,使用DotNetty这样的库也未尝不可,毕竟其稳定性是经过验证的。但DotNetty开发成本高,现场也没有高并发的情况,大多时候我们都是使用Socket做简单的开发。在开发的过程中,我们会遇到几个问题:
(1)断网重连。
(2)超时时间。
(3)同步与异步接收数据。
1、断网重连
无论网络多好,都会有断开的时候,这就要求我们在网络断开之后,能自动识别,并再次连接服务器。
Socket使用下面的语句判断网络是否断开:
bool isConnected = !mSocket.Poll(1000, SelectMode.SelectRead);
2、超时时间
.NET里的Socket是没有连接超时设置功能的,如果在网络不通的情况下,一个连接会需要20s左右的等待时间,这样大多时候是不满足我们的期待的。
这里我们使用的辅助手段是这样的:在启动连接的时候,同时启动一个定时器。在定时器到点的时候,强制关闭正在进行的连接。虽然看起来不太优雅,但这已几乎是唯一的方法。
private void ConnectWithTimeout()
{
mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
isInit = false;
mTimeoutObject = new ManualResetEvent(false);
try
{
mSocket.BeginConnect(mIPEndPoint, ConnectCallback, mSocket);
if (!mTimeoutObject.WaitOne(WebTimeOut, false))
{
LogToFile.WriteWebExceptionLog("SocketHelper ConnectWithTimeout Timeout");
CloseSocket();
}
else if (isInit)
{
mSocket.BeginReceive(DataBuffer, 0, DataBuffer.Length, 0, ReceiveCallback, mSocket);
}
}
catch (Exception ex)
{
isInit = false;
LogToFile.WriteWebExceptionLog("SocketHelper ConnectWithTimeout " + ex.Message);
}
}
3、同步与异步接收数据
使用同步还是异步,这需要看具体的使用需求。使用同步的话,流程逻辑会简单一些,但需要卡住等待;而异步就不需要等待,但会让代码逻辑稍微复杂一些。
同步接收数据代码如下:
public byte[] Receive()
{
try
{
int len = mSocket.Receive(DataBuffer);
if (len > 0)
{
byte[] data = new byte[len];
Array.Copy(DataBuffer, 0, data, 0, len);
string dataStr = ConvertCode.ByteArrayToString(data, data.Length);
LogToFile.WriteWebNormalLog("SocketHelper Receive: " + dataStr);
return data;
}
}
catch (Exception ex)
{
LogToFile.WriteWebExceptionLog("SocketHelper Receive " + ex.Message);
}
return null;
}
异步接收数据代码如下:
mSocket.BeginReceive(DataBuffer, 0, DataBuffer.Length, 0, ReceiveCallback, null);
private void ReceiveCallback(IAsyncResult ar)
{
try
{
if (mSocket != null)
{
int len = mSocket.EndReceive(ar);
if (len > 0)
{
byte[] data = new byte[len];
Array.Copy(DataBuffer, 0, data, 0, len);
string dataStr = ConvertCode.ByteArrayToString(data, data.Length);
LogToFile.WriteWebNormalLog("SocketHelper Receive: " + dataStr);
try
{
ReceiveDataEvent(data);
}
catch (Exception ex)
{
LogToFile.WriteWebExceptionLog("SocketHelper ReceiveCallback2 " + ex.Message);
}
}
bool isConnected = !mSocket.Poll(1000, SelectMode.SelectRead);
if (isConnected)
{
mSocket.BeginReceive(DataBuffer, 0, DataBuffer.Length, 0, ReceiveCallback, null);
}
}
}
catch (Exception ex)
{
LogToFile.WriteWebExceptionLog("SocketHelper ReceiveCallback " + ex.Message);
isInit = false;
CloseSocket();
}
}
二、跟仪器通信
仪器各种各样,他们使用的通信方式也会千差万别。大多数情况下,仪器还是会使用TCP连接,但有的时候会使用UDP,甚至要求工控机作为服务端。
这里提出一点需要注意的,就是跟仪器连接的使用,一般不使用异步的方法,甚至只能使用同步的方法。有的仪器,用异步接收,会有连接不上的情况出现。因为仪器跟工控机的距离很短,连接也很稳定,所以使用同步的方法问题也不太,程序还能写得更简单一些。
同步接收数据:
/// <summary>
/// 同步接收数据
/// </summary>
/// <returns>接收到的数据</returns>
public byte[] Receive()
{
try
{
int len = mSocket.Receive(DataBuffer);
if (len > 0)
{
byte[] data = new byte[len];
Array.Copy(DataBuffer, 0, data, 0, len);
string dataStr = ConvertCode.ByteArrayToString(data, data.Length);
LogToFile.WriteWebNormalLog("DeviceSocketHelper Receive: " + dataStr);
return data;
}
}
catch (Exception ex)
{
LogToFile.WriteWebExceptionLog("DeviceSocketHelper Receive " + ex.Message);
}
return null;
}
几个类库的源代码下载:https://download.csdn.net/download/lweiyue/10648659