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 + "]<<<<<>>>>>>>", 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 + "]<<<<<>>>>>>>", 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; } } }