Java WebSocket编程与网页简易聊天室
在webSocket還未引入前,許多開發人員通過各種非正規手段來完成更新網站的最新信息和到所有當前訪問者的任務,其中一種手段就是通過瀏覽器向服務器輪詢更新,但這種手段的網絡延遲比較明顯,其用戶體驗比較差。而webSocket協議的引入比較好的解決這種問題,webSocket是一種網絡協議,它允許兩個相連的端在一個TCP連接上進行全雙工通訊。它主要用來作為托管在Web服務器上的Web應用和瀏覽器之間的通訊機制,同樣,WebSocket可以在網絡間的任意兩端建立,而不一定要在瀏覽器和服務器上。Java Web Socket API 是JavaEE7平臺的核心特性。端點是Java WebSocket API組件模型的中心,而創建端點的方式有注解式和編程式。下面的內容都是關于WebSocket注解式編程。
WebSocket端點的4個生命周期事件
- 打開事件?
此事件發生在端點上建立新連接時并且在任何其他事件之前 - 消息事件?
此事件接收WebSocket對話的另外一端發送的消息。它可以發生在WebSocket端點接收了打開事件后并且在接收關閉事件關閉連接之前的任意時刻 - 錯誤事件?
此事件在WebSocket連接或者端點發生錯誤時產生 - 關閉事件?
此事件表示WebSocket端點的連接目前正在部分的關閉,它可以由參與連接的任意一個端點發出
注解式端點事件處理
將Java類聲明成WebSocket端點,在服務器端端點用@ServerEndpoint來注解,在客戶端可以使用@ClientEndpoint來注解。對于端點的四個生命周期事件:?
打開事件@OnOpen
消息事件@OnMessage
@OnMessage public void message(String textMessage,Session session){//處理文本信息,Session參數可選 }@OnMessage public void message(byte[] messageData,Session session){//處理二進制信息,Session參數可選 }@OnMessage public void message(String textMessage,boolean isLast){//處理分片段的文本信息,isLast 為false表示信息沒有接收完整,true則表示最后一條信息 }//所有的@OnMessage 也可以有返回值相當于發送消息的功能 @OnMessage public String message(String textMessage,Session session){//處理文本信息,Session參數可選return "I got it"; }錯誤事件@OnError
@OnError public void errorHandler(Throwable t){//log error here }關閉事件@OnClose
@OnClose public void goodbye(){// }發送信息
1.發送字符串消息
RemoteEndpoint.Basic發送文本信息:public void sendText(String text) throws IOEcxeption?
RemoteEndpoint.Basic發送文本信息到流:public Writer getSendStream() throws IOEcxeption?
RemoteEndpoint以片段形式發送文本消息:public void sendText(String partialMessage,boolean isLast) throws IOException?
以小片段序列的形式發送大的字符串消息,調用時isLast參數一般設為false,直到最后一個片段才設為true,表明消息發送完畢。
2.發送二進制消息
對于大多數應用,發送文本形式消息已經足夠,對于有特殊格式例如小圖像文件,以二進制形式發送消息則更合適?
RemoteEndpoint發送二進制消息:?
public void sendBinary(ByteBuffer data) throws IOException?
public void sendBinary(ByteBuffer partialByte,boolean isLast) throws IOException 以分片的形式發送,調用時isLast參數一般設為false,直到最后一個片段才設為true,表明消息發送完畢。?
RemoteEndpoint.Basic使用流發送二進制消息:?
public OutputStream getSendStream() throws IOException
基于Java WebSocket 編寫的簡易聊天室
服務端采用注解式編寫
package server; import java.io.IOException; import java.util.HashMap; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/echo")//注解使得此Java類聲明成WebSocket的端點 public class EchoServer {private boolean first = true;private String name;//用戶昵稱//connect key為session的ID,value為此對象thisprivate static final HashMap<String,Object> connect = new HashMap<String,Object>();//userMap key為session的ID,value為用戶名private static final HashMap<String,String> userMap = new HashMap<String,String>();private Session session;@OnOpenpublic void start(Session session){this.session = session; //獲取Seession,存入SashMapconnect.put(session.getId(),this);}@OnMessagepublic void echo( String incomingMessage,Session session){EchoServer client = null ;//first 判斷是否第一次傳值,第一次的值是昵稱,由web端的OnOpen傳入if(first){this.name = incomingMessage;String message ="系統:歡迎"+name;//昵稱和session的Id一一對應存儲在HashMapuserMap.put(session.getId(), name);//將message廣播給所有用戶for (String key : connect.keySet()) { try { client = (EchoServer) connect.get(key); synchronized (client) { //給對應的Web端發送一個文本消息client.session.getBasicRemote().sendText(message); } } catch (IOException e) { connect.remove(client); try { client.session.close(); } catch (IOException e1) { } } } //輸入昵稱后,往后的交互傳值都不是第一次first = false;}else{/*** incomingMessage的值為xxx@xxxxx的形式xxx為要發給的用戶昵稱,all則表示發給所有人* incomingMessage.split("@",2);以@為分隔符把字符串分為xxx和xxxxx兩部分*/String [] list = incomingMessage.split("@",2);if(list[0].equalsIgnoreCase("all")){ //all廣播全部人sendAll(list[1],session);}else{boolean you = false;//標記是否找到發送的用戶for(String key : userMap.keySet()){if(list[0].equalsIgnoreCase(userMap.get(key))){client = (EchoServer) connect.get(key); synchronized (client) { try {//發送信息給指定的用戶client.session.getBasicRemote().sendText(userMap.get(session.getId())+"對你說:"+list[1]);} catch (IOException e) {e.printStackTrace();} } you = true;//找到指定用戶標記為truebreak;}}//you為true則在自己頁面顯示自己對xxx說xxxxx,否則顯示系統:無此用戶if(you){try {session.getBasicRemote().sendText("自己對"+ list[0]+"說:"+list[1]);} catch (IOException e) {e.printStackTrace();}}else{try {session.getBasicRemote().sendText("系統:無此用戶");} catch (IOException e) {e.printStackTrace();}}}}}@OnClosepublic void close(Session session){//當一用戶退出時,對其他用戶進行廣播String message ="系統:"+userMap.get(session.getId()) +"退出群聊";userMap.remove(session.getId());connect.remove(session.getId());for (String key : connect.keySet()) { EchoServer client = null ; try { client = (EchoServer) connect.get(key); synchronized (client) { client.session.getBasicRemote().sendText(message); } } catch (IOException e) { connect.remove(client); try { client.session.close(); } catch (IOException e1) { } } } }//對信息進行全體廣播public static void sendAll(String mess,Session session){ String who = null;for (String key : connect.keySet()) { EchoServer client = null ; try { client = (EchoServer) connect.get(key); if(key.equalsIgnoreCase(session.getId())){who = "自己對大家說 : ";}else{who = userMap.get(session.getId())+"對大家說 : ";}synchronized (client) { client.session.getBasicRemote().sendText(who+mess); } } catch (IOException e) { connect.remove(client); try { client.session.close(); } catch (IOException e1) { } } } } public String getName(){return this.name;} }web端
<!DOCTYPE html> <html><head><title>簡易聊天室</title><meta name="keywords" content="keyword1,keyword2,keyword3"><meta name="description" content="this is my page"><meta name="content-type" content="text/html; charset=UTF-8"><script type="text/javascript">var ws;var wsUri = "ws://localhost:8080/Socket/echo";ws = new WebSocket(wsUri);ws.onopen = function(){n=prompt('請給自己取一個昵稱:');n=n.substr(0,16);ws.send(n);//在服務端必須由OnMessage接收此消息};//處理連接后的信息處理ws.onmessage = function(message){writeToScreen(message.data); };//對發送按鈕進行監聽,獲取發送的信息和發送對象function button(){message = document.getElementById('in').value;towho = document.getElementById('towho').value + "@";ws.send(towho+message);} //發生錯誤時,處理錯誤ws.onerror = function (evt){ writeToScreen('<span style="color:red;">ERROR:</span>'+evt.data);ws.close();};//把信息顯示到當前屏幕function writeToScreen(message){var pre = document.createElement("p");pre.style.wordWrap = "break-word";pre.innerHTML = message;output.appendChild(pre);} //當關閉頁面時執行ws.closewindow.onbeforeunload=function (){ ws.close();}; </script></head><body><h1>簡易聊天室</h1><div style="width:400px;height:260px; overflow:scroll; border:3px solid; " id="output"> </div> <br> <div style="text-align:left;"><form action=""><input id="in" name="message" value="" type="text" style="width:400px;height:60px; border:3px solid; " ><br><br><input onclick="button()" value="發送" type="button"/>發送對象:<input id="towho" name="towho" value="all"><br></form></div></body> </html>部署程序,Tomcat從7.0.27開始支持WebSocket,從7.0.47開始支持JSR-356,上述代碼也是需要部署在Tomcat7.0.47上,JDK1.7以上才能運行。當瀏覽器或者Tomcat或者jdk不支持的時候會報undefined的錯誤?
?
?
總結
以上是生活随笔為你收集整理的Java WebSocket编程与网页简易聊天室的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: update语句执行卡死现象原因及解决方
- 下一篇: VB.net写的音乐播放器,带百度翻译歌