最近项目上需要优化,原来的方法是通过http请求来获取数据,但是客户觉得速度不够快,一番思索后,决定用websocket实时传输数据。
准备知识:websocket是什么,为什么要用websocket,如何使用websocket。
WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。
WebSocket的使用,需要前端与后台配合,前端代码比较简单。
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript"type="text/javascript">
var wsUri ="ws://echo.websocket.org/";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) {
onOpen(evt)
};
websocket.onclose = function(evt) {
onClose(evt)
};
websocket.onmessage = function(evt) {
onMessage(evt)
};
websocket.onerror = function(evt) {
onError(evt)
};
}
function onOpen(evt) {
writeToScreen("CONNECTED");
doSend("WebSocket rocks");
}
function onClose(evt) {
writeToScreen("DISCONNECTED");
}
function onMessage(evt) {
writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>');
websocket.close();
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data);
}
function doSend(message) {
writeToScreen("SENT: " + message);
websocket.send(message);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<h2>WebSocket Test</h2>
<div id="output"></div>
</html>
后台可以选择的websocket的接口比较多,这里使用的是java。
package com.websocket;
//import org.java_websocket.WebSocketImpl; //main方法中使用
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
public class WebSocket extends WebSocketServer{
int j=0;
int h=0;
int e=0;
int l=0;
public WebSocket(InetSocketAddress address) {
super(address);
System.out.println("地址" + address);
}
public WebSocket(int port) throws UnknownHostException {
super(new InetSocketAddress(port));
System.out.println("端口" + port);
}
/**
* 触发连接事件
* @param conn
* @param handshake
*/
@Override
public void onOpen(org.java_websocket.WebSocket conn, ClientHandshake handshake) {
System.out.println("有人连接Socket conn:" + conn);
l++;
}
/**
* 触发关闭事件
* @param conn
* @param message
* @param reason
* @param remote
*/
@Override
public void onClose(org.java_websocket.WebSocket conn, int message, String reason, boolean remote) {
userLeave(conn);
}
/**
* 客户端发送消息到服务器是触发事件
* @param conn
* @param message
*/
@Override
public void onMessage(org.java_websocket.WebSocket conn, String message) {
if(message != null) {
//将用户加入
this.userJoin(message, conn);
}
}
/**
* 触发异常事件
* @param conn
* @param message
*/
@Override
public void onError(org.java_websocket.WebSocket conn, Exception message) {
System.out.println("Socket异常:" + message.toString());
e++;
}
public void onStart() {
}
/**
* 用户下线处理
* @param conn
*/
public void userLeave(org.java_websocket.WebSocket conn) {
String user = WebSocketPool.getUserByKey(conn);
boolean b = WebSocketPool.removeUser(conn); // 在连接池中移除连接
if (b) {
WebSocketPool.sendMessage(user); // 把当前用户从所有在线用户列表中删除
String leaveMsg = "[系统]" + user + "下线了";
WebSocketPool.sendMessage(leaveMsg); // 向在线用户发送当前用户退出的信息
}
}
public void userJoin(String user, org.java_websocket.WebSocket conn) {
WebSocketPool.sendMessage(user); // 把当前用户加入到所有在线用户列表中
String joinMsg = "[系统]" + user + "上线了!";
WebSocketPool.sendMessage(joinMsg); // 向所有在线用户推送当前用户上线的消息
WebSocketPool.addUser(user, conn); // 向连接池添加当前的连接的对象
WebSocketPool.sendMessageToUser(conn, WebSocketPool.getOnlineUser().toString());
// 向当前连接发送当前在线用户的列表
}
public static void main(String[] args) throws InterruptedException{
// System.out.println("开始启动webSocket");
// WebSocketImpl.DEBUG = false;
// int port = 8080; // 端口随便设置,只要不跟现有端口重复就可以了
// WebSocket s =null;
// try {
// s = new WebSocket(port);
// s.start();
// } catch (UnknownHostException e1) {
// System.out.println("启动webSocket失败!");
// e1.printStackTrace();
// }
// System.out.println("启动webSocket成功!");
}
}
package com.websocket;
import java.util.*;
import org.java_websocket.WebSocket;
public class WebSocketPool {
private static final Map<WebSocket, String> userconnections = new HashMap<WebSocket, String>();
/**
* 获取用户名
* @param conn
* @return
*/
public static String getUserByKey(WebSocket conn) {
return userconnections.get(conn);
}
/**
* 获取在线总数
* @return
*/
public static int getUserCount() {
return userconnections.size();
}
/**
* 获取WebSocket
* @param user
* @return
*/
public static WebSocket getWebSocketByUser(String user) {
Set<WebSocket> keySet = userconnections.keySet();
synchronized (keySet) {
for (WebSocket conn : keySet) {
String cuser = userconnections.get(conn);
if (cuser.equals(user)) {
return conn;
}
}
}
return null;
}
/**
* 向连接池中添加连接
* @param user
* @param conn
*/
public static void addUser(String user, WebSocket conn) {
userconnections.put(conn, user); // 添加连接
}
/**
* 获取所有的在线用户
* @return
*/
public static Collection<String> getOnlineUser() {
List<String> setUsers = new ArrayList<String>();
Collection<String> setUser = userconnections.values();
for (String u: setUser) {
setUsers.add(u);
}
return setUsers;
}
/**
* 移除连接池中的连接
* @param conn
* @return
*/
public static boolean removeUser(WebSocket conn) {
if (userconnections.containsKey(conn)) {
userconnections.remove(conn); // 移除连接
return true;
} else
return false;
}
/**
* 向特定的用户发送数据
* @param conn
* @param message
*/
public static void sendMessageToUser(WebSocket conn, String message) {
if (null != conn) {
conn.send(message);
}
}
public static void sendMessage(String message) {
Set<WebSocket> keySet = userconnections.keySet();
synchronized (keySet) {
for (WebSocket conn : keySet) {
String user = userconnections.get(conn);
if (user != null) { conn.send(message);
}
}
}
}
}