WebSocke是 HTML5 提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket协议是基于TCP的一种新的网络协议,是一个应用层协议,是TCP/IP协议的子集。

它实现了浏览器与服务器全双工(full-duplex)通信,客户端和服务器都可以向对方主动发送和接收数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在JS中创建WebSocket后,会有一个HTTP请求从浏览器发向服务器。在取得服务器响应后,建立的连接会使用HTTP升级将HTTP协议转换为WebSocket协议。也就是说,使用标准的HTTP协议无法实现WebSocket,只有支持那些协议的专门浏览器才能正常工作。由于WebScoket使用了自定义协议,所以URL与HTTP协议略有不同。未加密的连接为ws://,而不是http://。加密的连接为wss://,而不是https://。

用途:

实时Web应用的解决方案,实现Web的实时通信。

说的再直白点, html的消息推送 。

假如你有一个页面,数据不定期更改,通常的做法就是 Ajax轮询,轮询是指在特定的时间间隔(如每一秒),由浏览器对服务器发起HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。

由于HTTP协议是惰性的,只有客户端发起请求,服务器才会返回数据。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。。而WebSocket属于服务端推送技术,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

当有了web socket,数据变动时 让服务器通知客户端,启不是很美妙?

请求示例:

(1) 默认端口是80和443(ssl)。

(2) 协议标识符是ws和wss(ssl)。

(3) 请求报文示例

General
--------------------------------------------
Request URL:ws://localhost:8080/j2ee-websocket/websocket/1
Request Method:GET
Status Code: Switching Protocols
---------------------------------------------
Response Headers
---------------------------------------------
Connection:upgrade
Date:Tue, Dec :: GMT
Sec-WebSocket-Accept:cRxT/XcOpnsleDb1KdydWXOw+us=
Sec-WebSocket-Extensions:permessage-deflate;client_max_window_bits=
Server:Apache-Coyote/1.1
Upgrade:websocket

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

客户端JavaScript代码:

<script type="text/javascript">
var websocket = null;
var principal = '';
var socketURL = 'ws://' + window.location.host
+ '/j2ee-websocket/websocket/' + principal;
//判断当前浏览器是否支持WebSocket,若支持创建一个websocket对象。
if('WebSocket' in window){
websocket = new WebSocket(socketURL);
}
else{
alert('Not support websocket');
} //连接发生错误的回调方法
websocket.onerror = function(event){
alert("error");
}; //连接成功建立的回调方法
websocket.onopen = function(){
alert("open");
} //接收到消息的回调方法
websocket.onmessage = function(event){
alert('recive : ' + event.data);
} //连接关闭的回调方法
websocket.onclose = function(event){
alert("close");
} //发送消息
function send(message){
websocket.send(message);
}
</script>

WebSocket 对象的属性:

var Socket = new WebSocket(socketURL)
Socket.readyState

只读属性readyState表示连接状态,可以是以下值:

  • 0 - 表示连接尚未建立。

  • 1 - 表示连接已建立,可以进行通信。

  • 2 - 表示连接正在进行关闭。

  • 3 - 表示连接已经关闭或者连接不能打开。

websocket事件:

事件              事件处理程序                 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

websocket对象的方法

方法                       描述
Socket.send() 使用连接发送数据
Socket.close() 关闭连接

