WebSocket介绍
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
协议有两部分,握手和数据传输。
握手是基于http协议的
来自客户端的握手形式如下:
来自服务器的握手形式如下:
字段说明:
客户端实现
websocket对象
实现 WebSockets 的 Web 通过WebSocket 对象公开所有的必需的客户端功能。
以下 API 用于创建 WebSocket 对象:
var ws = new WebSocket(url);
//参数url格式说明: ws://ip地址端口号/资源名称
websocket方法
引入POM依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
WebSocket入口配置
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
/**
* 注册handle
* @see org.springframework.web.socket.config.annotation.WebSocketConfigurer#registerWebSocketHandlers(org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry)
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/testHandler.do").addInterceptors(new WebSocketInterceptor());
registry.addHandler(myHandler(), "/socketJs/testHandler.do").addInterceptors(new WebSocketInterceptor()).withSockJS();
}
@Bean
public WebSocketHandler myHandler(){
return new MyMessageHandler();
}
}
- 实现WebSocketConfigurer接口,重写registerWebSocketHandlers方法,这是一个核心实现方法,配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。
- registry.addHandler注册和路由的功能,当客户端发起websocket连接,把/path交给对应的handler处理,而不实现具体的业务逻辑,可以理解为收集和任务分发中心。
- addInterceptors,是为handler添加拦截器,可以在调用handler前后加入我们自己的逻辑代码。
创建拦截器
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
// 获取参数
String userId = serverHttpRequest.getServletRequest().getParameter(
"userId");
attributes.put("currentUser", userId);
}
return true;
}
// 初次握手访问后
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception e) {
}
}
beforeHandshake,在调用handler前处理方法。常用在登录用户信息,绑定WebSocketSession,在handler里根据用户信息获取WebSocketSession发送消息。
Handler处理类
public class MyMessageHandler implements WebSocketHandler {
/**
* userMap:使用线程安全map存储用户连接webscoket信息
*
* @since JDK 1.7
*/
private final static Map<String, WebSocketSession> userMap = new new ConcurrentHashMap<String, WebSocketSession>();
/**
* 关闭websocket时调用该方法
*
* @see org.springframework.web.socket.WebSocketHandler#afterConnectionClosed(org.springframework.web.socket.WebSocketSession,
* org.springframework.web.socket.CloseStatus)
*/
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus status) throws Exception {
String userId = this.getUserId(session);
if (StringUtils.isNoneBlank(userId)) {
userMap.remove(userId);
System.err.println("该" + userId + "用户已成功关闭");
} else {
System.err.println("关闭时,获取用户id为空");
}
}
/**
* 建立websocket连接时调用该方法
*
* org.springframework.web.socket.WebSocketHandler#afterConnectionEstablished(org.springframework.web.socket.WebSocketSession)
*/
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
String userId = this.getUserId(session);
if (StringUtils.isNoneBlank(userId)) {
userMap.put(userId, session);
session.sendMessage(new TextMessage("建立服务端连接成功!"));
}
}
/**
* 客户端调用websocket.send时候,会调用该方法,进行数据通信
*
* org.springframework.web.socket.WebSocketHandler#handleMessage(org.springframework.web.socket.WebSocketSession,
* org.springframework.web.socket.WebSocketMessage)
*/
@Override
public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message) throws Exception {
}
/**
* 传输过程出现异常时,调用该方法
*
* org.springframework.web.socket.WebSocketHandler#handleTransportError(org.springframework.web.socket.WebSocketSession,
* java.lang.Throwable)
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable e)
throws Exception {
WebSocketMessage<String> message = new TextMessage("异常信息:"
+ e.getMessage());
session.sendMessage(message);
}
/**
*
* org.springframework.web.socket.WebSocketHandler#supportsPartialMessages()
*/
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* sendMessageToUser:发给指定用户
*
*/
public void sendMessageToUser(String userId, String contents) {
WebSocketSession session = userMap.get(userId);
if (session != null && session.isOpen()) {
try {
TextMessage message = new TextMessage(contents);
session.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* sendMessageToAllUsers:发给所有的用户
*
*/
public void sendMessageToAllUsers(String contents) {
Set<String> userIds = userMap.keySet();
for (String userId : userIds) {
this.sendMessageToUser(userId, contents);
}
}
/**
* getUserId:获取用户id
*
* @author liuchao
* @param session
* @return
* @since JDK 1.7
*/
private String getUserId(WebSocketSession session) {
try {
String userId = (String) session.getAttributes().get("currentUser");
return userId;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
客户端连接
<script type="text/javascript">
$(function(){
var host= window.location.host;
var websocket;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://"+host+"/testHandler.do?userId=9528");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://"+host+"/testHandler.do?userId=9528");
} else {
websocket = new SockJS("http://"+host+"/socketJs/testHandler.do?userId=9528");
}
websocket.onopen = function (evnt) {
console.log("链接服务器成功!")
};
websocket.onmessage = function (evnt) {
console.log(evnt.data);
$("#message").html(evnt.data);
};
websocket.onerror = function (evnt) {
console.log("websocket错误");
};
websocket.onclose = function (evnt) {
console.log("与服务器断开了链接!")
}
$('#send').bind('click', function() {
send();
});
function send(){
if (websocket != null) {
var message = document.getElementById('message').value;
websocket.send(message);
} else {
alert('未与服务器链接.');
}
}
});
</script>
转载:https://blog.csdn.net/fffvdgjvbsfkb123456/article/details/116465394
查看评论