|
@@ -18,10 +18,12 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
private static Thread _SendThread;// 发送的线程
|
|
|
private static Thread heartBeatThread;// 断开超时链接的线程
|
|
|
private static Queue _SendConidQueue = Queue.Synchronized(new Queue()); // 存储历史记录数据的队列
|
|
|
- private static string connectionTimeOut = ConfigurationManager.AppSettings["ConnectionTimeOut"];
|
|
|
- private static string ConnectionTimeOutInterval = ConfigurationManager.AppSettings["ConnectionTimeOutInterval"];
|
|
|
- private static string ModBusQueryInterval = ConfigurationManager.AppSettings["ModBusQueryInterval"];
|
|
|
- private static bool isTimeRuning = false;
|
|
|
+ private static string connectionTimeOut = ConfigurationManager.AppSettings["ConnectionTimeOut"]; // 心跳间隔时间(毫秒)
|
|
|
+ private static string ConnectionTimeOutInterval = ConfigurationManager.AppSettings["ConnectionTimeOutInterval"]; // 执行断开静默链接间隔时间毫秒
|
|
|
+ private static string ModBusQueryInterval = ConfigurationManager.AppSettings["ModBusQueryInterval"]; // MODBUS轮询获取抄表数据时间毫秒
|
|
|
+ private static string IsHaveModBus = ConfigurationManager.AppSettings["IsHaveModBus"]; // 是否有MODBUS类设备1:有;0:无
|
|
|
+ private static bool isTimeRuning = false; // MODBUS定时器是否执行中
|
|
|
+ private static bool isHeartBeatRuning = false; // 心跳进程是否执行中
|
|
|
|
|
|
private static Dictionary<string, object> deviceTypes;
|
|
|
|
|
@@ -34,6 +36,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
|
|
|
private delegate void ShowMsg(string msg, ListBox lb);
|
|
|
private ShowMsg AddMsgDelegate;
|
|
|
+ private DateTime dtStartTime = DateTime.Now;
|
|
|
#endregion
|
|
|
|
|
|
public MainForm_TCP()
|
|
@@ -46,12 +49,6 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
try
|
|
|
{
|
|
|
server.MarkSilence = true;
|
|
|
- server.DisconnectSilenceConnections(5000);//测试将事假调长
|
|
|
-
|
|
|
- // 本机测试没必要改地址,有需求请注释或删除
|
|
|
- ///this.txtIpAddress.ReadOnly = true;
|
|
|
- this.groupBox3.Height = 0;
|
|
|
- this.splitContainer1.Height = this.groupBox1.Height + 75;
|
|
|
|
|
|
// 加个委托显示msg,因为on系列都是在工作线程中调用的,ui不允许直接操作
|
|
|
AddMsgDelegate = new ShowMsg(AddMsg);
|
|
@@ -68,7 +65,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
// 其他设置
|
|
|
// server.NoDelay = true;
|
|
|
|
|
|
- SetAppState(AppState.Stoped);
|
|
|
+ SetAppState(AppState.UnStart);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
@@ -97,13 +94,16 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
if (server.Start())
|
|
|
{
|
|
|
SetAppState(AppState.Started);
|
|
|
- AddMsg($"$Server Start OK -> ({ip}:{port})", lbReceiveData);
|
|
|
+ AddMsg($" > Server Start OK -> ({ip}:{port}) 服务启动成功", lbReceiveData);
|
|
|
|
|
|
deviceTypes = ProtocolAnalysisTools.GetDeviceTypes();
|
|
|
|
|
|
- StartModBusSendTimer();// 启动ModBus定时发送读取数据任务
|
|
|
+ if ("1".Equals(IsHaveModBus))
|
|
|
+ {
|
|
|
+ StartModBusSendTimer(); // 启动ModBus定时发送读取数据任务
|
|
|
+ }
|
|
|
|
|
|
- StartOrResumeHeartBeatThread();// 启动心跳超市检测
|
|
|
+ StartOrResumeHeartBeatThread(); // 启动心跳超时检测
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -125,16 +125,17 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
private void btnStop_Click(object sender, EventArgs e)
|
|
|
{
|
|
|
SetAppState(AppState.Stoping);
|
|
|
+
|
|
|
// 停止服务
|
|
|
- AddMsg("$Server Stop", lbReceiveData);
|
|
|
if (server.Stop())
|
|
|
{
|
|
|
+ AddMsg($" > Server Stop 服务停止成功", lbReceiveData);
|
|
|
heartBeatThread.Suspend();
|
|
|
SetAppState(AppState.Stoped);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- AddMsg($"$Stop Error -> {server.ErrorMessage}({server.ErrorCode})", lbErrorData);
|
|
|
+ AddMsg($" > Stop Error -> {server.ErrorMessage}({server.ErrorCode})", lbErrorData);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -165,10 +166,36 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
void SetAppState(AppState state)
|
|
|
{
|
|
|
appState = state;
|
|
|
- this.btnStart.Enabled = (appState == AppState.Stoped);
|
|
|
+ string status = "";
|
|
|
+ switch (state)
|
|
|
+ {
|
|
|
+ case AppState.UnStart:
|
|
|
+ status = "未启动";
|
|
|
+ break;
|
|
|
+ case AppState.Starting:
|
|
|
+ status = "启动中";
|
|
|
+ break;
|
|
|
+ case AppState.Started:
|
|
|
+ status = "已启动";
|
|
|
+ break;
|
|
|
+ case AppState.Stoping:
|
|
|
+ status = "停止中";
|
|
|
+ break;
|
|
|
+ case AppState.Stoped:
|
|
|
+ status = "已停止";
|
|
|
+ break;
|
|
|
+ case AppState.Error:
|
|
|
+ status = "错误";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ status = "";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ this.toolStripStatusLabel1.Text = "状态:" + status;
|
|
|
+ this.btnStart.Enabled = (appState == AppState.Stoped || appState == AppState.UnStart);
|
|
|
this.btnStop.Enabled = (appState == AppState.Started);
|
|
|
- this.txtIpAddress.Enabled = (appState == AppState.Stoped);
|
|
|
- this.txtPort.Enabled = (appState == AppState.Stoped);
|
|
|
+ this.txtIpAddress.Enabled = (appState == AppState.Stoped || appState == AppState.UnStart);
|
|
|
+ this.txtPort.Enabled = (appState == AppState.Stoped || appState == AppState.UnStart);
|
|
|
this.txtDisConn.Enabled = (appState == AppState.Started);
|
|
|
this.btnDisconn.Enabled = (appState == AppState.Started && this.txtDisConn.Text.Length > 0);
|
|
|
}
|
|
@@ -190,7 +217,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
{
|
|
|
lb.Items.RemoveAt(0);
|
|
|
}
|
|
|
- lb.Items.Add(DateTime.Now.ToString() + msg);
|
|
|
+ lb.Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + msg);
|
|
|
lb.TopIndex = lb.Items.Count - (int)(lb.Height / lb.ItemHeight);
|
|
|
LogUtil.WriteLog(msg);
|
|
|
}
|
|
@@ -213,7 +240,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
ushort port = 0;
|
|
|
if (server.GetRemoteAddress(connId, ref ip, ref port))
|
|
|
{
|
|
|
- AddMsg($" > [{connId},OnAccept] -> PASS({ip.ToString()}:{port})", lbReceiveData);
|
|
|
+ AddMsg($" > [{connId},OnAccept] -> PASS({ip.ToString()}:{port}) 建立链接成功", lbReceiveData);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -237,7 +264,12 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
#region OnHandShake(IServer sender, IntPtr connId)
|
|
|
private HandleResult OnHandShake(IServer sender, IntPtr connId)
|
|
|
{
|
|
|
- AddMsg($" > [{connId},OnHandShake]", lbReceiveData);
|
|
|
+ string ip = string.Empty;
|
|
|
+ ushort port = 0;
|
|
|
+ if (server.GetRemoteAddress(connId, ref ip, ref port))
|
|
|
+ {
|
|
|
+ AddMsg($" > [{connId},OnHandShake] -> PASS({ip.ToString()}:{port}) 链接握手成功", lbReceiveData);
|
|
|
+ }
|
|
|
return HandleResult.Ok;
|
|
|
}
|
|
|
#endregion
|
|
@@ -245,8 +277,13 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
#region OnSend(IServer sender, IntPtr connId, byte[] bytes)
|
|
|
HandleResult OnSend(IServer sender, IntPtr connId, byte[] bytes)
|
|
|
{
|
|
|
- // 服务器发数据了
|
|
|
- AddMsg($" > [{connId},OnSend] -> ({bytes.Length} bytes) -> {BitConverter.ToString(bytes, 0, bytes.Length).Replace("-", " ")}", lbSendData);
|
|
|
+ string ip = string.Empty;
|
|
|
+ ushort port = 0;
|
|
|
+ if (server.GetRemoteAddress(connId, ref ip, ref port))
|
|
|
+ {
|
|
|
+ // 服务器发数据了
|
|
|
+ AddMsg($" > [{connId},OnSend] -> {ip.ToString()}:{port} 发送数据 ({bytes.Length} bytes) -> {BitConverter.ToString(bytes, 0, bytes.Length).Replace("-", " ")}", lbSendData);
|
|
|
+ }
|
|
|
return HandleResult.Ok;
|
|
|
}
|
|
|
#endregion
|
|
@@ -263,17 +300,17 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
{
|
|
|
// clientInfo 就是accept里传入的附加数据了
|
|
|
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) \n {BitConverter.ToString(bytes, 0, bytes.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} 接收数据 ({bytes.Length} bytes) \n {BitConverter.ToString(bytes, 0, bytes.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
+
|
|
|
|
|
|
- // 将数据压入队列后 吊起线程
|
|
|
PSProtocol psp = new PSProtocol();
|
|
|
- //ProtocolAnalysisTools.UpSimplePack(clientInfo, bytes);
|
|
|
+ // 接外包操作
|
|
|
ResMsg msg = ProtocolAnalysisTools.UnOuterPack(bytes, psp);
|
|
|
|
|
|
if (!msg.Result)
|
|
|
{
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) 外包解包失败 \n {msg.Message}", lbReceiveData);
|
|
|
-
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {psp.SourceNumber} ({bytes.Length} bytes) 外包解包失败 \n {msg.Message}", lbReceiveData);
|
|
|
+
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -282,9 +319,9 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
PSProtocol protocol2;
|
|
|
byte[] array = new byte[psp.Data.Length];
|
|
|
psp.Data.CopyTo(array, 0);
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) 外包解包成功 \n {BitConverter.ToString(psp.Data, 0, psp.Data.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
-
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {psp.SourceNumber} ({bytes.Length} bytes) 外包解包成功 \n {BitConverter.ToString(psp.Data, 0, psp.Data.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
|
|
|
+ // 判断包类型 心跳或数据包
|
|
|
if (psp.Type == FrameType.GPRS_Link)
|
|
|
{
|
|
|
byte[] buffer2;
|
|
@@ -293,11 +330,11 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
if (!ProtocolAnalysisTools.OuterPack(protocol2, out buffer2).Result)
|
|
|
{
|
|
|
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) 心跳回应打包失败 ", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {psp.SourceNumber} ({bytes.Length} bytes) 心跳回应打包失败 ", lbReceiveData);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnSend] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) 心跳回应成功 \n {BitConverter.ToString(buffer2, 0, buffer2.Length).Replace("-", " ")} ", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnSend] -> {clientInfo.IpAddress}:{clientInfo.Port} {psp.SourceNumber} ({bytes.Length} bytes) 心跳回应成功 \n {BitConverter.ToString(buffer2, 0, buffer2.Length).Replace("-", " ")} ", lbReceiveData);
|
|
|
server.Send(clientInfo.ConnId, buffer2, buffer2.Length);// 发送数据
|
|
|
}
|
|
|
}
|
|
@@ -306,34 +343,37 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
if (psp.Type == FrameType.Battery_GPRS_Report || psp.Type == FrameType.GPRS_Data)
|
|
|
{
|
|
|
clientInfo.pSProtocol = psp;
|
|
|
- _SendConidQueue.Enqueue(clientInfo);// 将连接id 压入队列
|
|
|
+ clientInfo.receiveTime = DateTime.Now; // 收到数据时间,MODBUS设备使用
|
|
|
+ _SendConidQueue.Enqueue(clientInfo); // 将解包数据压入队列
|
|
|
|
|
|
byte[] buffer3;
|
|
|
protocol2 = new PSProtocol(psp.DestNumber, psp.SourceNumber, new byte[0]);
|
|
|
protocol2.Type = psp.Type;
|
|
|
protocol2.PackNum = psp.PackNum;
|
|
|
+
|
|
|
+ // 封装回包信息,并发送
|
|
|
if (!ProtocolAnalysisTools.OuterPack(protocol2, out buffer3).Result)
|
|
|
{
|
|
|
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) 历史记录回应打包失败 ", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {psp.SourceNumber} ({bytes.Length} bytes) 历史记录回应打包失败 ", lbReceiveData);
|
|
|
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnSend] -> {clientInfo.IpAddress}:{clientInfo.Port} ({bytes.Length} bytes) 历史记录回应成功 \n {BitConverter.ToString(buffer3, 0, buffer3.Length).Replace("-", " ")} ", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnSend] -> {clientInfo.IpAddress}:{clientInfo.Port} {psp.SourceNumber} ({bytes.Length} bytes) 历史记录回应成功 \n {BitConverter.ToString(buffer3, 0, buffer3.Length).Replace("-", " ")} ", lbReceiveData);
|
|
|
server.Send(clientInfo.ConnId, buffer3, buffer3.Length);// 发送数据
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- StartOrResumeSendThread();// 调起发送线程
|
|
|
+ StartOrResumeSendThread(); // 启动处理数据进程
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
- AddMsg($" > [{connId},OnReceive] -> ({bytes.Length} bytes)", lbReceiveData);
|
|
|
+ AddMsg($" > [{connId},OnReceive] -> 获取链接附加数据失败 ({bytes.Length} bytes)", lbReceiveData);
|
|
|
}
|
|
|
|
|
|
return HandleResult.Ok;
|
|
@@ -349,20 +389,24 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
HandleResult OnClose(IServer sender, IntPtr connId, SocketOperation enOperation, int errorCode)
|
|
|
{
|
|
|
if (errorCode == 0)
|
|
|
- //AddMsg(string.Format(" > [{0},OnClose]", connId));
|
|
|
AddMsg($" > [{connId},OnClose]", lbReceiveData);
|
|
|
else
|
|
|
- //AddMsg(string.Format(" > [{0},OnError] -> OP:{1},CODE:{2}", connId, enOperation, errorCode));
|
|
|
AddMsg($" > [{connId},OnError] -> OP:{enOperation},CODE:{errorCode}", lbReceiveData);
|
|
|
- // return HPSocketSdk.HandleResult.Ok;
|
|
|
- ClientInfo info = server.GetExtra<ClientInfo>(connId);
|
|
|
- if (info.SendCmdRecordId > 0)
|
|
|
+
|
|
|
+ // 移除设备的链接关联关系
|
|
|
+ foreach (KeyValuePair<string, IntPtr> conn in deveiceConnId)
|
|
|
{
|
|
|
- //DealWithCacheCommand.UpdataCacheCommandType(info.SendCmdRecordId, info.SendCmdParentId, 3); // 这里有点问题 特殊情况下 会有不更新的
|
|
|
+ IntPtr deviceConnId = conn.Value;
|
|
|
+ if (connId == deviceConnId)
|
|
|
+ {
|
|
|
+ deveiceConnId.Remove(conn.Key);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ // 移除附加数据
|
|
|
if (server.RemoveExtra(connId) == false)
|
|
|
{
|
|
|
- //AddMsg(string.Format(" > [{0},OnClose] -> SetConnectionExtra({0}, null) fail", connId));
|
|
|
AddMsg($" > [{connId},OnClose] -> SetConnectionExtra({connId}, null) fail", lbErrorData);
|
|
|
}
|
|
|
|
|
@@ -394,13 +438,16 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
private void StartModBusSendTimer()
|
|
|
{
|
|
|
int intervalTime = Convert.ToInt32(ModBusQueryInterval);
|
|
|
- //实例化Timer类,设置间隔时间(毫秒)
|
|
|
+ // 实例化Timer类,设置间隔时间(毫秒)
|
|
|
System.Timers.Timer timer = new System.Timers.Timer(intervalTime);
|
|
|
- timer.Elapsed += GetDeviceData;//到达时间的时候执行事件;
|
|
|
- timer.AutoReset = true;//设置是执行一次(false)还是一直执行(true);
|
|
|
- timer.Enabled = true;//启动计时器
|
|
|
+ timer.Elapsed += GetDeviceData; // 到达时间的时候执行事件;
|
|
|
+ timer.AutoReset = true; // 设置是执行一次(false)还是一直执行(true);
|
|
|
+ timer.Enabled = true; // 启动计时器
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 启动监控心跳是否超时进程
|
|
|
+ /// </summary>
|
|
|
private void StartOrResumeHeartBeatThread()
|
|
|
{
|
|
|
if (heartBeatThread == null)
|
|
@@ -410,38 +457,66 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
switch (heartBeatThread.ThreadState)
|
|
|
{
|
|
|
case ThreadState.Stopped:
|
|
|
- case ThreadState.Unstarted://未启动
|
|
|
+ case ThreadState.Unstarted: // 未启动
|
|
|
heartBeatThread.Start();
|
|
|
break;
|
|
|
- case ThreadState.Suspended://挂起
|
|
|
+ case ThreadState.Suspended: // 挂起
|
|
|
heartBeatThread.Resume();
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 处理心跳超时的链接
|
|
|
+ /// </summary>
|
|
|
private void DisconnectConnections()
|
|
|
{
|
|
|
while (true)
|
|
|
{
|
|
|
- // 获取所有连接
|
|
|
- IntPtr[] allConnIds = server.GetAllConnectionIDs();
|
|
|
-
|
|
|
- foreach (KeyValuePair<string, IntPtr> conn in deveiceConnId)
|
|
|
+ if (!isHeartBeatRuning)
|
|
|
{
|
|
|
- IntPtr connId = conn.Value;
|
|
|
- if (allConnIds == null || Array.IndexOf(allConnIds, connId) == -1)
|
|
|
- {
|
|
|
- deveiceConnId.Remove(conn.Key);
|
|
|
- continue;
|
|
|
- }
|
|
|
- uint SilenceTime = 0;
|
|
|
- if (server.GetSilencePeriod(connId, ref SilenceTime))
|
|
|
+ isHeartBeatRuning = true;
|
|
|
+ try
|
|
|
{
|
|
|
- if (SilenceTime > Convert.ToInt32(connectionTimeOut))
|
|
|
+
|
|
|
+ // 获取所有连接
|
|
|
+ IntPtr[] allConnIds = server.GetAllConnectionIDs();
|
|
|
+
|
|
|
+ List<string> disconnectId = new List<string>();
|
|
|
+
|
|
|
+ // 处理设备对应的链接,如果超时则断开链接并移除设备-链接对应关系
|
|
|
+ foreach (KeyValuePair<string, IntPtr> conn in deveiceConnId)
|
|
|
{
|
|
|
- server.Disconnect(connId);
|
|
|
- deveiceConnId.Remove(conn.Key);
|
|
|
+ IntPtr connId = conn.Value;
|
|
|
+ if (allConnIds == null || Array.IndexOf(allConnIds, connId) == -1)
|
|
|
+ {
|
|
|
+ disconnectId.Add(conn.Key);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ uint SilenceTime = 0;
|
|
|
+ if (server.GetSilencePeriod(connId, ref SilenceTime))
|
|
|
+ {
|
|
|
+ if (SilenceTime > Convert.ToInt32(connectionTimeOut))
|
|
|
+ {
|
|
|
+ server.Disconnect(connId);
|
|
|
+ disconnectId.Add(conn.Key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (string key in disconnectId)
|
|
|
+ {
|
|
|
+ deveiceConnId.Remove(key);
|
|
|
}
|
|
|
+ // 关闭所有静默链接(主要是只建立链接没有上报过数据的链接)
|
|
|
+ server.DisconnectSilenceConnections(Convert.ToUInt32(connectionTimeOut));
|
|
|
+
|
|
|
+ isHeartBeatRuning = false;
|
|
|
+ }
|
|
|
+ catch (Exception)
|
|
|
+ {
|
|
|
+ isHeartBeatRuning = false;
|
|
|
}
|
|
|
}
|
|
|
Thread.Sleep(Convert.ToInt32(ConnectionTimeOutInterval));
|
|
@@ -449,6 +524,9 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
}
|
|
|
|
|
|
#region 启动或者恢复发送线程
|
|
|
+ /// <summary>
|
|
|
+ /// 启动处理上报抄表数据的队列
|
|
|
+ /// </summary>
|
|
|
private void StartOrResumeSendThread()
|
|
|
{
|
|
|
if (_SendThread == null)
|
|
@@ -514,6 +592,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
{
|
|
|
if (server.Send(conId, buffer, buffer.Length))
|
|
|
{
|
|
|
+ AddMsg($" > [{conId},OnSend] -> {transId} ({buffer.Length} bytes) ModBus读模拟量寄存器 \n {BitConverter.ToString(buffer, 0, buffer.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
sendFlag = true;
|
|
|
modbusArr[0] = modbus;
|
|
|
}
|
|
@@ -527,6 +606,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
{
|
|
|
if (server.Send(conId, buffer, buffer.Length))
|
|
|
{
|
|
|
+ AddMsg($" > [{conId},OnSend] -> {transId} ({buffer.Length} bytes) ModBus读开关量输入状态 \n {BitConverter.ToString(buffer, 0, buffer.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
sendFlag = true;
|
|
|
modbusArr[1] = modbus;
|
|
|
}
|
|
@@ -544,10 +624,13 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
{
|
|
|
isTimeRuning = false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 处理上报抄表数据(上报抄表数据已经存入队列)
|
|
|
+ /// </summary>
|
|
|
private void DealWithSendThread()
|
|
|
{
|
|
|
//定义变量
|
|
@@ -563,15 +646,16 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- Label_1:
|
|
|
+ Label_1:
|
|
|
arr = null;
|
|
|
// 处理数据
|
|
|
ClientInfo clientInfo = (ClientInfo)_SendConidQueue.Dequeue();
|
|
|
PSProtocol psp = clientInfo.pSProtocol;
|
|
|
- clientInfo.NewConnId = deveiceConnId[psp.SourceNumber];
|
|
|
+ //clientInfo.NewConnId = deveiceConnId[psp.SourceNumber];
|
|
|
// 原地址
|
|
|
string sourceNumber = psp.SourceNumber;
|
|
|
|
|
|
+ // 查询该传输设备对应的设备信息及通讯设备信息
|
|
|
DataTable dt = ProtocolAnalysisTools.GetDeviceList(sourceNumber);
|
|
|
|
|
|
string agreement = ""; // 设备协议
|
|
@@ -582,7 +666,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
|
|
|
string agreementTmp = dt.Rows[i]["设备协议"].ToString();
|
|
|
string agreementParamTmp = dt.Rows[i]["设备协议参数"].ToString();
|
|
|
- trandId = dt.Rows[i]["trandId"].ToString();
|
|
|
+ trandId = dt.Rows[i]["trandId"].ToString();
|
|
|
// 如果一个通讯设备下挂载多个设备,判断多个设备的传输协议是否一致,如果不一致则配置错误,无法进行数据转换
|
|
|
if ("".Equals(agreement) && "".Equals(agreementParam))
|
|
|
{
|
|
@@ -599,6 +683,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
if (agreement.Equals("CD_CellMonitor"))
|
|
|
{
|
|
|
CellMonitor cm = new CellMonitor();
|
|
|
+ // 抄表数据进行解包操作,解包后抄表数据存入cm.Record
|
|
|
ResMsg msg = ProtocolAnalysisTools.UnInnerPack(cm, psp.Data);
|
|
|
|
|
|
if (!msg.Result)
|
|
@@ -614,28 +699,35 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({psp.Data.Length} bytes) 内包解包失败 \n {msg.Message}", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {sourceNumber} ({psp.Data.Length} bytes) CD_CellMonitor内包解包失败 \n {msg.Message}", lbReceiveData);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} ({psp.Data.Length} bytes) 内包解包成功 \n {BitConverter.ToString(psp.Data, 0, psp.Data.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {sourceNumber} ({psp.Data.Length} bytes) CD_CellMonitor内包解包成功 \n {BitConverter.ToString(psp.Data, 0, psp.Data.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
|
|
|
+ // 如果是最后一包则发送校时指令
|
|
|
if (cm.IsEnd)
|
|
|
{
|
|
|
byte[] buffer = RandomTime();
|
|
|
- AddMsg($" > [{clientInfo.ConnId},OnSend] -> {clientInfo.IpAddress}:{clientInfo.Port} ({buffer.Length} bytes) 最后一包校时 \n {BitConverter.ToString(buffer, 0, buffer.Length).Replace("-", " ")} ", lbReceiveData);
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnSend] -> {clientInfo.IpAddress}:{clientInfo.Port} {sourceNumber} ({buffer.Length} bytes) CD_CellMonitor最后一包校时 \n {BitConverter.ToString(buffer, 0, buffer.Length).Replace("-", " ")} ", lbReceiveData);
|
|
|
server.Send(clientInfo.ConnId, buffer, buffer.Length);// 发送数据
|
|
|
}
|
|
|
|
|
|
List<HistoryRecord> list = new List<HistoryRecord>();
|
|
|
+
|
|
|
+ // 获取配置的上报抄表数据的数据信息CONF/DataCellConfig.xml中CD_CellMonitor节点,根据传输设备中的设备协议参数关联取那些字段
|
|
|
CellMonitorDeviceType cellMonitorDeviceType = new CellMonitorDeviceType(agreementParam);
|
|
|
+ // 模拟量
|
|
|
Dictionary<string, CommOption> _analogData = cellMonitorDeviceType.GetAnalogCommOptions();
|
|
|
+ // 开关量
|
|
|
Dictionary<string, CommOption> _switchData = cellMonitorDeviceType.GetSwitchCommOptions();
|
|
|
|
|
|
for (int i = 0; i < cm.Record.Count; i++)
|
|
|
{
|
|
|
List<CommData> list2 = new List<CommData>();
|
|
|
+
|
|
|
+ #region 将数据与配置的字段进行关联
|
|
|
foreach (MonitorValue value2 in cm.Record[i].Analog)
|
|
|
{
|
|
|
if (_analogData.ContainsKey(value2.Name))
|
|
@@ -650,7 +742,9 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
_switchData[value3.Name].ExplainData(value3.Value);
|
|
|
}
|
|
|
}
|
|
|
+ #endregion
|
|
|
|
|
|
+ // 将数据进行封装,一条数据可能对于多个设备的数据,通过[设备信息表]中设备的[用户站参数]与CONF\US_Common.xml进行匹配拆分
|
|
|
List<HistoryRecord> item = this.UpdateHistoryData(cm.Record[i].PickTime, cm, dt, _analogData, _switchData);
|
|
|
if (item != null && item.Count > 0)
|
|
|
{
|
|
@@ -659,12 +753,14 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
|
|
|
}
|
|
|
|
|
|
+ // 保存抄表数据
|
|
|
ProtocolAnalysisTools.SaveRecord(list);
|
|
|
}
|
|
|
}
|
|
|
// MODBUS类设备
|
|
|
else if (agreement.Equals("CD_PSController"))
|
|
|
{
|
|
|
+ #region 根据上报数据的功能码区分获取对应的下发指令的MODBUS对象
|
|
|
Modbus.FunctionCode code = (Modbus.FunctionCode)psp.Data[1];
|
|
|
Modbus modbus = new Modbus();
|
|
|
if (code == Modbus.FunctionCode.F04)
|
|
@@ -675,21 +771,43 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
{
|
|
|
modbus = sendComm[trandId][1];
|
|
|
}
|
|
|
+ #endregion
|
|
|
|
|
|
- Modbus.UnPack(psp.Data, modbus);
|
|
|
- ModBusDeviceType modBusDeviceType = new ModBusDeviceType(agreementParam);
|
|
|
- Dictionary<string, CommOption> _analogData = modBusDeviceType.GetAnalogCommOptions();
|
|
|
- Dictionary<string, CommOption> _switchData = modBusDeviceType.GetSwitchCommOptions();
|
|
|
- if (code == Modbus.FunctionCode.F04)
|
|
|
+ // 内包进行解包,解包后的数据存入modbus.UpDataArea
|
|
|
+ ResMsg msg = Modbus.UnPack(psp.Data, modbus);
|
|
|
+
|
|
|
+ if (!msg.Result)
|
|
|
{
|
|
|
- ProtocolAnalysisTools.OrganizeAnalogData(modbus.UpDataArea, _analogData, Convert.ToInt32(modBusDeviceType.AnalogStartAddress));
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {sourceNumber} ({modbus.UpDataArea.Length} bytes) CD_PSController内包解包失败,数据类型{code} \n {msg.Message}", lbReceiveData);
|
|
|
}
|
|
|
- else if (code == Modbus.FunctionCode.F02)
|
|
|
+ else
|
|
|
{
|
|
|
- ProtocolAnalysisTools.OrganizeSwitchData(modbus.UpDataArea, _switchData, Convert.ToInt32(modBusDeviceType.SwitchStartAddress));
|
|
|
+ AddMsg($" > [{clientInfo.ConnId},OnReceive] -> {clientInfo.IpAddress}:{clientInfo.Port} {sourceNumber} ({modbus.UpDataArea.Length} bytes) CD_PSController内包解包成功,数据类型{code} \n {BitConverter.ToString(modbus.UpDataArea, 0, modbus.UpDataArea.Length).Replace("-", " ")}", lbReceiveData);
|
|
|
+
|
|
|
+ // 获取配置的上报抄表数据的数据信息CONF/DataCellConfig.xml中CD_PSController节点,根据传输设备中的设备协议参数关联取那些字段
|
|
|
+ ModBusDeviceType modBusDeviceType = new ModBusDeviceType(agreementParam);
|
|
|
+ // 模拟量
|
|
|
+ Dictionary<string, CommOption> _analogData = modBusDeviceType.GetAnalogCommOptions();
|
|
|
+ // 开关量
|
|
|
+ Dictionary<string, CommOption> _switchData = modBusDeviceType.GetSwitchCommOptions();
|
|
|
+
|
|
|
+ #region 将数据与配置的字段进行关联
|
|
|
+ if (code == Modbus.FunctionCode.F04)
|
|
|
+ {
|
|
|
+ ProtocolAnalysisTools.OrganizeAnalogData(modbus.UpDataArea, _analogData, Convert.ToInt32(modBusDeviceType.AnalogStartAddress));
|
|
|
+ }
|
|
|
+ else if (code == Modbus.FunctionCode.F02)
|
|
|
+ {
|
|
|
+ ProtocolAnalysisTools.OrganizeSwitchData(modbus.UpDataArea, _switchData, Convert.ToInt32(modBusDeviceType.SwitchStartAddress));
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ // 将数据进行封装,一条数据可能对于多个设备的数据,通过[设备信息表]中设备的[用户站参数]与CONF\US_Common.xml进行匹配拆分
|
|
|
+ List<HistoryRecord> item = this.UpdateHistoryData(clientInfo.receiveTime, null, dt, _analogData, _switchData);
|
|
|
+
|
|
|
+ // 保存抄表数据
|
|
|
+ ProtocolAnalysisTools.SaveRecord(item);
|
|
|
}
|
|
|
- List<HistoryRecord> item = this.UpdateHistoryData(DateTime.Now, null, dt, _analogData, _switchData);
|
|
|
- ProtocolAnalysisTools.SaveRecord(item);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -775,8 +893,51 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
}
|
|
|
return buffer;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
+ private void timer1_Tick(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ this.toolStripStatusLabel6.Text = "系统时间:" + DateTime.Now.ToString();
|
|
|
+ TimeSpan span = (TimeSpan)(DateTime.Now - this.dtStartTime);
|
|
|
+ this.toolStripStatusLabel4.Text = this.RunTime((int)span.TotalSeconds);
|
|
|
+ string coonNum = "0";
|
|
|
+ if (server.IsStarted && server.GetAllConnectionIDs() != null)
|
|
|
+ {
|
|
|
+ coonNum = server.GetAllConnectionIDs().Length.ToString();
|
|
|
+ }
|
|
|
+ this.toolStripStatusLabel3.Text = "客户端连接数:" + coonNum;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string RunTime(int s)
|
|
|
+ {
|
|
|
+ int num = 0;
|
|
|
+ int num2 = 0;
|
|
|
+ int num3 = 0;
|
|
|
+ int num4 = 0;
|
|
|
+ if (s < 60)
|
|
|
+ {
|
|
|
+ num4 = s;
|
|
|
+ }
|
|
|
+ else if ((60 <= s) && (s <= 0xe10))
|
|
|
+ {
|
|
|
+ num3 = s / 60;
|
|
|
+ num4 = s % 60;
|
|
|
+ }
|
|
|
+ else if ((0xe10 <= s) && (s <= 0x15180))
|
|
|
+ {
|
|
|
+ num2 = s / 0xe10;
|
|
|
+ num3 = (s % 0xe10) / 60;
|
|
|
+ num4 = (s % 0xe10) % 60;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ num = s / 0x15180;
|
|
|
+ num2 = (s % 0x15180) / 0xe10;
|
|
|
+ num3 = ((s % 0x15180) % 0xe10) / 60;
|
|
|
+ num4 = ((s % 0x15180) % 0xe10) % 60;
|
|
|
+ }
|
|
|
+ return ("系统持续运行:" + num.ToString() + "天" + num2.ToString() + "小时" + num3.ToString() + "分" + num4.ToString() + "秒");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
public class ClientInfo
|
|
@@ -793,6 +954,7 @@ namespace NB_IOT_TCP_HP_SOCKET
|
|
|
public bool flag { get; set; } // 指令是否正确
|
|
|
public string msg { get; set; } // 返回信息
|
|
|
public int meterId { get; set; }
|
|
|
+ public DateTime receiveTime { get; set; }
|
|
|
public int SendCmdRecordId { get; set; }// 发送的缓存命令的id
|
|
|
public int SendCmdParentId { get; set; }// 发送缓存命令的母id
|
|
|
}
|