You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
19 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using UPPLibs;
using RemoteObjects;
namespace CommService
{
/*
*类名称TCPHandler
*创建人:韩荣伟
*创建时间2010-10-30
*功能描述:集中器通信处理类
*/
class TCPHandler
{
public NetworkStream networkStream;
private byte[] bytes;
private bool online;
public Thread tWorker;
public bool stoped;
public string tName;
private Queue qCommand;
private Queue qSyncCommand;
private AutoResetEvent newReqEvent = new AutoResetEvent(false);
private AutoResetEvent resMatchEvent = new AutoResetEvent(false);
private Thread tReqWatcher;
public struRequestInQueue sCurrentReq;
private Mutex mut = new Mutex();
public string strIPPort;
public string sLoginTime;
private byte[] rcvBuff = { };
private int timeoutCount;
private byte seqFrame;
private TcpClient tcpClient = null;
private MessageHandler messageHandler = null;
public DateTime dtLogin;
private bool bReplace;
public bool bKickOff=false;
public TCPHandler(TcpClient tcpClient)
{
this.tcpClient = tcpClient;
networkStream = tcpClient.GetStream();
bytes = new byte[1024];
online = true;
tName = "未知终端";
qCommand = new Queue();
qSyncCommand = new Queue(qCommand);
seqFrame = 0x1;
stoped = false;
tReqWatcher = null;
bReplace = false;
messageHandler = new MessageHandler(this);
//messageHandler.Init();
}
/*
*方法名称WorkerThreadProc
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述void
*返回描述void
*功能描述:集中器通信线程函数
*/
public void WorkerThreadProc()
{
int i = 0;
// Loop to receive all the data sent by the client.
strIPPort = IPAddress.Parse(((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString())
+ ":"
+ ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port.ToString();
Common.logFile.write("[未知终端] 建立连接,来自:" + strIPPort, LogFile.LOGLVL_NORMAL);
try
{
//读取字节流
i = networkStream.Read(bytes, 0, bytes.Length);
}
catch (Exception e5)
{
Close();
Common.platForm.tcpServer.RemoveTCPHandler(this);
Common.logFile.write("采集终端 [" + this.tName + "] Exception: " + e5.ToString(), LogFile.LOGLVL_ERROR);
Common.logFile.write("采集终端 [" + this.tName + "]<<<<<<WorkerThreadProc exited>>>>>>>>", LogFile.LOGLVL_NORMAL);
return;
}
while (i != 0)
{
byte[] rcvbytes = new byte[i];
for (int j = 0; j < i; j++)
{
rcvbytes[j] = bytes[j];
}
//Common.logFile.writeHexString("[" + (this.tName == "未知终端" ? this.tName + "@" + strIPPort : this.tName) + "] " + "收到数据: ", rcvbytes, LogFile.LOGLVL_DEBUG);
//put into buffer
byte[] tmp = new byte[rcvBuff.Length + i];
for (int j = 0; j < rcvBuff.Length; j++)
{
tmp[j] = rcvBuff[j];
}
for (int j = 0; j < i; j++)
{
tmp[j + rcvBuff.Length] = bytes[j];
}
rcvBuff = tmp;
//数据包识别
byte[] pack = UPPHandler.FindPackFromBuff(ref rcvBuff);
if (this.tName == "未知终端" && pack.Length == 0)
{
break;
}
while (pack.Length > 0)
{
Common.logFile.writeHexString("[" + this.tName + "] " + "收到帧: ", pack, LogFile.LOGLVL_DEBUG);
UPPLibs.struFrame sFrame = new UPPLibs.struFrame();
//数据包解析
if (UPPHandler.frameParsing(pack, ref sFrame) == true)
{
string info2Display = "";
UPPHandler.frameCommenting(ref sFrame, ref info2Display);
Common.logFile.write("[" + this.tName + "] " + "收到 " + info2Display, LogFile.LOGLVL_DEBUG);
messageHandler.messageHandling(ref sFrame);
}
//数据包识别
pack = UPPHandler.FindPackFromBuff(ref rcvBuff);
}
try
{
i = networkStream.Read(bytes, 0, bytes.Length);
}
catch (Exception e5)
{
Common.logFile.write("采集终端 [" + this.tName + "] Exception: " + e5.ToString(), LogFile.LOGLVL_ERROR);
break;
}
}
// Shutdown and end connection
if (online == true && (this.tName.CompareTo("未知终端")!=0))
{
SaveOfflineInfo(DateTime.Now);
}
else if (online == false && (this.tName.CompareTo("未知终端") != 0))
{
if (bReplace == true)
{
SaveReplaceInfo(DateTime.Now);
}
else if (bKickOff == true)
{
SaveKickoffInfo(DateTime.Now);
}
else
{
SaveCloseInfo(DateTime.Now);
}
}
Close();
//Common.TCPWorkerList.Remove(this);
Common.platForm.tcpServer.RemoveTCPHandler(this);
Common.logFile.write("采集终端 [" + this.tName + "]<<<<<<WorkerThreadProc exited>>>>>>>>", LogFile.LOGLVL_NORMAL);
}
/*
*方法名称messageMatching
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述ref struFrame sFrame 对方应答帧
*返回描述bool true 匹配false 不匹配
*功能描述:与集中器通信,检查请求与应答是否匹配
*/
public bool messageMatching(ref struFrame sFrame)
{
bool matchOK = false;
//lock
mut.WaitOne();
//check current request with sFrame
if (sFrame.flagFSEQ == sCurrentReq.frameInfo.flagFSEQ
&& sFrame.flagCtrlF == sCurrentReq.frameInfo.flagCtrlF)
{
struFrame currentFrame = new struFrame();
UPPHandler.frameCopy(ref sCurrentReq.frameInfo, ref currentFrame);
sFrame.userData2 = (object)currentFrame;
//sCurrentReq.frameResp = new struFrame();
//取回数据
UPPHandler.frameCopy(ref sFrame, ref sCurrentReq.frameResp);
sCurrentReq.bMatchOK = true;
matchOK = sCurrentReq.bMatchOK;
try
{
resMatchEvent.Set();
sCurrentReq.handleReqEvent.Set();
//Common.logFile.write("sCurrentReq matching" + sCurrentReq.GetHashCode().ToString(), LogFile.LOGLVL_NORMAL);
//Common.logFile.write("sCurrentReq.frameResp" + sCurrentReq.frameResp.GetHashCode().ToString(), LogFile.LOGLVL_NORMAL);
}
catch (Exception e1)
{
Common.logFile.write("FSEQ:" + sFrame.flagFSEQ + "\r\nAutoResetEvent, Exception: " + e1.ToString(), LogFile.LOGLVL_ERROR);
}
}
else
{
Common.logFile.write("消息匹配 错误!!!!!", LogFile.LOGLVL_NORMAL);
}
//unlock
mut.ReleaseMutex();
return matchOK;
}
/*
*方法名称Start
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述void
*返回描述void
*功能描述:启动通信处理线程
*/
public void Start()
{
tWorker = new Thread(new ThreadStart(WorkerThreadProc));
tWorker.IsBackground = true;
tWorker.Start();
}
/*
*方法名称GetSeqFrame
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述void
*返回描述byte 序号
*功能描述:生成消息序号,循环赋值
*/
public byte GetSeqFrame()
{
byte res = seqFrame;
seqFrame++;
if (seqFrame >= 0x80)
{
seqFrame = 0x1;
}
return res;
}
/*
*方法名称PutNewReq
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述ref struRequestInQueue reqInQ 请求消息结构
*返回描述void
*功能描述:将请求消息结构放入队列
*/
public void PutNewReq(ref struRequestInQueue reqInQ) //
{
if (tReqWatcher == null || tReqWatcher.IsAlive == false)
{
tReqWatcher = new Thread(new ThreadStart(WatcherThreadProc));
tReqWatcher.Start();
}
Object obj = reqInQ;
qSyncCommand.Enqueue(obj);
//Console.WriteLine("put command:{0} into queue", n);
newReqEvent.Set();
}
/*
*方法名称SetTimeOut
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述int interval 集中器踢出时限值
*返回描述void
*功能描述:设置集中器踢出时限值
*/
public void SetTimeOut(int interval)
{
timeoutCount = interval;
}
/*
*方法名称CheckTimeOut
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述void
*返回描述bool true 时限之内false 超时
*功能描述:检查集中器是否心跳超时
*/
public bool CheckTimeOut()
{
bool res = true;
timeoutCount--;
if (timeoutCount < 0)
{
res = false;
}
return res;
}
/*
*方法名称remakeTimeCorrectingFrame
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述ref byte[] frameBytes 对集中器校时的帧字节数组
*返回描述void
*功能描述:对集中器校时的帧字节数组,更新最新时间
*/
private void remakeTimeCorrectingFrame(ref byte[] frameBytes)
{
if (frameBytes.Length == 20)
{
DateTime dtNow = DateTime.Now;
frameBytes[12] = (byte)Convert.ToInt32(dtNow.Second.ToString("D2"), 16);//秒
frameBytes[13] = (byte)Convert.ToInt32(dtNow.Minute.ToString("D2"), 16);//分
frameBytes[14] = (byte)Convert.ToInt32(dtNow.Hour.ToString("D2"), 16);//时
frameBytes[15] = (byte)Convert.ToInt32(dtNow.Day.ToString("D2"), 16);//日
frameBytes[16] = (byte)Convert.ToInt32(dtNow.Month.ToString("D2"), 16);//月
frameBytes[17] = (byte)Convert.ToInt32((dtNow.Year % 100).ToString("D2"), 16);//年
//重新计算 CS
frameBytes[18] = (byte)UPPLibs.UPPHandler.countCS(frameBytes, 0, frameBytes.Length - 2);
}
}
/*
*方法名称WatcherThreadProc
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述void
*返回描述void
*功能描述:发送消息队列的线程函数,从队列中取消息发送
*/
public void WatcherThreadProc()
{
bool loop = true;
while (loop)
{
//新消息通知
if (newReqEvent.WaitOne(8000, false) == true)
{
while (qSyncCommand.Count > 0)
{
//设置当前请求
byte[] frameBytes = null;
bool isTimeCorrectting = false;
mut.WaitOne();
sCurrentReq = (struRequestInQueue)qSyncCommand.Dequeue();
//Common.logFile.write("sCurrentReq" + sCurrentReq.GetHashCode().ToString(), LogFile.LOGLVL_NORMAL);
frameBytes = sCurrentReq.frameBytes;
isTimeCorrectting = sCurrentReq.frameInfo.isTimeCorrectting;
mut.ReleaseMutex();
//Console.WriteLine("current command:{0} waiting for answer", n);
resMatchEvent.Reset();
int cycleCount = 0;
bool matchOK = false;
//最多重发三次
while (cycleCount < 3)
{
if (isTimeCorrectting == true)
{
remakeTimeCorrectingFrame(ref frameBytes);
}
try
{
networkStream.Write(frameBytes, 0, frameBytes.Length);
Common.logFile.writeHexString("发送请求帧[" + this.tName + "]", frameBytes, LogFile.LOGLVL_NORMAL);// write("获取终端[" + tw.tName + "]主动上传间隔(分钟):" + sInterval, LogFile.LOGLVL_NORMAL);
}
catch (Exception e)
{
//Common.logFile.write("数据发送出现例外:"+e.ToString(), LogFile.LOGLVL_ERROR);
break;
}
//等待应答消息
if (resMatchEvent.WaitOne(3000, false) == true)
{
break;
}
else
{
//Console.WriteLine("get a commmand event timeout");
cycleCount++;
}
// 通知 service ,返回结果
mut.WaitOne();
matchOK = sCurrentReq.bMatchOK;
mut.ReleaseMutex();
if (matchOK == true)
{
break;
}
}
}
}
else
{
qSyncCommand.Clear();
loop = false;
}
}
}
/*
*方法名称Close
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述void
*返回描述void
*功能描述:关闭对集中器通信的处理
*/
public void Close()
{
//lock
//TCPServer.mut.WaitOne();
try
{
if (online == true)
{
//if(Thread.CurrentThread == this.tWorker && this.tName != "未知终端")
//{
// SaveOfflineInfo(DateTime.Now);
//}
online = false;
networkStream.Close();
tcpClient.Close();
if (tReqWatcher != null && tReqWatcher.IsAlive == true)
{
tReqWatcher.Abort();
}
qSyncCommand.Clear();
}
}
catch (Exception e1)
{
}
}
public void ExecuteTiming()
{
Thread t = new Thread(new ThreadStart(TimingThreadProc));
t.IsBackground = true;
t.Start();
}
/*
*方法名称SaveLoginInfo
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述DateTime dtLoginTime 集中器登录时间
*返回描述void
*功能描述:保存集中器登录时间入库
*/
public void TimingThreadProc()
{
ReqHandler reqHandler = new ReqHandler();
reqHandler.SetTime(this.tName);
}
/*
*方法名称SaveKickoffInfo
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述DateTime dtLogoutTime 集中器心跳超时被踢出的时间
*返回描述void
*功能描述:保存集中器被踢出的时间入库
*/
public void SaveKickoffInfo(DateTime dtLogoutTime)
{
messageHandler.SaveLogoutInfo(this.tName, this.dtLogin, dtLogoutTime, 1);
Common.logFile.write("[" + this.tName + "] 踢出 Kickoff", LogFile.LOGLVL_NORMAL);
}
/*
*方法名称SaveOfflineInfo
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述DateTime dtLogoutTime 集中器掉线的时间
*返回描述void
*功能描述:保存集中器掉线的时间入库
*/
public void SaveOfflineInfo(DateTime dtLogoutTime)
{
messageHandler.SaveLogoutInfo(this.tName, this.dtLogin, dtLogoutTime, 0);
Common.logFile.write("[" + this.tName + "] 掉线 Offline", LogFile.LOGLVL_NORMAL);
}
/*
*方法名称SaveCloseInfo
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述DateTime dtLogoutTime 集中器掉线的时间
*返回描述void
*功能描述:保存服务关机集中器掉线的时间入库
*/
public void SaveCloseInfo(DateTime dtLogoutTime)
{
messageHandler.SaveLogoutInfo(this.tName, this.dtLogin, dtLogoutTime, 2);
Common.logFile.write("[" + this.tName + "] 被服务关闭 Offline", LogFile.LOGLVL_NORMAL);
}
/*
*方法名称SaveCloseInfo
*创建人:韩荣伟
*创建时间2010-10-30
*参数描述DateTime dtLogoutTime 集中器掉线的时间
*返回描述void
*功能描述:保存服务关机集中器掉线的时间入库
*/
public void SaveReplaceInfo(DateTime dtLogoutTime)
{
messageHandler.SaveLogoutInfo(this.tName, this.dtLogin, dtLogoutTime, 3);
Common.logFile.write("[" + this.tName + "] 被同名替代 Offline", LogFile.LOGLVL_NORMAL);
}
public void SetReplaceFlag(bool bOn)
{
bReplace = bOn;
}
}
}