原理
很多网站为了实现即时聊天,使用的是轮询方式(在特定的时间间隔,由浏览器向服务器端发出 Http request,然后由服务器返回最新的数据)实现。这种传统的 Http request的方式有个明显的缺点,浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽。
比较新的方式是Comet—用了Ajax,但是还是要发出请求。
但是在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。这样做的两大好处是
- Header
互相沟通的Header是很小的-大概只有 2 Bytes
- Server Push
服务器的推送,服务器不再被动的接收到浏览器的request之后才返回数据,而是在有新数据时就主动推送给浏览器。
开发基于WebSocket协议的聊天室
开发环境
MyEclipse2014、JDK1.7.45 64位、Tomcat8
WebSocketConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package com.sx2.websocket;
import java.util.Set;
import javax.websocket.Endpoint; import javax.websocket.server.ServerApplicationConfig; import javax.websocket.server.ServerEndpointConfig;
public class WebSocketConfig implements ServerApplicationConfig{
@Override public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
return scan; }
@Override public Set<ServerEndpointConfig> getEndpointConfigs( Set<Class<? extends Endpoint>> arg0) { return null; }
}
|
chatSocket.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSONObject; import com.sx2.pojo.WebSocketResult;
@ServerEndpoint("/chatSocket") public class ChatSocket { private static Set<ChatSocket> sockets=new HashSet<ChatSocket>(); private static Map<String, String> photos = new HashMap<String, String>(); private static Set<String> names=new HashSet<String>(); private Session session; private String username; private String photo;
@OnOpen public void open(Session session){ this.session=session; sockets.add(this); String queryString = session.getQueryString(); String[] infos = queryString.split("&"); this.username = infos[0].substring(infos[0].indexOf("=") + 1); this.photo = infos[1].substring(infos[1].indexOf("=") + 1); WebSocketResult message = new WebSocketResult(); String encodeUsername = ""; try { if(this.username.matches("[A-Za-z]")){ encodeUsername = this.username; }else{ encodeUsername = URLDecoder.decode(this.username,"UTF-8"); } this.username = encodeUsername; names.add( encodeUsername); message.setNames(names); photos.put(encodeUsername, photo); message.setPhotos(photos); message.setWelCome(encodeUsername+"进入聊天室!!"); broadcast(sockets, JSONObject.toJSONString(message)); } catch (UnsupportedEncodingException e1) { message.setWelCome("服务器异常!"); broadcast(sockets, JSONObject.toJSONString(message)); } } @SuppressWarnings("deprecation")
@OnMessage public void receive(Session session,String msg ){ WebSocketResult message=new WebSocketResult(); message.setSendMsg(msg); message.setFrom(this.username); message.setDate(new Date().toLocaleString()); message.setPhotos(photos); broadcast(sockets, JSONObject.toJSONString(message)); }
@OnClose public void close(Session session){ sockets.remove(this); names.remove(this.username); photos.remove(this.username); WebSocketResult message=new WebSocketResult(); message.setWelCome(this.username+"退出聊天室!!"); message.setNames(names); message.setPhotos(photos); broadcast(sockets, JSONObject.toJSONString(message)); }
public void broadcast(Set<ChatSocket> ss ,String msg ){ for (Iterator<ChatSocket> iterator = ss.iterator(); iterator.hasNext();) { ChatSocket chatSocket = (ChatSocket) iterator.next(); try { chatSocket.session.getBasicRemote().sendText(msg); } catch (IOException e) { e.printStackTrace(); } } } }
|
WebSocketResult.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import java.util.Map; import java.util.Set;
public class WebSocketResult {
private String sendMsg; private String date; private String from; private String welCome; private Set<String> names;
private Map<String, String> photos; public String getWelCome() { return welCome; }
public void setWelCome(String welCome) { this.welCome = welCome; }
public String getSendMsg() { return sendMsg; }
public void setSendMsg(String sendMsg) { this.sendMsg = sendMsg; }
public String getDate() { return date; }
public void setDate(String date) { this.date = date; }
public String getFrom() { return from; }
public void setFrom(String from) { this.from = from; }
public Set<String> getNames() { return names; }
public void setNames(Set<String> names) { this.names = names; }
public Map<String, String> getPhotos() { return photos; }
public void setPhotos(Map<String, String> photos) { this.photos = photos; } }
|
客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| <?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Apache Tomcat WebSocket Examples: Chat</title> <style type="text/css"> input#chat { width: 410px }
#console-container { width: 400px; }
#console { border: 1px solid #CCCCCC; border-right-color: #999999; border-bottom-color: #999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } #userlist { border: 1px solid #CCCCCC; border-right-color: #999999; border-bottom-color: #999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } p { padding: 0; margin: 0; } </style> <script type="application/javascript"> //这里的target就是websocket服务的路径 //对应于@ServerEndpoint("/chatSocket") var target = "ws://localhost:8080/SX2/chatSocket?username="+ username +"&photo=<%=path%>/image/user/b3.png"; window.onload = function() { //进入聊天页面,就打开socket通道; if ('WebSocket' in window) { ws = new WebSocket(target); } else if ('MozWebSocket' in window) { ws = new MozWebSocket(target); } else { alert("WebSocket is not supported by this browser!"); return; } //当服务端向浏览器发送消息时会执行此函数 ws.onmessage = function(event) { eval("var msg=" + event.data); if(undefined != msg.welCome){ $('#console').append("msg.welCome"); } if(undefined != msg.sendMsg){ $('#console').append(msg.sendMsg); } if(undefined != msg.names){ $('#userlist').html(""); $(msg.names).each(function(){ $('#userlist').append(this); }); } }; }; //发送消息 function sendMsg() { var msg = $('#chat').val(); if(msg == "" || msg == null) return; ws.send(msg); $('#chat').val(""); } document.getElementById('chat').onkeydown = function(event) { if (event.keyCode == 13) { sendMsg(); } }; </script> </head> <body> <div> <p> <input type="text" placeholder="type and press enter to chat" id="chat" /> </p> <div id="console-container"> <div id="console"/> </div> <div id="console-container"> <div id="userlist"/> </div> </div> </body> </html>
|