使用WebSocket进行全双工通信
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用WebSocket进行全双工通信相关的知识,希望对你有一定的参考价值。
参考技术A WebSocket 是 html5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一 次“握手”(Handshaking)的步骤。
握手·请求
为了实现 WebSocket 通信,需要用到 HTTP 的 Upgrade 首部字 段,告知服务器通信协议发生改变,以达到握手的目的。
Sec-WebSocket-Key 字段内记录着握手过程中必不可少的键值。 Sec-WebSocket-Protocol 字段内记录使用的子协议。 子协议按 WebSocket 协议标准在连接分开使用时,定义那些连接 的名称。
177 握手·响应
对于之前的请求,返回状态码 101 Switching Protocols 的响应。
Sec-WebSocket-Accept 的字段值是由握手请求中的 SecWebSocket-Key 的字段值生成的。 成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数 据帧,而采用 WebSocket 独立的数据帧。
成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数 据帧,而采用 WebSocket 独立的数据帧。
javascript 可调用“The WebSocket API”,以下为调用 WebSocket API,每 50ms 发送一次数据的实例。
HTML5基于TCP的全双工通信协议WebSocket
我们从小就在学习分享,我们分享过糖果、分享过玩具,今天我们一起分享知识。
webSocket
1.websocket背景简介
2.websocket的客户端使用方式
3.websocket服务端使用方式
1.websocket背景介绍
HTTP和WebSocket两者的差距不大
浏览网页时,经过三个过程
1、浏览器经过三次握手与web服务器建立链接,
2、web服务器返回响应
3、浏览器通过四次握手主动断开链接
因为第三步导致不能持久链接,那我们去掉第三步不就可以了实现持久链接了吗?这就是WebSocket与HTTP最大的不同(Web服务器是不会主动断开连接的),当然还有更多的数据封装格式的不同。 可以看到WebSocket是在HTTP上做的改动,有人曾经用单片机的TCP/IP协议栈封装符合HTTP协议格式的字符串,去连接Web服务器。WebSocket和HTML5没有多大关系。
如果要搭建一个Web服务器,我们会有很多选择,市场上也有很多成熟的产品供我们应用,比如开源的Apache,安装后只需简单的配置(或者默认配置)就可以工作了。但是如果想搭建一个WebSocket服务器就没有那么轻松了,因为WebSocket是一种新的通信协议,目前还是草案,没有成为标准,市场上也没有成熟的WebSocket服务器或者Library实现WebSocket协议,我们就必须自己动手写代码去解析和组装WebSocket的数据包。要这样完成一个WebSocket服务器,估计所有的人都想放弃,幸好的是市场上有几款比较好的开源库供我们使用,我们可以调用这些接口,这在很大程度上减少了我们的工作量。
百万websocket常连接的服务器
Netty服务器
Spray服务器
node.js
Websocket协议之握手连接
一、协议包含两个部分,第一个是“握手”,第二个是数据传输。
ws://127.0.0.1:8080 //不太安全
wss://127.0.0.1:8080 //更安全
类似于http https的区别
二、握手(Opening > Closing Handshake)打开连接
1、发送握手请求
2、返回握手应答
3、错误处理 所有数据传输都是UTF-8编码的数据,当一端接收到的字节流数据不是一个有效的UTF-8数据流,那么接收到的这一方必须要马上关闭连接。这个规则在开始握手一直到所有的数据交换过程都要进行验证。
2.websocket的客户端使用方式
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
那么简言之用户所使用的浏览器就看作为客户端(client)那么我们需要在html中利用Javascript去创建我们的客户端
由于是html5提供的WebSocket服务那么现在主流的浏览器都可以直接使用WebSocket。(ie8+均可使用)
书归正传
WebSocket 属性
以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:
属性Socket.readyState
只读属性 readyState 表示连接状态,可以是以下值:
0 - 表示连接尚未建立。
1 - 表示连接已建立,可以进行通信。
2 - 表示连接正在进行关闭。
3 - 表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount
只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。
WebSocket 事件
以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:
事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发
WebSocket 方法
以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:
方法 描述
Socket.send()
使用连接发送数据
Socket.close()
关闭连接
1.需要先创建WebSocket 并且判断一下当前浏览器是否支持
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/webSocket/websocket");
} else {
alert('当前浏览器 Not support websocket')
}
创建成功后利用WebSocket提供的方法去实现WebSocket的服务
//连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function() {
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
3.websocket服务端使用方式
那么根据对客户端的理解,java中的servlet也就是我们服务端,处理业务逻辑的地方
需要注意
因为使用websocket与传统的http请求是不同的那么在servlet就与之前学习过的有很大的不同
不同一 注解不同
以前我们访问一个servlet使用的是@WebServlet("/login.do")如果换成websocket方式需要改成@ServerEndpoint("/websocket")
不同二 方法不同
我们不在需要doGet(),doPost()这个两个方法了。因为webSocket是一种新的协议与传统http不同(前文提到过)
/** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一 * 个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接 * 到WebSocket服务器端 */ @ServerEndpoint("/websocket") public class WebSocket { // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount; // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放, //其中Key可以为用户标识 private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>(); // 与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; /** * 连接建立成功调用的方法 * @param session * 可选的参数。session为与某个客户端的连接会话, * 需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); // 加入set中 addOnlineCount(); // 在线数加 System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); // 从set中删除 subOnlineCount(); // 在线数减 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * @param message * 客户端发送过来的消息 * @param session * 可选的参数 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("来自客户端的消息:" + message); // 群发消息 for (WebSocket item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); continue; } } } /** * 发生错误时调用 * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { System.out.println("发生错误"); error.printStackTrace(); } /** * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 * getBasicRemote() 与 getAsyncRemote()区别 * getAsyncRemote是非阻塞式的 * getBasicRemote阻塞模式 * 也就是说如果使用getBasicRemote那么每一条信息都需要等待上一条信息发送完毕之后才能发送 * ,反之区别getAsyncRemote是不需要的 * @param message * @throws IOException */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); // this.session.getAsyncRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocket.onlineCount++; } public static synchronized void subOnlineCount() { WebSocket.onlineCount--; } }
以上是关于使用WebSocket进行全双工通信的主要内容,如果未能解决你的问题,请参考以下文章