HTML5基于TCP的全双工通信协议WebSocket
Posted LittleStep
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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--; } }
以上是关于HTML5基于TCP的全双工通信协议WebSocket的主要内容,如果未能解决你的问题,请参考以下文章