WebServer.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. using centralController.model;
  2. using nettyCommunication;
  3. using PLCS7;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace centralController.WebServer
  11. {
  12. class MyWebServer : IWebServer
  13. {
  14. private Queue<MessageUTF8> waitToReserveQueue = null;
  15. private Queue<MessageUTF8> reservedQueue = null;
  16. private object waitToReserveLock = new object();
  17. private object reservedLock = new object();
  18. private Communication comm = null;
  19. private Thread receiveMsg = null;
  20. private bool isClosing { get; set; }
  21. private bool connected { get; set; }
  22. public void BookFetchRecord()
  23. {
  24. throw new NotImplementedException();
  25. }
  26. public void BookParkRecord()
  27. {
  28. throw new NotImplementedException();
  29. }
  30. /// <summary>
  31. /// 更新预约车车辆状态
  32. /// </summary>
  33. /// <param name="localDB"></param>
  34. /// <param name="state"></param>
  35. /// <param name="orderRecordsID"></param>
  36. /// <param name="license"></param>
  37. /// <returns></returns>
  38. private bool UpdateVehicleState(bool localDB, int state, int orderRecordsID, string license)
  39. {
  40. string vehicleUpdateSql = "";
  41. string vehicleInsertSql = "";
  42. if (orderRecordsID > 0)
  43. {
  44. if (state >= 0)
  45. {
  46. vehicleUpdateSql = "update vehicle set vehiclepParkState = " + state + " ,orderRecordsID = " + orderRecordsID + " where numberPlate = '" + license + "';";
  47. vehicleInsertSql = "insert into vehicle (numberPlate,vehiclepParkState,orderRecordsID) values " +
  48. "('" + license + "'," + state + "," + orderRecordsID + ");";
  49. }
  50. else
  51. {
  52. vehicleUpdateSql = "update vehicle set orderRecordsID = " + orderRecordsID + " where numberPlate = '" + license + "';";
  53. vehicleInsertSql = "insert into vehicle (numberPlate,orderRecordsID) values " +
  54. "('" + license + "'," + orderRecordsID + ");";
  55. }
  56. }
  57. else
  58. {
  59. if (state >= 0)
  60. {
  61. vehicleUpdateSql = "update vehicle set vehiclepParkState = " + state + " where numberPlate = '" + license + "';";
  62. vehicleInsertSql = "insert into vehicle (numberPlate,vehiclepParkState) values " +
  63. "('" + license + "'," + state + ");";
  64. }
  65. else
  66. {
  67. return false;
  68. }
  69. }
  70. List<string> vehicleUpdateList = new List<string>();
  71. List<string> vehicleInsertList = new List<string>();
  72. vehicleUpdateList.Add(vehicleUpdateSql);
  73. vehicleInsertList.Add(vehicleInsertSql);
  74. if (localDB)
  75. {
  76. if (!Monitor.Monitor.localDBOper.UpdateTransaction(vehicleUpdateList))
  77. {
  78. if (!Monitor.Monitor.localDBOper.Insert(vehicleInsertList))
  79. return false;
  80. else
  81. return true;
  82. }
  83. else return true;
  84. }
  85. else
  86. {
  87. if (!Monitor.Monitor.remoteDBOper.UpdateTransaction(vehicleUpdateList))
  88. {
  89. if (!Monitor.Monitor.remoteDBOper.Insert(vehicleInsertList))
  90. return false;
  91. else
  92. return true;
  93. }
  94. else return true;
  95. }
  96. }
  97. /// <summary>
  98. /// 插入预约记录
  99. /// </summary>
  100. /// <param name="localDB"></param>
  101. /// <param name="userID"></param>
  102. /// <param name="parking"></param>
  103. /// <param name="license"></param>
  104. /// <param name="orderTime"></param>
  105. /// <param name="orderLength"></param>
  106. /// <returns></returns>
  107. private bool InsertOrderRecord(bool localDB, string userID, bool parking, string license, string orderTime, int orderLength)
  108. {
  109. bool result = false;
  110. string orderRecordInsertSql;
  111. if (parking)
  112. {
  113. orderRecordInsertSql = "insert into orderrecords (userID,numberPlate,garageID, bookParkTime, bookHour, bookPrice,bookState) " +
  114. "VALUES (" + userID + ", '" + license + "', '" + Monitor.Monitor.garageID + "', '" + orderTime + "', " + orderLength + ",NULL, '0');";
  115. }
  116. else
  117. {
  118. orderRecordInsertSql = "insert into orderrecords (userID,numberPlate,garageID, bookFetchTime, bookHour, bookPrice,bookState) " +
  119. "VALUES (" + userID + ", '" + license + "', '" + Monitor.Monitor.garageID + "', '" + orderTime + "', " + orderLength + ",NULL, '2');";
  120. }
  121. List<string> orderList = new List<string>();
  122. orderList.Add(orderRecordInsertSql);
  123. if (localDB)
  124. result = Monitor.Monitor.localDBOper.Insert(orderList);
  125. else
  126. result = Monitor.Monitor.remoteDBOper.Insert(orderList);
  127. return result;
  128. }
  129. /// <summary>
  130. /// 找到当前预约记录ID
  131. /// </summary>
  132. /// <param name="localDB"></param>
  133. /// <param name="license"></param>
  134. /// <param name="latestIndex">最近第几条记录,1表示最新一条</param>
  135. /// <returns></returns>
  136. private int FindCurrentOrderRecordID(bool localDB, string license, int latestIndex = 1)
  137. {
  138. int currentID = 0;
  139. List<object[]> orderRecords = Monitor.Monitor.GetOrderRecords(localDB, license, DateTime.Now.ToString("yyyy-MM-dd"), DateTime.Now.AddDays(1).ToString("yyyy-MM-dd"));
  140. if (orderRecords.Count != 0)
  141. {
  142. try
  143. {
  144. currentID = (int)(UInt32)orderRecords[latestIndex - 1][0];
  145. }
  146. catch { }
  147. }
  148. return currentID;
  149. }
  150. /// <summary>
  151. /// 预约数据库操作
  152. /// </summary>
  153. /// <param name="localDB"></param>
  154. /// <param name="userID"></param>
  155. /// <param name="parking"></param>
  156. /// <param name="license"></param>
  157. /// <param name="orderTime"></param>
  158. /// <param name="orderLength"></param>
  159. /// <returns></returns>
  160. private bool ReserveDBOperation(bool localDB, string userID, bool parking, string license, string orderTime, int orderLength)
  161. {
  162. //预约记录插入db
  163. InsertOrderRecord(localDB, userID, parking, license, orderTime, orderLength);
  164. //查询预约记录id号
  165. int currentID = FindCurrentOrderRecordID(localDB, license);
  166. if (currentID == 0) { /*反馈web,预约失败*/ return false; }
  167. //更新车辆状态
  168. UpdateVehicleState(localDB, parking ? 4 : 5, currentID, license);
  169. return true;
  170. }
  171. /// <summary>
  172. /// 检查预约指令是否可行
  173. /// </summary>
  174. /// <param name="msg"></param>
  175. /// <returns></returns>
  176. private bool ReservationValidate(MessageUTF8 msg)
  177. {
  178. //可预约车位总数
  179. int allBookableSpace = Monitor.Monitor.ins.GetFreeSpaceCount(3);
  180. int count = 0;
  181. DateTime start, end;
  182. try
  183. {
  184. start = DateTime.Parse(msg.bookTime);
  185. end = start.AddHours(msg.bookLength);
  186. }
  187. catch { return false; }
  188. lock (waitToReserveLock)
  189. {
  190. Queue<MessageUTF8>.Enumerator enumer = waitToReserveQueue.GetEnumerator();
  191. while (enumer.MoveNext())
  192. {
  193. DateTime tempStart, tempEnd;
  194. try
  195. {
  196. tempStart = DateTime.Parse(enumer.Current.bookTime);
  197. tempEnd = start.AddHours(enumer.Current.bookLength);
  198. }
  199. catch { return false; }
  200. if (!((tempStart - end).TotalMinutes > 0 || (start - tempEnd).TotalMinutes > 0)) { count += 1; }
  201. }
  202. }
  203. if (allBookableSpace >= count)
  204. return true;
  205. else
  206. return false;
  207. }
  208. /// <summary>
  209. /// 根据消息类型分别处理
  210. /// </summary>
  211. /// <param name="msg"></param>
  212. private void MsgHandling(MessageUTF8 msg)
  213. {
  214. try
  215. {
  216. switch (msg.cmd)
  217. {
  218. //预约停
  219. case "RESERVE":
  220. if (msg.sender != "" && msg.bookTime != "" && msg.bookLength != 0)
  221. {
  222. MessageUTF8 returnMsg = new MessageUTF8();
  223. if (!ReservationValidate(msg))
  224. {
  225. //回复预约失败给web
  226. returnMsg.cmd = "FAILED";
  227. comm.SendMessage(returnMsg);
  228. }
  229. else
  230. {
  231. lock (waitToReserveLock)
  232. {
  233. waitToReserveQueue.Enqueue(msg);
  234. }
  235. //预约记录与车辆状态写入数据库
  236. ReserveDBOperation(true, msg.sender, true, msg.context, msg.bookTime, msg.bookLength);
  237. ReserveDBOperation(false, msg.sender, true, msg.context, msg.bookTime, msg.bookLength);
  238. //回复成功给web
  239. returnMsg.cmd = "0";
  240. comm.SendMessage(returnMsg);
  241. }
  242. }
  243. break;
  244. //预约取
  245. case "PREFETCH":
  246. break;
  247. //停车
  248. case "PARK":
  249. //根据号牌寻找对应号牌机编号,找不到则返回失败信息
  250. //判断号牌机编号对应PLC数据块是否空闲,空闲则判断按钮状态并发送停车指令到PLC,否则返回失败信息
  251. break;
  252. //取车
  253. case "FETCH":
  254. break;
  255. //连接断开消息
  256. case "DISCONNECT":
  257. Monitor.Monitor.SetNotification("收到连接断开提示消息");
  258. break;
  259. //更新广告
  260. case "ADVERT":
  261. string adAlert = "";
  262. bool result = Monitor.Monitor.advertMgr.UpdateAdvert(out adAlert);
  263. if (!result)
  264. {
  265. Monitor.Monitor.SetNotification("广告更新失败,请尝试手动更新");
  266. }
  267. else
  268. {
  269. Monitor.Monitor.SetNotification("广告更新成功\n" + adAlert);
  270. }
  271. break;
  272. default:
  273. Monitor.Monitor.SetNotification("接收到无法识别的指令");
  274. break;
  275. }
  276. }
  277. catch (Exception ex) { Console.WriteLine("收消息," + ex.Message + "\n" + ex.StackTrace); }
  278. }
  279. private void SendBookCmd(bool parking, int state)
  280. {
  281. int countdown = 5;
  282. while (countdown-- > 0)
  283. {
  284. if (Monitor.Monitor.mainBlockInfo.bookParkCmd != 0)
  285. Thread.Sleep(300);
  286. else
  287. {
  288. MainBlockStru mb = new MainBlockStru
  289. {
  290. centralHearbeat = -1,
  291. bookParkCmd = parking ? (short)state : (short)-1,
  292. bookFetchCmd = !parking ? (short)state : (short)-1,
  293. licenseReceived = -1
  294. };
  295. Monitor.Monitor.PLC.WriteToPLC(mb, PLCDataType.central);
  296. Monitor.Monitor.SetNotification(mb.bookParkCmd+","+mb.bookFetchCmd+"预约停车指令写入PLC");
  297. break;
  298. }
  299. if (countdown == 2)
  300. {
  301. Monitor.Monitor.SetNotification("未能获取预约指令位0状态,尝试手动清除");
  302. MainBlockStru mb = new MainBlockStru
  303. {
  304. centralHearbeat = -1,
  305. bookParkCmd = parking ? (short)0 : (short)-1,
  306. bookFetchCmd = !parking ? (short)0 : (short)-1,
  307. licenseReceived = -1
  308. };
  309. Monitor.Monitor.PLC.WriteToPLC(mb, PLCDataType.central);
  310. Thread.Sleep(500);
  311. }
  312. }
  313. }
  314. /// <summary>
  315. /// 根据时间段处理所有准备预约及已预约指令
  316. /// </summary>
  317. private void ReserveMsgHandling()
  318. {
  319. while (!isClosing)
  320. {
  321. //处理准备预约指令队列
  322. lock (waitToReserveLock)
  323. {
  324. for (int i = 0; i < waitToReserveQueue.Count; i++)
  325. {
  326. try
  327. {
  328. MessageUTF8 msg = waitToReserveQueue.Dequeue();
  329. DateTime startTime = DateTime.Parse(msg.bookTime);
  330. TimeSpan ts = DateTime.Now - startTime;
  331. //达到预约启动时间,放入已预约队列
  332. Console.WriteLine("当前时间差:"+ts.TotalMinutes+",指令类型:"+msg.cmd);
  333. if (ts.TotalMinutes >= 0)
  334. {
  335. Console.WriteLine();
  336. //如果是预约停车,通知PLC减少一个可预约车位数
  337. if (msg.cmd == "RESERVE")
  338. {
  339. SendBookCmd(true, 1);
  340. Monitor.Monitor.SetNotification("通知PLC减少可预约车位");
  341. }
  342. lock (reservedLock)
  343. {
  344. reservedQueue.Enqueue(msg);
  345. }
  346. }
  347. //还未达到启动时间
  348. else
  349. {
  350. waitToReserveQueue.Enqueue(msg);
  351. }
  352. }
  353. catch { }
  354. }
  355. }
  356. lock (reservedLock)
  357. {
  358. for (int i = 0; i < reservedQueue.Count; i++)
  359. {
  360. try
  361. {
  362. MessageUTF8 msg = reservedQueue.Dequeue();
  363. DateTime startTime = DateTime.Parse(msg.bookTime);
  364. TimeSpan ts = DateTime.Now - startTime;
  365. //预约超时
  366. if (ts.TotalMinutes > msg.bookLength * 60)
  367. {
  368. Monitor.Monitor.SetNotification("预约已超时");
  369. //通知PLC将可预约车位数恢复一个
  370. SendBookCmd(true, 2);
  371. //恢复车辆状态
  372. UpdateVehicleState(true, 0, 0, msg.context);
  373. UpdateVehicleState(false, 0, 0, msg.context);
  374. }
  375. }
  376. catch { }
  377. }
  378. }
  379. Thread.Sleep(5000);
  380. }
  381. }
  382. /// <summary>
  383. /// 启动消息接收,启动超时指令处理
  384. /// </summary>
  385. /// <param name="port"></param>
  386. /// <returns></returns>
  387. public bool Start(int port)
  388. {
  389. isClosing = false;
  390. waitToReserveQueue = new Queue<MessageUTF8>();
  391. reservedQueue = new Queue<MessageUTF8>();
  392. //MessageUTF8 message = new MessageUTF8();
  393. //message.context = "sending message test";
  394. //message.cmd = "S";
  395. //message.parkingRecordsID = 1;
  396. //持续进行连接尝试
  397. Task.Factory.StartNew(() =>
  398. {
  399. //初始化后与web持续连接
  400. while (!isClosing)
  401. {
  402. try
  403. {
  404. Connections.Connection();
  405. connected = true;
  406. comm = new Communication();
  407. break;
  408. }
  409. catch (Exception)
  410. {
  411. connected = false;
  412. Console.WriteLine("服务没有开启,请检查服务器");
  413. }
  414. Thread.Sleep(2000);
  415. }
  416. //持续判断连接状态并重连
  417. while (!isClosing)
  418. {
  419. Console.WriteLine(Connections.isAlive() + ", " + receiveMsg.ThreadState.ToString());
  420. if (Connections.isAlive())
  421. {
  422. if (!connected)
  423. {
  424. comm = new Communication();
  425. }
  426. connected = true;
  427. if (receiveMsg.ThreadState == ThreadState.Aborted)
  428. {
  429. try
  430. {
  431. receiveMsg.Start();
  432. }
  433. catch (Exception ex) { Console.WriteLine(ex.Message); }
  434. }
  435. }
  436. else
  437. {
  438. connected = false;
  439. try
  440. {
  441. if (receiveMsg.ThreadState == ThreadState.WaitSleepJoin)
  442. {
  443. receiveMsg.Interrupt();
  444. }
  445. }
  446. catch (Exception ex)
  447. {
  448. Monitor.Monitor.SetNotification("连接断开,终止消息接收线程");
  449. }
  450. Console.WriteLine(" 连接关闭,需要重新连接注册");
  451. try
  452. {
  453. Connections.Connection();
  454. }
  455. catch (Exception)
  456. {
  457. Console.WriteLine("服务没有开启,请检查服务器");
  458. }
  459. }
  460. Thread.Sleep(1000);
  461. }
  462. });
  463. //持续接收消息
  464. receiveMsg = new Thread(() =>
  465. {
  466. while (!isClosing)
  467. {
  468. try
  469. {
  470. if (connected && comm != null)
  471. {
  472. MessageUTF8 msg = ((MessageUTF8)comm.ReceiveMessage());
  473. if (msg != null)
  474. {
  475. MsgHandling(msg);
  476. }
  477. Monitor.Monitor.SetNotification(msg.context);
  478. }
  479. }
  480. catch { Console.WriteLine("线程已中断"); }
  481. }
  482. });
  483. receiveMsg.Start();
  484. //根据所处时间段处理预约指令
  485. Task.Factory.StartNew(() =>
  486. {
  487. ReserveMsgHandling();
  488. });
  489. return true;
  490. }
  491. /// <summary>
  492. /// 停止消息接收模块
  493. /// </summary>
  494. public void Stop()
  495. {
  496. isClosing = true;
  497. Connections.close();
  498. //throw new NotImplementedException();
  499. }
  500. /// <summary>
  501. /// 预约车辆入场检测
  502. /// </summary>
  503. /// <param name="license"></param>
  504. /// <returns></returns>
  505. public bool ReservedCarCheck(string license)
  506. {
  507. //对提前入场车辆,将预约指令丢出
  508. lock (waitToReserveLock)
  509. {
  510. for (int i = 0; i < waitToReserveQueue.Count; i++)
  511. {
  512. MessageUTF8 msg = waitToReserveQueue.Dequeue();
  513. if (msg.context != license)
  514. {
  515. waitToReserveQueue.Enqueue(msg);
  516. }
  517. }
  518. }
  519. //已进入预约状态车辆入场,审核确认后指令丢出
  520. lock (reservedLock)
  521. {
  522. for (int i = 0; i < reservedQueue.Count; i++)
  523. {
  524. MessageUTF8 msg = reservedQueue.Dequeue();
  525. if (msg.context == license)
  526. {
  527. return true;
  528. }
  529. else
  530. {
  531. reservedQueue.Enqueue(msg);
  532. }
  533. }
  534. }
  535. return false;
  536. }
  537. }
  538. }