最近趁着空闲时间,搭建了一套webSocket的demo,以做备用,那么我们先来简单的说一下什么是webSocket?
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
如果说刚毕业的你可能对于java socket不太理解,不用担心,webSocket还是很好理解的,需要你自己动手去敲代码,研究每一部分的作用与意义,毕竟实战是最好的老师!
首先我们新建一个maven的web工程,在webApp下建立两个jsp文件
此处贴出我们的js代码,你可以画个简单的页面去调用
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
var url = "ws://" + window.location.host +"/webSocket/webSocketOneToOne/1,123"
websocket = new WebSocket(url);
} else {
alert('当前浏览器 Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function() {
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
console.log("回调信息",event.data)
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '
';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
//message作为发送的信息,role作为发送的对象标识,socketId是此次会话的标识
websocket.send(JSON.stringify({'message':message,'role':'2','socketId':"123"}));
}
后台语言我们用的是java,编写代码前我们需要在pom.xml中引入如下依赖包
javax
javaee-api
7.0
provided
接下来我们就可以着手编写java代码了,具体的用法我都打注释了
package com.webSocket;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import net.sf.json.JSONObject;
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint(value = "/webSocketOneToOne/{param}")
public class WebSocketOneToOne {
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount;
//实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key为用户标识
private static Map connections = new ConcurrentHashMap<>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String role;
private String socketId;
/**
* 连接建立成功调用的方法
*
* @param session
* 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(@PathParam("param") String param,Session session) {
this.session = session;
String[] arr = param.split(",");
this.role = arr[0]; //用户标识
this.socketId = arr[1]; //会话标识
connections.put(role,this); //添加到map中
addOnlineCount(); // 在线数加
System.out.println("有新连接加入!新用户:"+role+",当前在线人数为" + getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
connections.remove(role); // 从map中移除
subOnlineCount(); // 在线数减
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message
* 客户端发送过来的消息
* @param session
* 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message);
JSONObject json=JSONObject.fromObject(message);
String string = null; //需要发送的信息
String to = null; //发送对象的用户标识
if(json.has("message")){
string = (String) json.get("message");
}
if(json.has("role")){
to = (String) json.get("role");
}
send(string,role,to,socketId);
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
//发送给指定角色
public static void send(String msg,String from,String to,String socketId){
try {
//to指定用户
WebSocketOneToOne con = connections.get(to);
if(con!=null){
if(socketId==con.socketId||con.socketId.equals(socketId)){
con.session.getBasicRemote().sendText(from+"说:"+msg);
}
}
//from具体用户
WebSocketOneToOne confrom = connections.get(from);
if(confrom!=null){
if(socketId==confrom.socketId||confrom.socketId.equals(socketId)){
confrom.session.getBasicRemote().sendText(from+"说:"+msg);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketOneToOne.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketOneToOne.onlineCount--;
}
}
至此,一个简单的webSocket就搭建好了,可移植性高,你可以集成到你的项目里尽情的玩耍了,也可发挥你的想象去扩展!