錢 立
(四川職業(yè)技術(shù)學(xué)院,四川 遂寧 629000)
伴隨著智能手機的全面普及,人們在衣食住行各方面依賴手機查詢各種有用信息[1]。無車上班族每天出行幾乎都依賴城市公交系統(tǒng),這類人會習(xí)慣性查詢實時公交信息。公交實時位置查詢帶來兩大好處,一是節(jié)省乘客等待時間,基本上可以比較“準(zhǔn)時”地趕上車,一定程度上減少各站臺乘客擁擠狀態(tài),二是社會心理學(xué)方面,可緩解乘客等待時的焦慮,增加社會和諧度。
公交系統(tǒng)實時位置查詢功能雖說簡單但又有并發(fā)響應(yīng)難度。簡單即是說任何一個乘客進入公交系統(tǒng)查詢頁面,選擇將要乘坐的公交路數(shù)和往返方向,比如203 路(從育才西路到四川職業(yè)技術(shù)學(xué)院方向),那么在查詢結(jié)果展示頁面上將顯示出這個線路上全部站臺多個車輛的運行和到站實時情況。查詢僅需提供兩個參數(shù),一個是公交路數(shù),另一個是往或返的方向。
有難度即是說對于一個中大型城市,公交系統(tǒng)往往有幾十路或上百路公交車,每一路公交分往返兩個方向,每一路公交的站臺一般有十多個,高峰上下班期間假定平均每個站臺有15 名乘客,其中有10 名乘客會使用公交實時位置查詢。那么這個公交查詢系統(tǒng)高峰期間每秒種可能提供的查詢請求數(shù)萬次左右,所以該系統(tǒng)應(yīng)當(dāng)有較高的請求并發(fā)性,能及時響應(yīng)。
乘客查詢公交實時位置都會使用Http 方式連接到服務(wù)器,以往使用技術(shù)Long POLLing 等輪詢方式來實現(xiàn)實時,但這種技術(shù)浪費大量網(wǎng)絡(luò)、服務(wù)器資源和等待時間,不是最好解決方案。在HTML5 技術(shù)不斷推陳出新后,使用WebSocket 可提供更加高效的實時數(shù)據(jù)交互。
WebSocket 是HTML5 提供的一種在單個TCP連接上進行全雙工通訊的協(xié)議[2]??梢钥醋鍪荋ttp 協(xié)議的一個升級,使得在服務(wù)器和瀏覽器之間能進行雙向交流,只要連接創(chuàng)建后服務(wù)器就可以實時推送消息給瀏覽器,這是一個重要的改變。主要API 有:連接建立時觸發(fā)open 事件,onopen()進行處理;客戶端接收服務(wù)端數(shù)據(jù)時觸發(fā)message 事件,onmessage()進行處理;使用send()發(fā)送數(shù)據(jù),close()關(guān)閉連接。[3-4]
通過分析知道查詢系統(tǒng)需要能及時響應(yīng)高并發(fā)請求,現(xiàn)階段Node.js 技術(shù)用來做高并發(fā)是一種很好的選擇。Node.js 是一個基于Chrome V8引擎的JavaScript 運行環(huán)境。Node.js 使用了一個事件驅(qū)動、非阻塞式I/O 的模型,使其輕量又高效。Node.js 適合運用在高并發(fā)、I/O 密集、少量業(yè)務(wù)邏輯的場景。[5]
PC 和手機上的現(xiàn)代瀏覽器都支持WebSocket技術(shù),Node.js 為了能支持WebSocket 需要第三方軟件支持包(這類軟件包很多,本文選用ws)。ws 是應(yīng)用于Node.js 下的實現(xiàn)了Web-Socket 功能的一個軟件包,它簡單快速,集成了客戶端和服務(wù)端測試能力。ws 有兩個主要類WebSocket.Server 和WebSocket[5]。WebSocket.Server 主要事件是connection 事件,與Html5 的WebSocket API 類似。
對于公交系統(tǒng)實時位置查詢,本文僅考慮瀏覽器發(fā)出查詢請求,服務(wù)器查詢得到實時位置數(shù)據(jù)推送給瀏覽器這兩個過程,不考慮各路公交GPS 位置的收集、發(fā)送給服務(wù)器判斷位置及存儲等其余過程。
先考慮一路公交車往返兩個方向的查詢及顯示,多路公交同樣處理。Node.js 結(jié)合Express做頁面查詢busInfo.htm,并且設(shè)計一個Query-Server.js 提供服務(wù)端查詢服務(wù)。QueryServer.js 需引用ws 模塊以便Node.js 支持WebSocket。
以站臺為基準(zhǔn)來設(shè)計數(shù)據(jù)格式,將某路公交線路上的站臺依次編號1、2、……、n,各編號有站臺名稱,來車狀態(tài)兩種(0:表示未到,1:表示到站)。考慮數(shù)據(jù)精簡,選擇JSON 格式,實例公交203 路車從育才西路到四川職業(yè)技術(shù)學(xué)院方向數(shù)據(jù)表示如下:
{"RouteID":203,//公交車路數(shù)
"GoBack":0,//0:往方向1:返方向
"stations":[
{"xuhao":1,"status":0, "name":" 育才西路"},
{"xuhao":0,"status":1, "name":" 育才西路出"},
{"xuhao":2,"status":0, "name":" 育才路口"},
……,
{"xuhao":13,"status":1,"name":" 環(huán)島商務(wù)中心"},
{"xuhao":0,"status":0,"name":" 環(huán)島商務(wù)中心出"},
{"xuhao":14,"status":0,"name":" 四川職業(yè)技術(shù)學(xué)院"}]}
含義描述:RouteID 表示公交路數(shù);GoBack表示往返;stations 表示站臺,是一個JSON 數(shù)組。數(shù)組中每個站臺有三個屬性,xuhao 表示站臺序號(xuhao 為0 表示某兩個站臺之間),name 表示站臺名,status 為1 表示對應(yīng)站臺序號有車,為0 表示無車?,F(xiàn)在站臺的情況是:在育才西路與育才路口之間的途中有車,在環(huán)島商務(wù)中心有車到站。
const WebSocket = require(’ws’);
const wss = new WebSocket.Server ({port:8010});
wss.on (’connection’,function connection(ws,req){
// 根據(jù)req.url 中車次routeID 和往返方向0 查詢
var busRouteInfo=getBusRouteInfo(routeID,0);
ws.on (’message’, function incoming(message){
ws.send(busRouteInfo);
});
var tm = setInterval(function(){
try { busRouteInfo=getBusRouteInfo(routeID,0);
ws.send(busRouteInfo);
}catch(e){
consol e.log("出錯,清除定時器"+e);
clear Interval(t m);
}},5000);//每隔5 秒鐘發(fā)送一次更新});
console.log (’ 服務(wù)器運行,綁定在端口8010’);
其中g(shù)etBusRouteInfo(routeID,0)這個方法(需依據(jù)后臺數(shù)據(jù)庫單獨設(shè)計)根據(jù)提供的公交路數(shù)和往返方向參數(shù)從數(shù)據(jù)庫查詢到數(shù)據(jù)后以JS O N 格式返回。服務(wù)器端設(shè)置了一個定時器,每隔5 秒鐘就重新查詢更新公交位置信息。
//打開一個WebSocket
var ws = new WebSocket ("ws://192.168.1.1:8010/RouteNo="
+checi.value+"&goback=0");
ws.onopen = function(){
ws.send (" 請查詢"+checi.value+" 路公交車");
};
wws.onmessage = function (evt) {
var busRouteInfo = evt.data;
jsonRoute = JSON.parse(busRouteInfo);// 先刪除所有子節(jié)點
while(myRoute.hasChildNodes()){
myRoute.removeChild (myRoute.firstChild);
}
busStartEnd.innerText = "";
var number = jsonRoute.stations.length;
myLine.style.height = number*40+’px’;
var len = jsonRoute.stations.length;
busStartEnd.innerText = " 公交"
+checi.value+" 路,始發(fā)站:
+jsonRoute.stations [0].name+"---〉終點站:"
+jsonRoute.stations[len-1].name;
for(var i in jsonRoute.stations){
var tmpDiv = document.createElement(’div’);
var tmpImg = document.createElement(’img’);
var tmpSpan = document.createElement(’span’);
if (jsonRoute.stations [i].status == 0){
tmpImg.src=’Images/kong.png’;
}else{ tmpImg.src=’Images/bus.png’; }
if (i%2==1){tmpSpan.innerText = "-- 途中";
}else{
tmpSpan.innerText =
jsonRoute.stations[i].xuhao+
" "+jsonRoute.stations[i].name;
}
tmpDiv.append(tmpImg);
tmpDiv.append(tmpSpan);
myRoute.append(tmpDiv);
}//end for
};//end onmessage()
圖1 公交203 路實時運行情況
瀏覽器端使用WebSocket 方式先創(chuàng)建與服務(wù)器的鏈接,當(dāng)服務(wù)器推送消息來時,取出該消息解析為JS O N 格式,然后依次創(chuàng)建相應(yīng)的頁面元素顯示,運行效果如上圖1。
智慧城市為了實現(xiàn)其智慧功能要求城市公交提供更優(yōu)的服務(wù)。城市公交實時位置查詢是無車上班族出行的一個重要需求。本文分析了公交實時位置查詢系統(tǒng)應(yīng)具備高并發(fā)處理能力,采用Node.js 結(jié)合Express 實現(xiàn)Web 頁面瀏覽查詢,在Web 頁面使用HTML5 的WebSocket 技術(shù),服務(wù)器端使用ws 組件提供WebSocket 支持與之結(jié)合,實現(xiàn)了服務(wù)器端更高效的實時推送位置信息。HTML5 的WebSocket 技術(shù)和Node.js 結(jié)合使得實現(xiàn)公交系統(tǒng)實時位置查詢變得更加簡潔高效。