WebSocket总结
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebSocket总结相关的知识,希望对你有一定的参考价值。
WebSocket总结
-
基于TCP的新网络协议,实现浏览器与服务器全双工通信。
3.优点
在以前的消息推送机制中,用的都是 Ajax 轮询(polling),在特定的时间间隔由浏览器自动发出请求,将服务器的消息主动的拉回来,这种方式是非常消耗资源的,因为它本质还是http请求,而且显得非常笨拙。而WebSocket 在浏览器和服务器完成一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时向服务器发送数据。
4.WebSocket和Socket的区别
1.WebSocket:
-
- websocket通讯的建立阶段是依赖于http协议的。最初的握手阶段是http协议,握手完成后就切换到websocket协议,并完全与http协议脱离了。
- 建立通讯时,也是由客户端主动发起连接请求,服务端被动监听。
- 通讯一旦建立连接后,通讯就是“全双工”模式了。也就是说服务端和客户端都能在任何时间自由得发送数据,非常适合服务端要主动推送实时数据的业务场景。
- 交互模式不再是“请求-应答”模式,完全由开发者自行设计通讯协议。
- 通信的数据是基于“帧(frame)”的,可以传输文本数据,也可以直接传输二进制数据,效率高。当然,开发者也就要考虑封包、拆包、编号等技术细节。
2.Socket:
-
- 服务端监听通讯,被动提供服务;客户端主动向服务端发起连接请求,建立起通讯。
- 每一次交互都是:客户端主动发起请求(request),服务端被动应答(response)。
- 服务端不能主动向客户端推送数据。
- 通信的数据是基于文本格式的。二进制数据(比如图片等)要利用base64等手段转换为文本后才能传输。
SpringBoot整合WebSocket
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.开启WebSocket支持
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3.WebSocketServer 核心类
几个常用的注解:
@OnOpen
连接建立成功调用的方法
OnClose
连接关闭调用的方法
OnMessage
收到客户端消息后调用的方法
OnError
报错时调用的方法
@Component
@ServerEndpoint("/imserver/{userId}")
public class WebSocketServer {
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
addOnlineCount();
} else {
webSocketMap.put(userId, this);
addOnlineCount();
}
log.info("用户" + userId + "连接,当前在线人数为:" + getOnlineCount());
try {
sendMessage("连接成功");
} catch (IOException e) {
log.error("用户:" + userId + ",网络异常,哈哈哈");
e.printStackTrace();
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
subOnlineCount();
}
log.info("用户:" + userId + "退出成功,当前在线人数为:" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:" + userId + ",报文:" + message);
//可以群发消息
//消息保存到数据库、redis
if (StringUtils.isNotBlank(message)) {
try {
// 解析报文
JSONObject jsonObject = JSON.parseObject(message);
// 追加发送人(防止串改)
jsonObject.put("fromUserId", this.userId);
String toUserId = jsonObject.getString("toUserId");
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
}else {
log.error("请求的userId:"+toUserId+"不在该服务器上");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
error.printStackTrace();
}
}
4.前端界面
客户端主动发起一次请求建立WebSocket连接,双方进行一次握手即可实现全双工通信。
- 前端发起建立WebSocket请求,会通过WebSocketServer 的@ServerEndpoint 进行访问
若连接建立则会先会调用客户端所写的OnOpen方法
服务器收到后会调用服务器端的OnOpen方法。
- 通过服务器端的提供的接口来初始化Socket对象。
- socket对象具有send方法可以给服务器端发送消息(字符串)。
<script>
var socket;
function openSocket() {
if (typeof (WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
console.log("您的浏览器支持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
//等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
//var socketUrl="${request.contextPath}/im/"+$("#userId").val();
var socketUrl = "http://localhost:8080/imserver/" + $("#userId").val();
socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
console.log(socketUrl);
if (socket != null) {
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function () {
console.log("websocket已打开");
//socket.send("这是来自客户端的消息" + location.href + new Date());
};
//获得消息事件
socket.onmessage = function (msg) {
console.log(msg.data);
//发现消息进入 开始处理前端触发逻辑
};
//关闭事件
socket.onclose = function () {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function () {
console.log("websocket发生了错误");
}
}
}
function sendMessage() {
if (typeof (WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
console.log("您的浏览器支持WebSocket");
console.log('{"toUserId":"' + $("#toUserId").val() + '","contentText":"' + $("#contentText").val() + '"}');
socket.send('{"toUserId":"' + $("#toUserId").val() + '","contentText":"' + $("#contentText").val() + '"}');
}
}
</script>
4.WebSocket实现用户之间发送消息
- 用户指定目标用户并发送消息 将请求传给服务器
- 服务器调用OnMessage方法 然后解析内容然后给转发给目标用户
/**
* 收到客户端消息后调用的方法
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:" + userId + ",报文:" + message);
//可以群发消息
//消息保存到数据库、redis
if (StringUtils.isNotBlank(message)) {
try {
// 解析报文
JSONObject jsonObject = JSON.parseObject(message);
// 追加发送人(防止串改)
jsonObject.put("fromUserId", this.userId);
String toUserId = jsonObject.getString("toUserId");
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
}else {
log.error("请求的userId:"+toUserId+"不在该服务器上");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 实现服务器消息主动推送
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
目标用户接受到消息会调用前端的OnMessage方法。
//获得消息事件
socket.onmessage = function (msg) {
console.log(msg.data);
//发现消息进入 开始处理前端触发逻辑
};
发送客户端
接收客户端
所有 J a v a _ P r o j e c t Java\\_Project Java_Project项目Github下载地址
以上是关于WebSocket总结的主要内容,如果未能解决你的问题,请参考以下文章