WebServer.cs 19 KB

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