三、WebSocket客户端
1.说明
WebSocket作为 HTML5的一个重要组成部分,在现今逐渐成为一个主流的标准.Voovan 提供对 WebSocket 客户端的支持.下面我们就简单的介绍一下: 首先通过 HttpClient
类的 webSocket
方法即可简单的实现对 WebSocket 的访问.同时基于 WebSocketRouter
类实现对onOpen
、onRecived
、onSent
、onClose
四个方法的支持。
以下几个类是 WebSocket 开发中常用的类:
WebServer
类: 该类的 Socket 方法提供给我们一个注册 WebSocket 服务的入口.WebSocketRoute
类: 一个 WebSocket 业务处理类,Voovan 采用异步的方式调用这个类的各种事件.WebSocketSession
类: 一个 WebSocket 会话类,提供了诸如:send
,close
,isConnect
等基于会话的方法.WebSocketFilter
类: WebSocket 消息过滤器类
2.材料准备
首先我们来介绍一个HttpClient.webSocket
方法
public void webSocket(String urlString, WebSocketRouter webSocketRouter) throws SendMessageException, ReadMessageException {
- urlString: websocket 访问路由地址.
- webSocketRouter: websocket 路由处理对象.如果要开发一个 WebSocket 类,首先我们要调用webSocket方法,并注册一个路由和 WebSocket 的路由处理类WebSocketRouter.
接下来我们来熟悉一下WebSocketRouter
类的定义
/**
/**
* websocket 连接打开
* @return 收到的缓冲数据
*/
public abstract ByteBuffer onOpen(WebSocketSession session);
/**
* websocket 收到消息
* @param message 收到的缓冲数据
* @return 收到的缓冲数据
*/
public abstract ByteBuffer onRecived(WebSocketSession session, ByteBuffer message);
/**
* websocket 消息发送完成
* @param message 发送的消息
*/
public abstract void onSent(WebSocketSession session, ByteBuffer message);
/**
* websocket 关闭
*/
public abstract void onClose(WebSocketSession session);
最后我们来介绍一下样例的信息:
- 访问的地址:
http://127.0.0.1:28080/websocket
onOpen
发送 OPEN_MSGonRecived
收到后发送 RECIVE_MSGonSent
输出发送的消息onClose
输出 close如何处理消息的发送和接受?
如何接受消息:
在 onRecive 事件中的第二个参数 message 就是 WebSocket 从客户端接收到的数据.我们们可以在这里讲数据转换成需要个对象后进行处理.
在 Voovan HttpClient 中向客户端发送消息有三种方式:
- onOpen 事件返回的数据将会被发送至客户端, 返回 null 时不发送任何消息.
- onRecive 事件返回的数据将会被发送至客户端, 返回 null 时不发送任何消息.
- 调用 WebSocketSession.send 来发送数据. 也就是说,我们在 WebSocket 刚建立连接的时候就可以主动发送消息给客户端了,然后就是在收到消息后返回一个消息给客户端.
3.过滤器
我们可以通过 WebSocketRouter
的 addFilterChain
方法为 WebSocketRouter
增加过滤器.下面例子中我们增加了一个 StringFilter
过滤器,这是一个字符串过滤器是一个继承于WebSocketFilter
接口的类,他的作用是将 WebSocket 接收的 ByteBuffer 转换成 一个字符串对象供 WebSocketRouter 的 onRecived 调用. 这样这个过滤器类就可以被多个场景复用,且保证了WebSocketRouter的可单元测试的特性。下面我们来看一下 StringFilter 的实现:
public class StringFilter implements WebSocketFilter {
@Override
public Object encode(WebSocketSession session, Object object) {
if(object instanceof String){
String sourceString = TObject.cast(object);
return ByteBuffer.wrap(sourceString.getBytes());
}
return object;
}
@Override
public Object decode(WebSocketSession session,Object object) {
if(object instanceof ByteBuffer){
return TByteBuffer.toString((ByteBuffer)object);
}
return object;
}
}
由于只有一个过滤器,我们可以发现一个规律, 所有过滤器链的第一个位置过滤器的 decode 方法接收到的都是 ByteBuffer对象,所有过滤器链最后一个位置的过滤器的 encode 方法都返回都是 ByteBuffer 对象,这一点大家在开发的时候需要注意.
4.举个栗子
这里我们首先初始话一个HttpClient
对象,接着我们通过webSocket
方法来注册一个 WebSocket 消息处理类.最后通过实现WebSocketRouter
类来处理 WebSocket 的消息.
HttpClient httpClient = new HttpClient("ws://127.0.0.1:28080/","GBK2312",500);
httpClient.webSocket("/websocket", new WebSocketRouter() {
@Override
public Object onOpen(WebSocketSession webSocketSession) {
Logger.simple("WebSocket open");
return "OPEN_MSG";
}
@Override
public Object onRecived(WebSocketSession webSocketSession, Object message) {
Logger.simple("Recive: "+message);
try {
return "RECIVE_MSG";
}finally {
webSocketSession.close();
}
}
@Override
public void onSent(WebSocketSession webSocketSession, Object message){
Logger.simple("Send: " + message);
}
@Override
public void onClose(WebSocketSession webSocketSession) {
Logger.simple("WebSocket close");
}
}.addFilterChain(new StringFilter()));