using centralController.model; using db; using nettyCommunication; using parkMonitor.LOG; using PLCS7; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Terminal; namespace centralController.WebServer { class MyWebServer : IWebServer { private Queue waitToReserveQueue = null; private Queue reservedQueue = null; private object waitToReserveLock = new object(); private object reservedLock = new object(); private object parkLock = new object(); private object fetchLock = new object(); private object connectLock = new object(); private Communication comm = null; private Thread receiveMsg = null; private bool isClosing { get; set; } /// /// 是否正在调用函数进行连接 /// private bool connecting { get; set; } /// /// 连接状态 /// private bool connected { get; set; } public void BookFetchRecord() { throw new NotImplementedException(); } public void BookParkRecord() { throw new NotImplementedException(); } /// /// 更新预约车车辆状态 /// /// /// /// /// /// private bool UpdateVehicleState(bool localDB, int state, int orderRecordsID, string license) { string vehicleUpdateSql = ""; string vehicleInsertSql = ""; if (orderRecordsID > 0) { if (state >= 0) { vehicleUpdateSql = "update vehicle set vehiclepParkState = " + state + " ,orderRecordsID = " + orderRecordsID + " where numberPlate = '" + license + "';"; vehicleInsertSql = "insert into vehicle (numberPlate,vehiclepParkState,orderRecordsID) values " + "('" + license + "'," + state + "," + orderRecordsID + ");"; } else { vehicleUpdateSql = "update vehicle set orderRecordsID = " + orderRecordsID + " where numberPlate = '" + license + "';"; vehicleInsertSql = "insert into vehicle (numberPlate,orderRecordsID) values " + "('" + license + "'," + orderRecordsID + ");"; } } else { if (state >= 0) { vehicleUpdateSql = "update vehicle set vehiclepParkState = " + state + " where numberPlate = '" + license + "';"; vehicleInsertSql = "insert into vehicle (numberPlate,vehiclepParkState) values " + "('" + license + "'," + state + ");"; } else { return false; } } List vehicleUpdateList = new List(); List vehicleInsertList = new List(); vehicleUpdateList.Add(vehicleUpdateSql); vehicleInsertList.Add(vehicleInsertSql); DBOperation dbHandle = null; if (localDB) dbHandle = Monitor.Monitor.localDBOper; else dbHandle = Monitor.Monitor.remoteDBOper; if (!dbHandle.UpdateTransaction(vehicleUpdateList)) { int id = 0; if (!dbHandle.Insert(vehicleInsertList, out id)) return false; else return true; } else return true; } /// /// 插入预约记录 /// /// /// /// /// /// /// /// private bool InsertOrderRecord(bool localDB, string userID, bool parking, string license, string orderTime, int orderLength, out int id) { bool result = false; string orderRecordInsertSql; if (parking) { orderRecordInsertSql = "insert into orderrecords (userID,numberPlate,garageID, bookParkTime, bookHour, bookPrice,bookState) " + "VALUES (" + userID + ", '" + license + "', '" + Monitor.Monitor.garageID + "', '" + orderTime + "', " + orderLength + ",NULL, '0');"; } else { orderRecordInsertSql = "insert into orderrecords (userID,numberPlate,garageID, bookFetchTime, bookHour, bookPrice,bookState) " + "VALUES (" + userID + ", '" + license + "', '" + Monitor.Monitor.garageID + "', '" + orderTime + "', " + orderLength + ",NULL, '2');"; } List orderList = new List(); orderList.Add(orderRecordInsertSql); if (localDB) result = Monitor.Monitor.localDBOper.Insert(orderList, out id); else result = Monitor.Monitor.remoteDBOper.Insert(orderList, out id); return result; } /// /// 找到当前预约记录ID,暂未使用 /// /// /// /// 最近第几条记录,1表示最新一条 /// private int FindCurrentOrderRecordID(bool localDB, string license, int latestIndex = 1) { int currentID = 0; int count = 10; while (count-- > 0 && currentID == 0) { List orderRecords = Monitor.Monitor.GetOrderRecords(localDB, license, DateTime.Now.ToString("yyyy-MM-dd"), DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")); if (orderRecords.Count != 0) { try { currentID = (int)(UInt32)orderRecords[latestIndex - 1][0]; } catch { } } } return currentID; } /// /// 预约数据库操作 /// /// /// /// /// /// /// /// private bool ReserveDBOperation(bool localDB, string userID, bool parking, string license, string orderTime, int orderLength) { UpdateVehicleState(localDB, parking ? 4 : 5, 0, license); //预约记录插入db int currentID = 0; InsertOrderRecord(localDB, userID, parking, license, orderTime, orderLength, out currentID); ////查询预约记录id号 //int currentID = FindCurrentOrderRecordID(localDB, license); if (currentID == 0) { /*反馈web,预约失败*/ return false; } //更新车辆状态 UpdateVehicleState(localDB, parking ? 4 : 5, currentID, license); return true; } /// /// 检查预约指令是否可行 /// /// /// private bool ReservationValidate(MessageUTF8 msg) { int allBookableSpace, count; lock (waitToReserveLock) { //可预约车位总数 allBookableSpace = Monitor.Monitor.ins.GetFreeSpaceCount(4); count = 0; DateTime start, end; try { start = DateTime.Parse(msg.bookTime); end = start.AddHours(msg.bookLength); //Console.WriteLine("--------"+msg.bookTime+","+msg.bookLength); } catch { Console.WriteLine("时间解析异常1"); return false; } Queue.Enumerator enumer = waitToReserveQueue.GetEnumerator(); while (enumer.MoveNext()) { DateTime tempStart, tempEnd; try { tempStart = DateTime.Parse(enumer.Current.bookTime); tempEnd = tempStart.AddHours(enumer.Current.bookLength); //Console.WriteLine("#########" + enumer.Current.bookTime + "," + enumer.Current.bookLength); } catch { Console.WriteLine("时间解析异常2"); return false; } //Console.WriteLine("**********" + start.ToString() + "," + end.ToString() + "," + tempStart.ToString() + "," + tempEnd.ToString()); //Console.WriteLine("**********" + ((tempStart - end).TotalMinutes > 0)+","+ ((start - tempEnd).TotalMinutes > 0)); if (!((tempStart - end).TotalMinutes > 0 || (start - tempEnd).TotalMinutes > 0)) { count += 1; } } Queue.Enumerator enumer2 = reservedQueue.GetEnumerator(); while (enumer2.MoveNext()) { DateTime tempStart, tempEnd; try { tempStart = DateTime.Parse(enumer2.Current.bookTime); tempEnd = tempStart.AddHours(enumer2.Current.bookLength); //Console.WriteLine("#########" + enumer.Current.bookTime + "," + enumer.Current.bookLength); } catch { Console.WriteLine("时间解析异常2"); return false; } //Console.WriteLine("**********" + start.ToString() + "," + end.ToString() + "," + tempStart.ToString() + "," + tempEnd.ToString()); //Console.WriteLine("**********" + ((tempStart - end).TotalMinutes > 0)+","+ ((start - tempEnd).TotalMinutes > 0)); if (!((tempStart - end).TotalMinutes > 0 || (start - tempEnd).TotalMinutes > 0)) { count += 1; } } } Console.WriteLine("----------" + msg.context + ":" + allBookableSpace + "," + count); if (allBookableSpace > count) return true; else return false; } /// /// 根据消息类型分别处理 /// /// private void MsgHandling(MessageUTF8 msg) { try { MessageUTF8 returnMsg = new MessageUTF8(); switch (msg.cmd) { //预约停 case "RESERVE": if (msg.userID != "" && msg.bookTime != "" && msg.bookLength != 0) { if (!ReservationValidate(msg)) { //回复预约失败给web returnMsg.cmd = "RESERVEFAILED"; returnMsg.userID = msg.userID; returnMsg.context = msg.context; returnMsg.garageID = ClientSettings.GarageID; comm.SendMessage(returnMsg); Monitor.Monitor.SetNotification("车辆" + msg.context + "预约停车,已无可预约车位", parkMonitor.model.TextColor.Warning); } else { bool DBOperResult = true; lock (waitToReserveLock) { waitToReserveQueue.Enqueue(msg); } //预约记录与车辆状态写入数据库 DBOperResult = DBOperResult && ReserveDBOperation(true, msg.userID, true, msg.context, msg.bookTime, msg.bookLength); DBOperResult = DBOperResult && ReserveDBOperation(false, msg.userID, true, msg.context, msg.bookTime, msg.bookLength); //回复成功给web if (!DBOperResult) Log.WriteLog(LogType.process, LogFile.WARNING, msg.context + "从" + msg.bookTime + "开始预约" + msg.bookLength + "小时,预约指令数据库操作未获得记录ID"); returnMsg.cmd = "RESERVEOK"; returnMsg.userID = msg.userID; returnMsg.context = msg.context; returnMsg.garageID = ClientSettings.GarageID; comm.SendMessage(returnMsg); Monitor.Monitor.SetNotification("车辆" + msg.context + "预约停车,操作成功", parkMonitor.model.TextColor.Log); } } break; case "CANCELRESERVE": //IEqualityComparer comparer ; //if(waitToReserveQueue.Contains(msg, ) break; //预约取 case "PREFETCH": break; //停车 case "PARK": lock (parkLock) { returnMsg = new MessageUTF8(); int id = 0; int countdown = 2; int resultCode = 8; //根据号牌寻找对应号牌机编号,找不到则返回失败信息 if (msg.context != "" && msg.userID != "") { while (id == 0 && countdown-- > 0) { try { id = Terminal.Terminal.GetIdAccordingToLicense(msg.context.Split('.')[2]); //id = 1; //id = Monitor.Monitor.numMachineLinker.GetLicenseID(msg.context.Split('.')[2]); } catch { Console.WriteLine("号牌截取异常"); } } } if (id > 0) //判断号牌机编号对应PLC数据块是否空闲,空闲则判断按钮状态并发送停车指令与号牌到PLC,否则返回失败信息 { try { resultCode = TerminalSimul.ParkTermOper(id, msg.context); } catch { resultCode = 8; } } else { resultCode = 1; } Thread.Sleep(1000); switch (resultCode) { case 0: returnMsg.cmd = "PARKOK"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "正在进行停车", parkMonitor.model.TextColor.Info); break; case 1: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("未识别到车辆" + msg.context.Split('.')[2] + ",终端" + id + "停放位置,请确认车辆已入场", parkMonitor.model.TextColor.Warning); break; case 2: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "生成凭证号失败", parkMonitor.model.TextColor.Warning); break; case 3: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "凭证转换异常", parkMonitor.model.TextColor.Warning); break; case 4: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "停车码解析异常", parkMonitor.model.TextColor.Warning); break; case 5: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "地感异常,当前位置无地感", parkMonitor.model.TextColor.Warning); break; case 6: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "状态异常,非停车终端", parkMonitor.model.TextColor.Warning); break; case 7: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "状态异常,已有停车指令在处理中", parkMonitor.model.TextColor.Warning); break; case 8: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "其他异常", parkMonitor.model.TextColor.Warning); Log.WriteLog(LogType.process, LogFile.ERROR, "凭证号" + msg.context + "出现未知异常,无法停车"); break; case 9: returnMsg.cmd = "PARKFAILED"; Monitor.Monitor.SetNotification("车辆" + msg.context.Split('.')[2] + ",终端" + id + "无空闲车位", parkMonitor.model.TextColor.Warning);break; } returnMsg.userID = msg.userID; returnMsg.garageID = Monitor.Monitor.garageID; returnMsg.context = msg.context; comm.SendMessage(returnMsg); } break; //取车 case "FETCH": lock (fetchLock) { returnMsg = new MessageUTF8(); int resultCode = TerminalSimul.FetchTermOper(msg.context); Thread.Sleep(1500); switch (resultCode) { case 0: returnMsg.cmd = "FETCHOK"; Monitor.Monitor.SetNotification("凭证号" + msg.context + "正在取车", parkMonitor.model.TextColor.Info); break; case 1: returnMsg.cmd = "FETCHFAILED"; Monitor.Monitor.SetNotification("凭证号" + msg.context + "地感异常,有地感时无法取车", parkMonitor.model.TextColor.Warning); break; case 2: returnMsg.cmd = "FETCHFAILED"; Monitor.Monitor.SetNotification("凭证号" + msg.context + "终端状态异常,当前非取车终端", parkMonitor.model.TextColor.Warning); break; case 3: returnMsg.cmd = "FETCHFAILED"; Monitor.Monitor.SetNotification("凭证号" + msg.context + "指令占用异常,已有取车指令在处理中", parkMonitor.model.TextColor.Warning); break; case 4: returnMsg.cmd = "FETCHFAILED"; Monitor.Monitor.SetNotification("凭证号" + msg.context + "凭证解析异常,无法解析该凭证号", parkMonitor.model.TextColor.Warning); break; case 5: returnMsg.cmd = "FETCHFAILED"; Monitor.Monitor.SetNotification("凭证号" + msg.context + "其他异常", parkMonitor.model.TextColor.Warning); Log.WriteLog(LogType.process, LogFile.ERROR, "凭证号" + msg.context + "出现未知异常,无法取车"); break; } returnMsg.userID = msg.userID; returnMsg.garageID = Monitor.Monitor.garageID; returnMsg.context = msg.context; comm.SendMessage(returnMsg); } break; //连接断开消息 case "DISCONNECT": Monitor.Monitor.SetNotification("收到连接断开提示消息", parkMonitor.model.TextColor.Warning); break; //更新广告 case "ADVERT": string adAlert = ""; bool result = Monitor.Monitor.advertMgr.UpdateAdvert(out adAlert); if (!result) { Monitor.Monitor.SetNotification("广告更新失败,请尝试手动更新", parkMonitor.model.TextColor.Warning); } else { Monitor.Monitor.SetNotification("广告更新成功\n" + adAlert, parkMonitor.model.TextColor.Log); } break; case "RESPONSE": if (msg.context == "REGSUCCESS") { Console.WriteLine("收到web注册指令"); } else if (msg.context == "HEARTSUCCESS") { Console.WriteLine("收到web心跳指令"); } break; default: Monitor.Monitor.SetNotification("接收到无法识别的指令", parkMonitor.model.TextColor.Warning); break; } } catch (Exception ex) { Console.WriteLine("收消息," + ex.Message + "\n" + ex.StackTrace); } } private void SendBookCmd(bool parking, int state) { int countdown = 5; while (countdown-- > 0) { if (Monitor.Monitor.mainBlockInfo.bookParkCmd != 0 && countdown > 1) { Thread.Sleep(300); if (countdown == 2) { Monitor.Monitor.SetNotification("未能获取预约指令位0状态,尝试手动清除", parkMonitor.model.TextColor.Warning); MainBlockStru mbs = new MainBlockStru { centralHearbeat = -1, bookParkCmd = parking ? (short)0 : (short)-1, bookFetchCmd = !parking ? (short)0 : (short)-1, processCompleted = (short)-1, licenseReceived = -1 }; Monitor.Monitor.PLC.WriteToPLC(mbs, PLCDataType.central); Thread.Sleep(500); } continue; } MainBlockStru mb = new MainBlockStru { centralHearbeat = -1, bookParkCmd = parking ? (short)state : (short)-1, bookFetchCmd = !parking ? (short)state : (short)-1, processCompleted = (short)-1, licenseReceived = -1 }; Monitor.Monitor.PLC.WriteToPLC(mb, PLCDataType.central); Monitor.Monitor.SetNotification(mb.bookParkCmd + "," + mb.bookFetchCmd + "; 预约停车指令写入PLC", parkMonitor.model.TextColor.Log); Log.WriteLog(LogType.process, LogFile.INFO, mb.bookParkCmd + "," + mb.bookFetchCmd + "预约停车指令写入PLC"); break; } } /// /// 根据时间段处理所有准备预约及已预约指令 /// private void ReserveMsgHandling() { while (!isClosing) { //处理准备预约指令队列 lock (waitToReserveLock) { for (int i = 0; i < waitToReserveQueue.Count; i++) { try { MessageUTF8 msg = waitToReserveQueue.Dequeue(); DateTime startTime = DateTime.Parse(msg.bookTime); TimeSpan ts = DateTime.Now - startTime; //达到预约启动时间,放入已预约队列 Console.WriteLine("当前时间差:" + ts.TotalMinutes + ",指令类型:" + msg.cmd); if (ts.TotalMinutes >= 0) { //如果是预约停车,通知PLC减少一个可预约车位数 if (msg.cmd == "RESERVE") { //本地车位更新,2->3 for (int j = 0; j < Monitor.Monitor.parkingSpaceInfo.Count; j++) { if (Monitor.Monitor.parkingSpaceInfo[j].spaceStatus == 2) { ParkingSpaceStru ps = Monitor.Monitor.parkingSpaceInfo[j]; ps.spaceStatus = 3; Monitor.Monitor.parkingSpaceInfo[j] = ps; break; } } SendBookCmd(true, 1); Monitor.Monitor.SetNotification("通知PLC减少可预约车位", parkMonitor.model.TextColor.Log); } reservedQueue.Enqueue(msg); } //还未达到启动时间 else { waitToReserveQueue.Enqueue(msg); } } catch { } } } lock (reservedLock) { for (int i = 0; i < reservedQueue.Count; i++) { try { MessageUTF8 msg = reservedQueue.Dequeue(); DateTime startTime = DateTime.Parse(msg.bookTime); TimeSpan ts = DateTime.Now - startTime; //预约超时 if (ts.TotalMinutes > msg.bookLength * 60) { Monitor.Monitor.SetNotification(msg.context + " 预约已超时", parkMonitor.model.TextColor.Warning); Log.WriteLog(LogType.process, LogFile.INFO, msg.context + " 预约已超时"); //本地车位更新,3->2 for (int j = 0; j < Monitor.Monitor.parkingSpaceInfo.Count; j++) { if (Monitor.Monitor.parkingSpaceInfo[j].spaceStatus == 3) { ParkingSpaceStru ps = Monitor.Monitor.parkingSpaceInfo[j]; ps.spaceStatus = 2; Monitor.Monitor.parkingSpaceInfo[j] = ps; break; } } //通知PLC将可预约车位数恢复一个 SendBookCmd(true, 2); //恢复车辆状态 UpdateVehicleState(true, 0, 0, msg.context); UpdateVehicleState(false, 0, 0, msg.context); } else { reservedQueue.Enqueue(msg); } } catch { } } } Thread.Sleep(5000); } } /// /// 启动消息接收,启动超时指令处理 /// /// /// public bool Start(int port) { isClosing = false; connecting = false; waitToReserveQueue = new Queue(); reservedQueue = new Queue(); //MessageUTF8 message = new MessageUTF8(); //message.context = "sending message test"; //message.cmd = "S"; //message.parkingRecordsID = 1; //持续进行连接尝试 Task.Factory.StartNew(() => { //初始化后与web持续连接 try { Connections.Connection(); connected = true; while (!isClosing) { if (Connections.isAlive()) { comm = new Communication(); break; } else { Connections.close(); Connections.Connection(); } Thread.Sleep(1000); } } catch (Exception) { connected = false; Console.WriteLine("初始web服务连接异常"); } Connect(); }); //持续接收消息 receiveMsg = new Thread(() => { while (!isClosing) { try { if (connected && comm != null) { //byte[] bytes = new byte[256]; MessageUTF8 msg = ((MessageUTF8)comm.ReceiveMessage()); //string str = ""; //str = Encoding.Default.GetString(bytes); //Console.WriteLine(str); if (msg != null) { MsgHandling(msg); } //Monitor.Monitor.SetNotification(msg.context); } Thread.Sleep(200); } catch { Console.WriteLine("线程已中断"); } } }); receiveMsg.Start(); //根据所处时间段处理预约指令 Task.Factory.StartNew(() => { ReserveMsgHandling(); }); return true; } /// /// 停止消息接收模块 /// public void Stop() { isClosing = true; try { Connections.close(); } catch { } //throw new NotImplementedException(); } /// /// 预约车辆入场检测 /// /// /// public bool ReservedCarCheck(string license) { //对提前入场车辆,将预约指令丢出 lock (waitToReserveLock) { for (int i = 0; i < waitToReserveQueue.Count; i++) { MessageUTF8 msg = waitToReserveQueue.Dequeue(); if (msg.context != license) { waitToReserveQueue.Enqueue(msg); } } } //已进入预约状态车辆入场,审核确认后指令丢出 lock (reservedLock) { for (int i = 0; i < reservedQueue.Count; i++) { MessageUTF8 msg = reservedQueue.Dequeue(); if (msg.context == license) { return true; } else { reservedQueue.Enqueue(msg); } } } return false; } /// /// 主动连接web服务器 /// public void Connect() { //持续判断连接状态并重连 if (!connecting) { lock (connectLock) { connecting = true; int count = 3; while (!isClosing) { //if (receiveMsg != null) // Console.WriteLine(Connections.isAlive() + ", " + receiveMsg.ThreadState.ToString()); Console.WriteLine(Connections.isAlive() + "," + count + "," + connected); if (Connections.isAlive()) { if (!connected) { comm = new Communication(); Monitor.Monitor.SetNotification("web已连接上", parkMonitor.model.TextColor.Info); } count = 3; connected = true; if (receiveMsg != null && receiveMsg.ThreadState == ThreadState.Aborted) { try { receiveMsg.Start(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } else { if (count == 3 && connected) Monitor.Monitor.SetNotification("web连接已断开", parkMonitor.model.TextColor.Warning); else if (count == 0) { try { Connections.close(); //comm = null; } catch (Exception ex) { Console.WriteLine("网络异常,停止尝试"); } break; } else if (connected) { try { Connections.close(); } catch (Exception) { Console.WriteLine("服务没有开启,请检查服务器"); } } connected = false; count--; try { if (receiveMsg != null && receiveMsg.ThreadState == ThreadState.WaitSleepJoin) { receiveMsg.Interrupt(); } } catch (Exception ex) { Monitor.Monitor.SetNotification("连接断开,终止消息接收线程", parkMonitor.model.TextColor.Log); } Console.WriteLine(" 连接关闭,需要重新连接注册"); try { Connections.Connection(); } catch { Console.WriteLine("尝试连接异常"); } } Thread.Sleep(1000); } Monitor.Monitor.SetNotification("重连web服务器超时,请检查网络并手动连接web服务器", parkMonitor.model.TextColor.Error); connecting = false; } } else { if (!connected) Monitor.Monitor.SetNotification("正在尝试连接,请勿重复点击", parkMonitor.model.TextColor.Warning); else Monitor.Monitor.SetNotification("已连接,请勿重复点击", parkMonitor.model.TextColor.Info); } } /// /// 获取连接状态 /// /// public bool GetConnectStatus() { return Connections.isAlive(); } } }