目录
websocket的理解
基于代码理解
客户端和服务端建立连接,就产生一个新的webSocket对象,所以不存在线程安全问题(Servlet是一个实例对象,多线程操作一个对象存在线程安全问题)
理论上的实现
异步,事件驱动,io模型的理论原理
从网卡拿到数据,然后系统决定数据怎么交给进程,都是io的操作,由io的模型来决定如何交付数据
websocket的实现,是基于事件驱动,异步的方式(原理叫作io多路复用)
注册一个事件后,java进程(web项目不用一直阻塞等待io数据返回)【程序该做啥就做啥,系统接收到网卡传到对应端口进程的数据,websocket某个事件发生以后,由系统调用websocket的回调函数】
我(java进程运行web项目)挂了 n 个鱼竿,都绑定铃铛(注册事件),如果有鱼上钩(事件发生),铃铛会通知我,我就再把对应鱼竿的鱼处理好(执行回调函数)
websocket协议的原理
建立连接基于http协议,(包含升级协议字段)
传输数据:基于传输层tcp,应用层websocket协议,长连接,双方都保持连接状态,双方都可以收发消息
服务器接收消息的处理方式
存在问题
服务器端onMessage方法
@OnMessage
public void onMessage(Session session, String message) {
// 1.遍历保存的所有session,每个都发送消息
MessageCenter.sendMessage(message);
// 2.消息还要保存在数据库,
// (1)反序列化json字符串为message对象
Message msg = Util.deserialize(message, Message.class);
// (2)message设置接收消息的时间
// msg.setSendTime(new Date());
// (3)插入数据库
int n = MessageDao.insert(msg);
System.out.println("接收到的消息:" + message);
}
具体发送消息sendMessage方法
public static void sendMessage(String message) {
try {
//遍历map的所有数据,然后转发到所有session对象中
Enumeration<Session> e = clients.elements();
while (e.hasMoreElements()) {
Session session = e.nextElement();
session.getBasicRemote().sendText(message);
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
遍历所有客户端,如果客户端数量很多,sendMessage方法长时间无法返回
|
@OnMessage注解方法无法返回(接收某个客户端消息处于长时间的处理执行上)
|
大量的接收客户端消息时,产生大量的消息堆积在服务端,服务端资源占用太多
解决方案
接收消息,发送消息的步骤,分离开(用不同的线程来处理,双方可以并发,并行的执行)
阻塞队列:用来存放消息,接收的客户端消息就放在里面(放进去时很快的)
再启动一个线程,不停的拉取队列中的消息,发送(发送和接收并发并行执行,分离)
改造方案:基于阻塞队列,将接收消息和发送消息两个操作分隔开,(异步消息处理)
目的:大量消息接收时,可以降低服务器压力,达到消峰的目的
处理消息的仓库messageCenter
把该类升级为单例模式(懒汉模式)
package org