webSocket+Stomp+SockJS+rabbitmq推送原理和使用

一、websocket与http

http是基于短连接的,无法实现长连接,无法实现双工通信。
websocket是基于长连接的,可以双工通信。

这两个协议都属于应用层,都是基于tcp传输层协议实现的。
websocket第一次连接的时候,是发送的http请求,请求成功后,
升级为socket连接。

第一次请求头会带着两个参数,告诉服务器,协议要升级。
服务端确认并返回后,就升级(与http无关了)
Upgrade: websocket
Connection: Upgrade

二、Websocket的作用

1、long poll 和 ajax轮询 的原理。

ajax轮询就是客户端不断的发送请求
long poll也是客户端发送请求,只不过是阻塞的,没有数据就不返回,有了再返回。

缺点:

1、不能双工通信,服务端不能主动给客户端发送信息
2、耗费资源
3、消息推送有延迟,因为轮询是有间隔的。

2、websocket:

服务端就可以主动推送信息给客户端
只需要经过一次HTTP请求,就可以做到源源不断的信息传送了,避免了HTTP的非状态性。
无延迟,持久连接

3、WebSocket 如何工作?

(1)、原生H5加javax.websocket方式:

前端代码:

var Socket = new WebSocket(url, [protocol] );

然后基于事件,写回调函数:

// 初始化一个 WebSocket 对象
var ws = new WebSocket('ws://localhost:9998/echo');

// 建立 web socket 连接成功触发事件
ws.onopen = function() {
		// 使用 send() 方法发送数据
		ws.send('发送数据');
};
// 接收服务端数据时触发事件
ws.onmessage = function(evt) {
		var received_msg = evt.data;
};
// 断开 web socket 连接成功触发事件
ws.onclose = function() {
};

后端代码:

声明一个处理类,写事件回调函数。
@ServerEndpoint
标记一个类是 WebSocket 的处理器

// 收到消息触发事件
@OnMessage
public void onMessage(String message, Session session){}

// 打开连接触发事件
@OnOpen
public void onOpen(Session session, EndpointConfig config, 	@PathParam("id") String id){}

// 关闭连接触发事件
@OnClose
public void onClose(Session session, CloseReason closeReason) {}

// 传输消息错误触发事件
@OnError
public void onError(Throwable error) {}

(2)、SockJS和Stomp+RabbitMQ的方式:

前端代码:

连接端点
var socket = new SockJS("/webServer");
//根据端点打开Stomp客户端
stompClient = Stomp.over(socket);
//客户端进行连接
stompClient.connect({}, function(frame) {
//客户端订阅消息
stompClient.subscribe(url, function(response){
}
}
// 连接消息服务器
stompClient .connect(login, password, on_connect, on_error, '/');

后台代码:

websocket配置类:

在这里插入图片描述

配置websocket端点,
配置请求路径关键字和请求前缀
配置点对点方式的前缀

发送消息到rabbit的工具类
通过simpmessagingtemplate发送消息到mq
在这里插入图片描述

发送的时候,destination 默认的模式有以下 3 种:

(1)、/exchange/<exchangeName>/[/routingKey]:
(指定交换机和路由key,就知道往哪里发了)

需要提前绑定路由key到exchange


先提前绑定路由key和交换机,然后发送的时候就根据pattern(路由key)
和<exchangeName>决定发送到哪个交换机里面的临时队列,。

(2)、/queue/<queueName>
(往默认交换机里面的指定队列发)

先在默认的交换机里面,创建名为queueName的队列,
路由key也是<queueName>,与默认交换机作绑定,发送消息就发送到这个队列。

(3)、/topic/<topicName>
(往amq.topic exchange交换机上的被topicName绑定的队列上发)

创建出临时的 queue,并根据 routingkey <topicName>绑定
到amq.topic exchange 上,同时实现对该 queue 的订阅。

总结:

rabbitmq的Stomp插件,就是在websocket和stomp之间做了一层桥接,
可以让浏览器订阅到rabbitmq里面的消息
在后端,使用simpmessagingtemplate往指定的队列发送消息
发送的路径destination有默认的格式,方便操作。

3、Stomp原理:

直接使用WebSocket(或SockJS)就很类似于使用TCP套接字来编写Web应用。
Stomp就类似于http一样,可以规定好消息协议格式。

就像HTTP在TCP套接字之上添加了请求-响应模型层一样,
STOMP在WebSocket之上提供了一个基于帧的线路格式层,用来定义消息的语义。

STOMP帧由命令、一个或多个头信息以及消息主体所组成。

>>> SEND
transaction:tx-0
destination:/app/marco
content-length:20

{"message":"Marco!"}

STOMP命令是send,表明会发送一些内容.
紧接着是三个头信息:
transaction:tx-0:表示消息的的事务机制
destination:/app/marco:表示消息要发送到哪里的目的地,
content-length:20:消息的大小

(2)、启用STOMP功能

以 /app 开头的消息都会被路由到带有@MessageMapping 
或 @SubscribeMapping 注解的方法中

以/topic 或 /queue 开头的消息都会发送到STOMP代理

以/user开头的消息会将消息重路由到某个用户独有的目的地上。

在这里插入图片描述

(3)、处理来自客户端的STOMP消息

@MessageMapping("/marco")
  @SendTo("/topic/marco")
  public Shout stompHandle(Shout shout){
      LOGGER.info("接收到消息:" + shout.getMessage());
      Shout s = new Shout();
      s.setMessage("Polo!");
      return s;
  }

@MessageMapping 指定目的地是“/app/marco”,用于客户端访问,
并且返回值会发到消息代理

@SendTo 注解重写了消息代理的目的地,
用于指定消息发送到哪里(simpmessagingtemplate)也可以实现同样的效果。

(4)、为指定用户发送消息

convertAndSendToUser

simpMessageSendingOperations.convertAndSendToUser(user.getName(), "/queue/shouts", shout);

最终会把消息发送到 /user/sername/queue/shouts

然后客户端去订阅这个路径的队列就好了。
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值