释义:
WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
为什么需要 WebSocket:
了解计算机网络协议的人,应该都知道:HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步JavaScript和XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。
因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高
利用javax.websocket实现websocket的案例如下:
消息发送端:
String pushMsg = JSON.toJSONString(msgVo,SerializerFeature.DisableCircularReferenceDetect);
String url = ws://192.168.11.215:8082/websocket/weionwall/"+barId+"/false";
//推送消息
WebSocketClientThread clientThread = new WebSocketClientThread(url,pushMsg);
Thread thread = new Thread(clientThread);
thread.start();
WebSocketClientThread类:
/**
* websocket客户端
*
*/
public class WebSocketClientThread implements Runnable {
private static final Log logger = LogFactory.getLog(WebSocketClientThread.class);
private String url;
private String msg;
public WebSocketClientThread(String url, String msg) {
super();
this.url = url;
this.msg = msg;
}
public void run() {
sendMsg(1);
}
public void sendMsg(int i){
i++;
try {
MyWebSocketClient client = new MyWebSocketClient(new URI(url), msg);
client.connect();
} catch (Exception e) {
logger.error(e.fillInStackTrace());
e.printStackTrace();
if(i<=10){
sendMsg(i);
}
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
MyWebSocketClient类:
package com.dflm.weixin.util;
import java.net.URI;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.framing.Framedata;
import org.java_websocket.handshake.ServerHandshake;
public class MyWebSocketClient extends WebSocketClient {
private static final Log logger = LogFactory.getLog(MyWebSocketClient.class);
private String msg;
public MyWebSocketClient(URI serverUri, Draft draft, String msg) {
super(serverUri, draft);
this.msg = msg;
}
public MyWebSocketClient(URI serverURI, String msg) {
super(serverURI);
this.msg = msg;
}
@Override
public void onOpen(ServerHandshake handshakedata) {
this.send(msg);
}
@Override
public void onMessage(String message) {
this.close();
}
@Override
public void onFragment(Framedata fragment) {
}
@Override
public void onClose(int code, String reason, boolean remote) {
if(!remote){
logger.info("MyWebSocketClient closed by " + ( remote ? "remote peer" : "us" ));
}
}
@Override
public void onError(Exception ex) {
ex.printStackTrace();
}
}
WeionwallWebSocket类:
/**
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint("/websocket/weionwall/{bid}/{isAdmin}")
public class WeionwallWebSocket{
/**
* 连接建立成功调用的方法
*
* @param session
* 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "bid") String bid,
@PathParam(value = "isAdmin") Boolean isAdmin) {
if(isAdmin == null){
isAdmin = false;
}
if(StringUtil.isNotBlank(bid)&&isAdmin){
SessionUtil.putOnwallAdminSession(bid, session);
}
if(StringUtil.isNotBlank(bid)&&!isAdmin){
SessionUtil.putOnwallUserSession(bid, session);
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam(value = "bid") String bid,
@PathParam(value = "isAdmin") Boolean isAdmin,Session session) {
if(isAdmin == null){
isAdmin = false;
}
if(StringUtil.isNotBlank(bid)&&isAdmin){
SessionUtil.removeOnwallAdminSession(bid, session);
}
if(StringUtil.isNotBlank(bid)&&!isAdmin){
SessionUtil.removeOnwallUserSession(bid, session);
}
}
/**
* 收到客户端消息后调用的方法
*
* @param message
* 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message,@PathParam(value="bid") String bid) {
if(StringUtil.isNotEmpty(message)){
JSONObject object = JSONObject.parseObject(message);
Boolean isCheck = object.getBoolean("isCheck");
if(isCheck == null){
isCheck = false;
}
if(isCheck){
if(SessionUtil.onWallAdminSessionMap!=null&&!SessionUtil.onWallAdminSessionMap.isEmpty()){
Set<Session> set = SessionUtil.onWallAdminSessionMap.get(bid);
if(set!=null&&!set.isEmpty()){
for(Session session : set){
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}else{
if(SessionUtil.onWallUserSessionMap!=null&&!SessionUtil.onWallUserSessionMap.isEmpty()){
if(message.contains("type\":\"redBag")){
String cashRedType = null;
JSONArray array = (JSONArray) object.get("normal");
JSONArray barIdList = (JSONArray)object.get("barIdList");
if(array!=null && array.size()>0)
{
JSONObject obj = (JSONObject) array.get(0);
cashRedType = obj.getString("cashRedType");
}
if(StringUtil.isNotBlank(cashRedType))
{
if("2".equals(cashRedType))
{
Set<String> bidSet = SessionUtil.onWallUserSessionMap.keySet();
for (String barid : bidSet) {
if(barIdList!=null && barIdList.contains(barid)) {
Set<Session> set = SessionUtil.onWallUserSessionMap.get(barid);
if(set!=null&&!set.isEmpty()){
for(Session session : set){
try {
synchronized (session){
session.getAsyncRemote().sendText(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}else {
Set<Session> set = SessionUtil.onWallUserSessionMap.get(bid);
if(set!=null&&!set.isEmpty()){
for(Session session : set){
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}else {
Set<Session> set = SessionUtil.onWallUserSessionMap.get(bid);
if(set!=null&&!set.isEmpty()){
for(Session session : set){
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}else
{
Set<Session> set = SessionUtil.onWallUserSessionMap.get(bid);
if(set!=null&&!set.isEmpty()){
for(Session session : set){
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error,@PathParam(value = "bid") String bid,
@PathParam(value = "isAdmin") Boolean isAdmin) {
if(isAdmin == null){
isAdmin = false;
}
if(StringUtil.isNotBlank(bid)&&isAdmin){
SessionUtil.removeOnwallAdminSession(bid, session);
}
if(StringUtil.isNotBlank(bid)&&!isAdmin){
SessionUtil.removeOnwallUserSession(bid, session);
}
}
}