您的位置:首页 > 编程语言 > Java开发

Java WebSocket 基础知识点及简单实现

2016-09-03 15:26 239 查看

一 、 WebSocket简单介绍

  随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

  我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应 用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。

  轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。

  Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。

  这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。

  伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这 样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多。本文不详细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。

  JavaEE 7中出了JSR-356:Java API for WebSocket规范。不少Web容器,如Tomcat,Nginx,Jetty等都支持WebSocket。Tomcat从7.0.27开始支持 WebSocket,从7.0.47开始支持JSR-356,所以需要部署在Tomcat7.0.47以上的版本才能运行。

二 、webSocket 实用基础知识点

WebSocket端点的4个生命周期事件

打开事件

此事件发生在端点上建立新连接时并且在任何其他事件之前

消息事件

此事件接收WebSocket对话的另外一端发送的消息。它可以发生在WebSocket端点接收了打开事件后并且在接收关闭事件关闭连接之前的任意时刻

错误事件

此事件在WebSocket连接或者端点发生错误时产生

关闭事件

此事件表示WebSocket端点的连接目前正在部分的关闭,它可以由参与连接的任意一个端点发出

注解式端点事件处理

将Java类声明成WebSocket端点,在服务器端端点用@ServerEndpoint来注解,在客户端可以使用@ClientEndpoint来注解。对于端点的四个生命周期事件:

打开事件@OnOpen

@OnOpen
public void init(Session session,EndpointConfig config){
/*
*方法名任意,参数两个任选,可要可不要,其他事件也一样
**/
}


消息事件@OnMessage

@OnMessage
public void message(String textMessage,Session session){
//处理文本信息,Session参数可选
}

@OnMessage
public void message(byte[] messageData,Session session){
//处理二进制信息,Session参数可选
}

@OnMessage
public void message(String textMessage,boolean isLast){
//处理分片段的文本信息,isLast 为false表示信息没有接收完整,true则表示最后一条信息
}

//所有的@OnMessage 也可以有返回值相当于发送消息的功能
@OnMessage
public String message(String textMessage,Session session){
//处理文本信息,Session参数可选
return "I got it";
}


错误事件@OnError

@OnError
public void errorHandler(Throwable t){
//log error here
}


关闭事件@OnClose

@OnClose
public void goodbye(){
//
}


发送信息

javax.websocket.Session

Session 代表了单客户端的状态,每个客户端与服务端建立连接都会生成唯一的session 属性中有主键id 通过id可以分辨用户

发送字符串消息

RemoteEndpoint.Basic发送文本信息:public void sendText(String text) throws IOEcxeption

RemoteEndpoint.Basic发送文本信息到流:public Writer getSendStream() throws IOEcxeption

RemoteEndpoint以片段形式发送文本消息:public void sendText(String partialMessage,boolean isLast) throws IOException

以小片段序列的形式发送大的字符串消息,调用时isLast参数一般设为false,直到最后一个片段才设为true,表明消息发送完毕。

发送二进制消息

对于大多数应用,发送文本形式消息已经足够,对于有特殊格式例如小图像文件,以二进制形式发送消息则更合适

RemoteEndpoint发送二进制消息:

public void sendBinary(ByteBuffer data) throws IOException

public void sendBinary(ByteBuffer partialByte,boolean isLast) throws IOException 以分片的形式发送,调用时isLast参数一般设为false,直到最后一个片段才设为true,表明消息发送完毕。

RemoteEndpoint.Basic使用流发送二进制消息:

public OutputStream getSendStream() throws IOException

javax.websocket.EndpointConfig: 与多客户端共享的端点状态相关联。

了解以上服务端的基础知识可以处理从客户端接收到的请求和给客户端发送信息。但是如何与客户端建立连接呢?

构建服务端类

@ServerEndpoint("/echo")
public class Test {
@OnOpen
public void name(Session session) {
System.out.println("连接成功");
}

@OnMessage
public void message(String textMessage,Session session{
//处理文本信息,Session参数可选
}
...
}


以javascript脚本为客户端讲解:

建立连接

定义uri : var wsUri = “ws://localhost:9080/context/echo”;

var ws = new WebSocket(wsUri);

说明:/context 是项目的上下文;/echo 断点的路径 (整个项目中唯一的)

发送消息

ws.onopen = function(){
//成功建立连接之后调用的方法
}
//想服务端发送消息
ws.send("文本消息");

websocket.onclose = function() {
//关闭建立连接之后调用的方法
};
websocket.onmessage = function(evt) {
//服务器返回消息触发的方法
};
websocket.onerror = function(evt) {
//产生已成触发的方法
};

//关闭连接
ws.close();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