博客地址: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>