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