1. websocket
1.1 websocket介绍
websocket是一种网络通信协议。RFC6455定义了它的通信标准。
websocket 是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。
HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
这种通信模型有一个弊端:HTTP协议无法实现服务器主动向客户端发起消息。
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数web应用程序将通过频繁的异步A.JAX请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP连接始终打开)。
http协议:
websocket 协议:
1.2 websocket协议
本协议有两部分:握手和数据传输
握手时基于http协议的
来自客户端的握手看起来像如下形式:
GET wS :/ /1oca1host/chat HTTP/1.1
Host: loca1host
upgrade: websocketconnection: upgrade
sec-websocket-key: dGh1IHNhbXBSZSBub25jzQ==
sec-websocket-Extensions : permessage-deflate
sec-websocket-version: 13
来自服务器端的握手看起来像如下形式:
HTTP/1.1 101 switching Protocols
upgrade: websocket
connection: upgrade
sec-websocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
sec-websocket-Extensions: permessage-deflate
字段说明:
头名称 | 说明 |
---|---|
connection Upgrade | 标识该HTTP请求是一个协议升级请求 |
upgrade websocket | 协议升级为websocket协议 |
websocket-version: 13 | 客户端支持websocket的版本 |
sec-websocket-key | 客户端采用base64编码的24位随机字符序列,服务器接受客户端HTTP协议升级的证明。要求服务端响应一个对应加密的sec-websocket-Accept头信息作为应答 |
sec-websocket-Extensions | 协议扩展类型 |
1.3 客户端(浏览器)实现
1.3.1 websocket对象
实现 WebSockets 的web浏览器将通过WebSocket
对象公开所有必须的客户端功能(主要支持html5 的浏览器)
以下 API 用于创建 WebSocket 对象:
var ws = new WebSocket(url);
1.3.2 websocket事件
WebSocket 对象的相关事件
事件 | 事件处理程序 | 描述 |
---|---|---|
open | websocket对象.onopen | 连接建立时触发 |
message | websocket对象.onmessage | 客户端接收服务端数据时触发 |
error | websocket对象.onerror | 通信发生错误时触发 |
close | websocket对象.onclose | 连接关闭时触发 |
1.3.3 websocket方法
WebSocket对象的相关方法
方法 | 描述 |
---|---|
send | 使用连接发送数据 |
1.4 服务端实现
Tomcat的7.0.5版本开始支持webSocket,并且实现了Java websocket规范(JSR356)。
Java WebSocket应用由一系列的webSocketEndpoint组成。Endpoint 是一个java对象,代表websocket链接的一端,对于服务端,我们可以视为处理具体websockJ消息的接口,就像servlet之与http请求一样。
我们可以通过两种方式定义Endpoint :
- 第一种是编程式,即继承类javax.websocket.Endpoint并实现其方法
- 第二种是注解式,即定义一个PoJo,并添加eserverEndpoint相关注解。
Endpoint实例在webSocket握手时创建,并在客户端与服务端链接过程中有效,最后在链接关闭时结束。在Endpoint接口中明确定义了与其生命周期相关的方法,规范实现者确保生命周期的各个阶段调用实例的相关方法。生命周期方法如下:
方法 | 含义描述 | 注解 |
---|---|---|
onClose | 当会话关闭时调用。 | @OnClose |
onOpen | 当开启一个新的会话时调用,该方法是客户端与服务端握手成功后调用的方法。 | @OnOpen |
onError | 当连接过程中异常时调用。 | @OnError |
1.4.1 服务端如何接收客户端发送的数据呢?
通过为 Session
添加MessageHandler
消息处理器来接收消息,当采用注解方式定义Endpoint
时,我们还可以通过@onMessage
注解指定接收消息的方法。
1.4.2 服务端如何推送数据给客户端呢?
发送消息则由RemoteEndpoint
完成,其实例由session维护,根据使用情况,我们可以通过session.getBasicRemote
获取同步消息发送的实例,然后调用其sendXxx ()
方法就可以发送消息,可以通过session.getAsyncRemote
获取异步消息发送实例。
1.4.3 服务器端代码
@ServerEndpoint("/robin")
public class CharEndPoint {
private static Set<Session> websocketSet = new HashSet<>();
private Session session;
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println("接收到的消息是:"+message);
System.out.println(session);
// 消息发送给其它用户
for (Session chat : websocketSet){
if (chat != this){
chat.getBasicRemote().sendText(message);
}
}
}
//建立连接成功调用
@OnOpen
public void onOpen(Session session){
this.session = session;
}
//关闭连接时调用
@OnClose
public void onClose(Session session){
System.out.println("连接关闭了");
}
//错误时调用
@OnError
public void onError(Session session, Throwable throwable){
System.out.println("出错了。。。"+throwable.getMessage());
}
}