張文康+王治豪+唐建國(guó)
摘要:該文論述websocket信息推送技術(shù)的概念,以及如何在高校教學(xué)網(wǎng)絡(luò)系統(tǒng)中設(shè)計(jì)實(shí)現(xiàn)websocket信息推送。
關(guān)鍵詞:推送技術(shù);高校教學(xué)網(wǎng)絡(luò)系統(tǒng);實(shí)時(shí)通信
中圖分類(lèi)號(hào):TP393 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2016)27-0064-02
1 背景
傳統(tǒng)的HTTP request模式存在明顯的缺點(diǎn),瀏覽器通過(guò)不斷向服務(wù)器“輪詢(xún)”獲取最新信息,從而占用大量帶寬資源。WebSocket協(xié)議作為HTML5的一種新協(xié)議,很好地解決了這個(gè)問(wèn)題:瀏覽器發(fā)出websocket連接請(qǐng)求,服務(wù)器發(fā)生回應(yīng),產(chǎn)生“握手”,從而使瀏覽器與服務(wù)器之間產(chǎn)生長(zhǎng)連接。這個(gè)長(zhǎng)連接的生命周期是從建立握手到瀏覽器或者服務(wù)器一方主動(dòng)斷開(kāi)連接為止,相對(duì)于以往的http連接,生命周期長(zhǎng)。
2 服務(wù)器信息推送
首先,用戶(hù)頁(yè)面的布局用的是html的iframe子框架組合,頭部子框架留出一塊位置用戶(hù)顯示系統(tǒng)推送消息,同時(shí)負(fù)責(zé)與Server端進(jìn)行websocket連接。然后管理員賬號(hào)有系統(tǒng)消息選項(xiàng),進(jìn)入消息面板進(jìn)行消息推送。
關(guān)鍵功能代碼介紹如下。
子frame觸發(fā)同源兄弟frame發(fā)送函數(shù):
function postToServer(){
parent.frames["topFrame"].postToServer();
}
兄弟frame將消息發(fā)送給服務(wù)器:
function postToServer(){
var msg = parent.frames["main"].document.getElementById("pushtext").value;
we.send(msg);
}
Server端存儲(chǔ)在線(xiàn)用戶(hù)session的數(shù)據(jù)結(jié)構(gòu)為動(dòng)態(tài)數(shù)組:
private static ArrayList
若用戶(hù)成功用websocket與Server握手時(shí),將該用戶(hù)節(jié)點(diǎn)加入數(shù)組:
public void onOpen(WsOutbound outbound){
System.out.println("Open Client");
this.myoutbound = outbound;
mmiList.add(this);}
用戶(hù)關(guān)閉網(wǎng)站,與服務(wù)器斷開(kāi)握手時(shí),刪除該用戶(hù)節(jié)點(diǎn):
public void onClose(int status){
System.out.println("Close Client.");
mmiList.remove(this);
}
系統(tǒng)消息推送時(shí),Server端將從管理員用戶(hù)接收來(lái)的消息發(fā)送給所有在線(xiàn)用戶(hù);發(fā)送時(shí)通過(guò)遍歷在線(xiàn)用戶(hù)session數(shù)組進(jìn)行發(fā)送:
public void onTextMessage(CharBuffer cb) throws IOException{
System.out.println("Accept Message:"+cb);
for(MyMessageInbound mmib : mmiList){
CharBuffer buffer = CharBuffer.wrap(cb);
mmib.myoutbound.writeTextMessage(buffer);
mmib.myoutbound.flush();
}
}
3 客戶(hù)端信息推送
websocket技術(shù)如果是管理員面向全體在線(xiàn)用戶(hù)就是系統(tǒng)推送,而如果是用戶(hù)與用戶(hù)間互相進(jìn)行推送就升級(jí)為了在線(xiàn)聊天。
關(guān)鍵功能代碼介紹如下。
//發(fā)送消息給Server
function sendMsg() {
var fromName = parent.frames["main"].document.getElementById("userName").innerHTML;
var toName = parent.frames["main"].document.getElementById(name).value; //發(fā)給誰(shuí)
var content = parent.frames["main"].document.getElementById(writeMsg).value; //發(fā)送內(nèi)容
ws.send(fromName+","+toName+","+content);
}
//從Server接收消息
ws.onmessage = function(e){
if(flage == 0){ parent.frames["BoardMenu"].document.getElementById("message").inn erHTML += e.data + "
";
}else{ parent.frames["main"].document.getElementById("xiaoxi").textContent += e.data + "\n";
} }
//Server端存儲(chǔ)用戶(hù)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)是哈希表
public static HashMap
HashMap
String msgString = msg.toString();
String m[] = msgString.split(",");
map.put("fromName", m[0]);
map.put("toName", m[1]);
map.put("content", m[2]);
return map;
}
//服務(wù)器發(fā)送給消息接收者
protected void onTextMessage(CharBuffer msg) throws IOException {
//用戶(hù)所發(fā)消息處理后的map
HashMap
//上線(xiàn)用戶(hù)集合類(lèi)map
HashMap
String fromName = messageMap.get("fromName"); //消息來(lái)自人 的userId
String toName = messageMap.get("toName"); //消息發(fā)往人的 userId
//獲取該用戶(hù)
MessageInbound messageInbound = userMsgMap.get(toName);
MessageInbound messageInbound2 = userMsgMap.get(fromName); //在倉(cāng)庫(kù)中取出發(fā)往人的MessageInbound
if(messageInbound!=null){ //如果發(fā)往人 存在進(jìn)行操作
WsOutbound outbound = messageInbound.getWsOutbound();
String content = messageMap.get("content"); //獲取消息內(nèi)容
String msgContentString = fromName + " " + content; //構(gòu)造發(fā)送的消息
//發(fā)出去內(nèi)容
CharBuffer toMsg = CharBuffer.wrap(msgContentString.toCharArray());
outbound.writeTextMessage(toMsg); //
outbound.flush();
if(messageInbound2!=null){ //如果發(fā)往人 存在進(jìn)行操作
WsOutbound outbound2 = messageInbound2.getWsOutbound();
String content2 = messageMap.get("content"); //獲取消息內(nèi)容
String msgContentString2 = fromName + " " + content2; //構(gòu)造發(fā)送的消息
//發(fā)出去內(nèi)容
CharBuffer toMsg2 = CharBuffer.wrap(msgContentString2.toCharArray());
outbound2.writeTextMessage(toMsg2);
outbound2.flush();
}
}else{
WsOutbound outbound3 = messageInbound2.getWsOutbound();
String error = "系統(tǒng)消息:對(duì)不起,對(duì)方不在線(xiàn)!";
CharBuffer toMsg3 = CharBuffer.wrap(error.toCharArray());
outbound3.writeTextMessage(toMsg3);
outbound3.flush();
}
4 結(jié)束語(yǔ)
本文基于websocket技術(shù)實(shí)現(xiàn)了網(wǎng)絡(luò)教學(xué)系統(tǒng)的信息推送服務(wù),實(shí)現(xiàn)了管理員面向全體在線(xiàn)用戶(hù)就是系統(tǒng)推送,用戶(hù)與用戶(hù)間的在線(xiàn)聊天等功能。
參考文獻(xiàn):
[1] Williams N S. Java Web高級(jí)編程[M]. 王肖峰, 譯. 北京: 清華大學(xué)出版社, 2015.
[2] Ja Lengstorf, Leggetter P.構(gòu)建實(shí)時(shí)Web應(yīng)用[M]. 肖志清, 譯.北京: 機(jī)械工業(yè)出版社, 2013.
[3] 趙振,王順. Web異步與實(shí)時(shí)交互iframe Ajax WebSocket開(kāi)發(fā)實(shí)戰(zhàn)[M]. 北京: 人民郵電出版社, 2016.