博客地址:https://ainyi.com/67
WebSocket協議是基於TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發送信息給客戶端。
需要導入一個jar包:javax.websocket-api-1.0-rc4.jar
注意點:
需要實現這幾個方法:
1 //注冊事件 2 ws.onopen = function(){ 3 openWs(); 4 }; 5 ws.onmessage = function(event){ 6 msgWs(event); 7 }; 8 ws.onclose = function(){ 9 closeWs(); 10 }; 11 ws.onerror = function(){ 12 errorWs(); 13 };
后台代碼:
1 package com.krry.socket; 2 import java.io.IOException; 3 import java.util.concurrent.CopyOnWriteArraySet; 4 5 import javax.websocket.OnClose; 6 import javax.websocket.OnError; 7 import javax.websocket.OnMessage; 8 import javax.websocket.OnOpen; 9 import javax.websocket.Session; 10 import javax.websocket.server.ServerEndpoint; 11 12 //該注解用來指定一個URI,客戶端可以通過這個URI來連接到WebSocket。類似Servlet的注解mapping。無需在web.xml中配置。 13 @ServerEndpoint("/websocket") 14 public class MyWebSocket { 15 //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。 16 private static int onlineCount = 0; 17 18 //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識 19 private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>(); 20 21 //與某個客戶端的連接會話,需要通過它來給客戶端發送數據 22 private Session session; 23 24 /** 25 * 連接建立成功調用的方法 26 * @param session 可選的參數。session為與某個客戶端的連接會話,需要通過它來給客戶端發送數據 27 */ 28 @OnOpen 29 public void onOpen(Session session){ 30 this.session = session; 31 webSocketSet.add(this); //加入set中 32 addOnlineCount(); //在線數加1 33 System.out.println("有新連接加入!當前在線人數為" + getOnlineCount()); 34 } 35 36 /** 37 * 連接關閉調用的方法 38 */ 39 @OnClose 40 public void onClose(){ 41 webSocketSet.remove(this); //從set中刪除 42 subOnlineCount(); //在線數減1 43 System.out.println("有一連接關閉!當前在線人數為" + getOnlineCount()); 44 } 45 46 /** 47 * 收到客戶端消息后調用的方法 48 * @param message 客戶端發送過來的消息 49 * @param session 可選的參數 50 */ 51 @OnMessage 52 public void onMessage(String message, Session session) { 53 System.out.println("來自客戶端的消息:" + message); 54 55 //群發消息 56 for(MyWebSocket item: webSocketSet){ 57 try { 58 item.sendMessage(message); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 continue; 62 } 63 } 64 } 65 66 /** 67 * 發生錯誤時調用 68 * @param session 69 * @param error 70 */ 71 @OnError 72 public void onError(Session session, Throwable error){ 73 System.out.println("發生錯誤"); 74 error.printStackTrace(); 75 } 76 77 /** 78 * 這個方法與上面幾個方法不一樣。沒有用注解,是根據自己需要添加的方法。 79 * @param message 80 * @throws IOException 81 */ 82 public void sendMessage(String message) throws IOException{ 83 this.session.getBasicRemote().sendText(message); 84 //this.session.getAsyncRemote().sendText(message); 85 } 86 87 public static synchronized int getOnlineCount() { 88 return onlineCount; 89 } 90 91 public static synchronized void addOnlineCount() { 92 MyWebSocket.onlineCount++; 93 } 94 95 public static synchronized void subOnlineCount() { 96 MyWebSocket.onlineCount--; 97 } 98 }
前端代碼:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <!doctype html> 3 <html> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 6 <meta name="keywords" content=""> 7 <meta name="description" content=""> 8 <title>基於Java服務器端的消息主動推送技術揭秘 --krry</title> 9 <link rel="stylesheet" href="css/animate.css"/> 10 <link rel="stylesheet" type="text/css" href="css/sg.css" /> 11 <style> 12 *{margin:0;padding:0;} 13 body{background:url("images/5.jpg");background-size:cover;} 14 h1{margin-top:50px;text-align:center;color:#fff;text-shadow:1px 1px 1px #000;font-family:-webkit-body;font-size:24px;} 15 .box{width:700px;margin:20px auto;} 16 .box span{color:#f60;font-size:16px;font-family:"微軟雅黑";} 17 .box .shu{text-indent:1em;height:24px;font-family:"微軟雅黑";border:0;outline:none;font-size:14px;} 18 .box .add{width:300px;margin-right:24px;} 19 .box .user{width:200px;} 20 .box .btn{width:80px;height:34px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;margin-top:20px;font-size:16px;font-family:"微軟雅黑";} 21 .box .area{line-height: 29px;height:280px;width:680px;padding:10px;overflow:auto;font-size:16px;font-family:"微軟雅黑";margin:20px 0;outline:none;box-shadow:1px 2px 18px #000} 22 .box .setex{text-indent:1em;height:28px;border:1px solid #6c0;width:618px;outline:none;float:left;font-family:"微軟雅黑";} 23 .box .send{font-size:14px;width:80px;height:30px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;font-family:"微軟雅黑";} 24 </style> 25 </head> 26 <body> 27 <h1>基於Java服務器端的消息主動推送技術揭秘 --krry</h1> 28 <div class="box"> 29 <span>服務器地址:</span><input type="text" class="shu add" value="localhost/krry_NetChat/websocket" readonly/> 30 <span>用戶名:</span><input type="text" class="shu user" value="匿名"/> 31 <input type="button" value="連接" class="btn" /> 32 <div class="area" id="boxx"></div> 33 <div class="c_cen"> 34 <input type="text" class="setex"/> 35 <input type="button" value="發送" class="send"> 36 </div> 37 </div> 38 <script src="js/jquery-1.11.1.min.js"></script> 39 <script src="js/sg.js"></script> 40 <script src="js/sgutil.js"></script> 41 <script> 42 var close = true; 43 var ws; 44 $(function(){ 45 $(".c_cen").hide(); 46 //首先判斷瀏覽器是否支持webSocket,支持h5的瀏覽器才會支持 47 if(window.WebSocket){ 48 printMsg("您的瀏覽器支持WebSocket,您可以嘗試連接到聊天服務器!","OK"); 49 }else{ 50 printMsg("您的瀏覽器不支持WebSocket,請選擇其他瀏覽器!","ERROR"); 51 //設置按鈕不可點擊 52 $(".btn").attr("disabled","true"); 53 } 54 }); 55 //打印信息 56 function printMsg(msg,msgType){ 57 if(msgType == "OK"){ 58 msg = "<span style='color:green'>"+msg+"</span>"; 59 } 60 if(msgType == "ERROR"){ 61 msg = "<span style='color:red'>"+msg+"</span>"; 62 } 63 $(".area").append(msg+"<br/>"); 64 var boxx = document.getElementById("boxx"); 65 boxx.scrollTop = boxx.scrollHeight;//使滾動條一直在底部 66 } 67 68 //打開Socket 69 function openWs(){ 70 printMsg("鏈接已建立","OK"); 71 ws.send("【"+$(".user").val()+"】已進入聊天室"); 72 $(".c_cen").show(); 73 } 74 75 //接收消息的時候 76 function msgWs(e){ 77 printMsg(e.data); 78 } 79 //關閉連接 80 function closeWs(){ 81 $(".btn").val("連接"); 82 $(".c_cen").hide(); 83 } 84 //產生錯誤 85 function errorWs(){ 86 printMsg("您與服務器連接錯誤...","ERROR"); 87 } 88 89 //點擊發送按鈕 90 $(".send").click(function(){ 91 var text = $(".setex").val(); 92 if(text == null || text == "") return; 93 $(".setex").val(""); 94 ws.send("【"+$(".user").val()+"】:"+text); 95 }); 96 97 //點擊連接 98 $(".btn").click(function(){ 99 if($(".add").val() && $(".user").val()){ 100 if(close){ 101 printMsg("正在准備連接服務器,請稍等..."); 102 var url = "ws://"+$(".add").val(); 103 if("WebSocket" in window){ 104 ws = new WebSocket(url); 105 }else if("MozWebSocket" in window){ 106 ws = new MozWebSocket(url); 107 } 108 //已連接 109 $(".btn").val("斷開"); 110 close = false; 111 112 //注冊事件 113 ws.onopen = function(){ 114 openWs(); 115 }; 116 ws.onmessage = function(event){ 117 msgWs(event); 118 }; 119 ws.onclose = function(){ 120 closeWs(); 121 }; 122 ws.onerror = function(){ 123 errorWs(); 124 }; 125 126 //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。 127 window.onbeforeunload = function(){ 128 ws.send("【"+$(".user").val()+"】離開了聊天室"); 129 close = true; 130 ws.close(); 131 }; 132 133 }else{ 134 ws.send("【"+$(".user").val()+"】離開了聊天室"); 135 close = true; 136 ws.close(); 137 } 138 }else{ 139 $.tmDialog.alert({open:"left",content:"服務器地址和用戶名不能為空哦...",title:"提示哦~~~"}); 140 } 141 }); 142 143 //回車鍵 144 $(".setex").keypress(function(event){ 145 if(event.keyCode == 13){ 146 $(".send").trigger("click"); 147 } 148 }); 149 </script> 150 </body> 151 </html>

博客地址:https://ainyi.com/67
