Java的WebSocket实现
一、WebSocket的简单实现
随着互联网的发展,传统的http协议已经很难满足web应用日益复杂的需求了,近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,拓展了浏览器与服务端的通信功能,使服务端也能够主动的向客户端发送数据
轮询是最原始的实时的Web应用的解决方案,轮询技术要求客户端以设定的时间间隔周期性的向服务端发送请求,频繁的查询是否有新的数据改动,明显的这种方法会导致过多不必要的请求。浪费流量和服务器资源
Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求,他会为某些数据设定过期的时间,当数据过期之后才会向服务端发送请求,这种机制适合数据的改动不是特别频繁的情况,流技术通常是指客户端使用一个隐藏得窗口与服务器端建立一个http长连接,服务端会不断更新连接状态以保持http长连接存活,这样的话,服务器端就可以通过这条长连接主动将数据发送给客户端,流技术在大并发环境下,可能会考验到服务端的性能
这两种技术都是基于请求 – 应答模式,都不算真正意义上的实时技术,它们的每一次请求,应答都浪费了一定流量在相同的头部信息上,并且开发复杂度也比较大。
伴随着HTML5推出的websocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力,WebSocket的工作流程是这样的
1. 浏览器通过JavaScript 向服务器端发出建立WebScoket连接的请求,连接建立成功之后
2. 客户端和服务端就可以通过TCP连接传输数据因为WebSocket连接本质时TCP,所以不需要每次传输都带上重复的头部数据,所以数据传输比轮询和Comet技术小了很多 。
二、WebSocket实例
2.1 新建JavaWeb测试项目
在POM.xml中添加jar包依赖
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> <scope>provided</scope> </dependency>
客户端(Web)代码HTML部分
1.HTML部分
<button id="connBtn">连接</button> <input type="text" id="msg"> <button id="sendBtn" onclick="send()">发送</button> <button id="closeBtn" onclick="closeWebsocket()">关闭</button> <div id="message"> </div>
2.Javascript 部分
JavaWeb后端代码
package com.gss.socket;
import com.sun.istack.internal.logging.Logger;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint(value = “/websocket”)
public class WebSocketTest {
private static Logger logger = Logger.getLogger(WebSocketTest.class); //线程安全的静态变量,表示在线连接数 private static volatile int onlineCount = 0; //用来存放每个客户端对应的WebSocketTest对象,适用于同时与多个客户端通信 public static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>(); //若要实现服务端与指定客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 public static ConcurrentHashMap<Session, Object> webSocketMap = new ConcurrentHashMap<Session, Object>(); //与某个客户端的连接会话,通过它实现定向推送(只推送给某个用户) private Session session; /** * 建立连接成功调用的方法 */ @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); // 添加到set中 webSocketMap.put(session,this); // 添加到map中 addOnlineCount(); // 添加在线人数 System.out.println("新人加入,当前在线人数为:" + getOnlineCount()); } /** * 关闭连接调用的方法 */ public void onClose(Session closeSession){ webSocketMap.remove(session); webSocketSet.remove(this); subOnlineCount(); System.out.println("有人离开,当前在线人数为:" + getOnlineCount()); } /** * 收到客户端小心调用的方法 */ @OnMessage public void onMessage(String message,Session mysession) throws Exception{ for (WebSocketTest item: webSocketSet) { item.sendAllMessage(message); } } public void sendAllMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } // 获取在线人数 public static synchronized int getOnlineCount(){ return onlineCount; } // 添加在线人+1 public static synchronized void addOnlineCount(){ onlineCount ++; } // 减少在线人-1 public static synchronized void subOnlineCount(){ onlineCount --; }
也可以看看 GoEasy文库 的其他资料.