推荐:google/jquery-websocket代码 (http://code.google.com/p/jquery-websocket)

google/jquery-websocket增加了消息的类型,将消息拆分为{"type":"","message":""}。

这样更灵活,可以根据业务类型,定义type,如:通知,公告,广播,发文等...

<script type="text/javascript">
var principal = '';
var socketURL = 'ws://' + window.location.host
+ '/j2ee-websocket/websocket/' + principal; websocket = $.websocket(socketURL, {
open : function() {
// when the socket opens
alert("open");
},
close : function() {
// when the socket closes
alert("close");
},
//收到服务端推送的消息处理
events : {
'radio' : function(event) {
console.info($.parseJSON(event.data));
},
'notice' : function(event) {
console.info($.parseJSON(event.data));
},
//... more custom type of message
}
}); //发送消息
function send() {
websocket.send('radio', " hello,this msg from client request");
}
</script>

AJAX轮询和Websockets:

SockJS是一个浏览器JavaScript库,它提供了一个连贯的、跨浏览器的Javascript API,在浏览器和web服务器之间建立一个低延迟、全双工、跨域通信通道。SockJs的一大好处是提供了浏览器兼容性,优先使用原生的WebSocket,在不支持websocket的浏览器中,会自动降为轮询的方式。

<script src="//cdn.jsdelivr.net/sockjs/1.0.0/sockjs.min.js"></script>

var sock = new SockJS('/coordination');
sock.onopen = function() {
console.log('open');
};
sock.onmessage = function(e) {
console.log('message', e.data);
};
sock.onclose = function() {
console.log('close');
};
sock.send('test');
sock.close();

以下内容转载自(https://segmentfault.com/a/1190000006617344?utm_source=tag-newest

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。

stomp帧(Frame)格式如下:

属性。                类型                         描述
command String name of the frame("CONNECT",'SEND',etc.)
headers JavaScript object
body String

command和headers属性始终会被定义,当这个frame没有头部时,headers可以为空。若这个frame没有body, body的值可以为null。

创建stomp客户端:

1、在web浏览器中使用普通的Web Socket

stomp javascript客户端会使用ws://的URL与stomp服务端进行交互。为了创建一个stomp客户端js对象,需要使用Stomp.client(url), 而这个URL连接着服务端的WebSocket的代理:

var url = "ws://localhost:61614/stomp";
var client = Stomp.client(url);

Stomp.client(url, protocols)也可以用来覆盖默认的subprotocols, 第二个参数可以是一个字符串或一个字符串数组指定的多个subprotocols。

2、在web浏览器中使用定制的WebSocket

浏览器提供了不同的websocket协议,一些老的浏览器不支持WebSocket的脚本或者使用别的名字。默认下,stomp.js会使用浏览器原生的WebSocket class去创建WebSocket。利用Stomp.over(ws)这个方法可以使用其他类型的WebSockets.

<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
// use SockJS implementation instead of the browser's native implementation
var ws = new SockJS(url);
var client = Stomp.over(ws);
[...]
</script>

连接服务器:

一旦Stomp客户端建立了,必须调用它的connect()方法去连接,从而Stomp服务端进行验证。这个方法需要两个参数,用户的登录和密码凭证。这种情况下,客户端会使用Websocket打开连接,并发送一个CONNECT frame。这个连接是异步进行的,你不能保证当这个方法返回时是有效连接的,为了知道连接的结果,需要一个回调函数。

var connect_callback = function(){
// called back after the client is connected and authenticated to the STOMP server
}

如果连接失败connect()方法接受一个可选的参数(error_callback),当客户端不能连接上服务端时,这个回调函数error_callback会被调用,该函数的参数为对应的错误对象。

var error_callback = function(error) {
// display the error's message header:
alert(error.headers.message);
};

在大多数情况下,connect()方法可接受不同数量的参数来提供简单的API:

client.connect(login, passcode, connectCallback);
client.connect(login, passcode, connectCallback, errorCallback);
client.connect(login, passcode, connectCallback, errorCallback, host);

如果你需要附加一个headers头部,connect方法还可以接受其他两种形式的参数:

client.connect(headers, connectCallback);
client.connect(headers, connectCallback, errorCallback);

header是map形式,需要自行在headers添加login, passcode(甚至host):

var headers = {
login: 'my login',
passcode: 'my passcode',
// additional header
'client-id': 'my-client-id'
}
client.connect(headers, connectCallback);

断开连接时,调用disconnect方法,这个方法也是异步的,当断开成功后会接受一个额外的回调函数的参数:

client.disconnect(function(){
alert('See you next time!');
});

当客户端与服务器断开连接,就不会再发送或接收消息了。

客户端和服务器连接过程中会每隔固定时间发送heart-beats, heat-beating也就是频率,incoming时接收频率,outgoing是发送频率。通过改变incoming和outgoing可以更改客户端的heart-beating(默认为10000ms

client.heartbeat.outgoing = ;    // client will send heartbeats every 20000ms
client.heartbeat.incoming = ; // client does not want to receive heartbeats from the server

heart-beating 是利用window.setInterval()去规律地发送heat-beats或者检查服务端的heart-beats.

发送消息

当客户端与服务端连接成功后,可以调用send()来发送STOMP消息。这个方法必须有一个参数,用来描述对应的STOMP的目的地。另两个可选的参数:headers(object类型包含额外的信息头部)和body(一个String类型的参数)

client.send("queue/test", {priority:}, "Hello, STOMP");

如果你想发送一个有body的信息,也必须传递headers参数。如果没有headers需要传递,那么就传递{}即可,如下所示:

client.send(destination, {}, body);

订阅(Subscribe)和接收(receive)消息

为了在浏览器中接收消息,STOMP客户端必须先订阅一个目的地destination。你可以使用subscribe()去订阅。这个方法有2个必需的参数:目的地(destination),回调函数(callback);还有一个可选的参数headers。其中destination是String类型,对应目的地,回调函数是伴随着一个参数的function类型。

var subscription = client.subscribe("/queue/test/", callback);

subscribe()方法返回一个object,这个object包含一个id属性,对应这个这个客户端的订阅ID。而unsubscribe()可以用来取消客户端对这个目的地destination的订阅。

默认情况下,如果没有在headers额外添加,这个库会默认构建一个独一无二的ID。在传递headers这个参数时,可以使用你自己的ID:

var mysubid = '...';
var subscription = client.subscribe(destination, callback, { id: mysubid });

这个客户端会向服务端发送一个STOMP订阅帧(SUBSCRIBE frame)并注册回调事件。每次服务端向客户端发送消息时,客户端都会轮流调用回调函数,参数为对应消息的STOMP帧对象(Frame object)。如下所示:

callback = function(message) {
// called when the client receives a STOMP message from the server
if (message.body) {
alert("got message with body " + message.body)
} else {
alert("got empty message");
}
});

subscribe()方法,接受一个可选的headers参数用来标识附加的头部。

var headers = {ack: 'client', 'selector': "location = 'Europe'"};
client.subscribe("/queue/test", message_callback, headers);

这个客户端指定了它会确认接收的信息,只接收符合这个selector : location = 'Europe'的消息。

如果想让客户端订阅多个目的地,你可以在接收所有信息的时候调用相同的回调函数:

onmessage = function(message) {
// called every time the client receives a message
}
var sub1 = client.subscribe("queue/test", onmessage);
var sub2 = client.subscribe("queue/another", onmessage)

如果要中止接收消息,客户端可以在subscribe()返回的object对象调用unsubscribe()来结束接收。

var subscription = client.subscribe(...);

...

subscription.unsubscribe();

支持JSON

STOMP消息的body必须为字符串。如果你需要发送/接收JSON对象,你可以使用JSON.stringify()JSON.parse()去转换JSON对象。

var quote = {symbol: 'APPL', value: 195.46};
client.send("/topic/stocks", {}, JSON.stringify(quote)); client.subcribe("/topic/stocks", function(message) {
var quote = JSON.parse(message.body);
alert(quote.symbol + " is at " + quote.value);
};

Acknowledgment(确认)

默认情况,在消息发送给客户端之前,服务端会自动确认(acknowledged)。

客户端可以选择通过订阅一个目的地时设置一个ack headerclientclient-individual来处理消息确认。

在下面这个例子,客户端必须调用message.ack()来通知服务端它已经接收了消息。

var subscription = client.subscribe("/queue/test",
function(message) {
// do something with the message
...
// and acknowledge it
message.ack();
},
{ack: 'client'}
);

ack()接受headers参数用来附加确认消息。例如,将消息作为事务(transaction)的一部分,当要求接收消息时其实代理(broker)已经将ACK STOMP frame处理了。

var tx = client.begin();
message.ack({ transaction: tx.id, receipt: 'my-receipt' });
tx.commit();

nack()也可以用来通知STOMP 1.1.brokers(代理):客户端不能消费这个消息。与ack()方法的参数相同。

事务(Transactions)

可以在将消息的发送和确认接收放在一个事务中。

客户端调用自身的begin()方法就可以开始启动事务了,begin()有一个可选的参数transaction,一个唯一的可标识事务的字符串。如果没有传递这个参数,那么库会自动构建一个。

这个方法会返回一个object。这个对象有一个id属性对应这个事务的ID,还有两个方法:
commit()提交事务
abort()中止事务

在一个事务中,客户端可以在发送/接受消息时指定transaction id来设置transaction。

// start the transaction
var tx = client.begin();
// send the message in a transaction
client.send("/queue/test", {transaction: tx.id}, "message in a transaction");
// commit the transaction to effectively send the message
tx.commit();

如果你在调用send()方法发送消息的时候忘记添加transction header,那么这不会称为事务的一部分,这个消息会直接发送,不会等到事务完成后才发送。

var txid = "unique_transaction_identifier";
// start the transaction
var tx = client.begin();
// oops! send the message outside the transaction
client.send("/queue/test", {}, "I thought I was in a transaction!");
tx.abort(); // Too late! the message has been sent

WebSocket消息推送的更多相关文章

  1. node.js Websocket消息推送---GoEasy

    Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送 速度快,代码简单易懂上手快 浏览器兼容性:GoEasy推送 支持websocket ...

  2. C(++) Websocket消息推送---GoEasy

    Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送 速度快,代码简单易懂上手快 浏览器兼容性:GoEasy推送 支持websocket ...

  3. 【WebSocket】WebSocket消息推送

    准备使用WebSocket实现Java与Vue或者安卓间的实时通信,实现私密聊天.群聊.查询下资料备用. WebSocket客户端 websocket允许通过JavaScript建立与远程服务器的连接 ...

  4. websocket消息推送实现

    一.服务层 package com.demo.websocket; import java.io.IOException; import java.util.Iterator; import java ...

  5. spring boot下WebSocket消息推送(转)

    原文地址:https://www.cnblogs.com/betterboyz/p/8669879.html WebSocket协议 WebSocket是一种在单个TCP连接上进行全双工通讯的协议.W ...

  6. spring+rabbitmq+stomp搭建websocket消息推送(非spring boot方式)

    前言: 两年前做过spring+activemq+stomp的ws推送,那个做起来很简单,但现在公司用的mq中间件是rabbitmq,因此需要通过rabbitmq去做ws通信.仔细搜了搜百度/谷歌,网 ...

  7. spring boot下WebSocket消息推送

    WebSocket协议 WebSocket是一种在单个TCP连接上进行全双工通讯的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范.WebSo ...

  8. swoole WebSocket 消息推送

    server.php <?php //连接本地的 Redis 服务 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $r ...

  9. WebSocket消息推送(实现进行聊天)和WebSocket简介

    WebSocket简介 WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术.依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信.特点:事件驱动异步使用ws或者 ...

随机推荐

  1. [转]OData and Authentication – Part 6 – Custom Basic Authentication

    本文转自:https://blogs.msdn.microsoft.com/astoriateam/2010/07/21/odata-and-authentication-part-6-custom- ...

  2. SVG 旋转图形实例

    本实例展示如何在SVG中画出一个正方形并使之旋转.运行结果如下图所示: 在文本框中输入时间间隔,单位是毫秒.点击Start按钮,蓝色方块就会开始转动,每个时间间隔变化一度.变换的角度在下面的Angle ...

  3. [linux] C语言Linux系统编程进程基本概念

    1.如果说文件是unix系统最重要的抽象概念,那么进程仅次于文件.进程是执行中的目标代码:活动的.生存的.运行的程序. 除了目标代码进程还包含数据.资源.状态以及虚拟化的计算机. 2.进程体系: 每一 ...

  4. 三:SpringCloud-Ribbon

    六:Ribbon负载均衡 1. 概述 1.1 是什么 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套==客户端 负载均衡==的工具. 简单的说,Ribbon是Net ...

  5. Jenkins-在节点上执行copy命令,将节点机上的文件拷贝到映射的网络驱动盘中报错,访问被拒绝 找不到指定驱动器

    问题如标题,根据网友提供的解决方法,完美解决: 在jenkins中执行这个命令时报错 说无法访问. 重新映射一次可解决这个问题,添加一条 net use 命令

  6. 1..net mvc的原理概述

    请求过来,根据ip和端口,由iis服务器进行接收,如果是静态文件则直接返回文件内容,如果无法解析,则根据映射规则找到对应请求后缀 的ASPNET_ISAPI.dll处理程序集,交由其进行处理. 1.此 ...

  7. Struts2 (三) — OGNL与值栈

    一.OGNL表达式 1.概述 1.1什么是OGNL ​ OGNL是Object-Graph Navigation Language的缩写,俗称对象图导航语言. 它是一种功能强大的表达式语言,通过它简单 ...

  8. ES6学习笔记(六)-数组扩展

  9. 普通平衡树Tyvj1728、luogu P3369 (splay)

    存个模板,这次是splay的: 题目见这个题解: <--(鼠标移到这儿) 代码如下: #include<cstdio> #define INF 2147483647 using na ...

  10. Ueditor更改编辑框样式

    1.在ueditor.all.min.js文件中查找“ueditor.css”,找到位置后更改css文件,或在原文件中更改