一、websocket简介

websocket协议通过在客户端和服务端之间提供全双工通信来进行web和服务器的交互功能。

在websocket应用程序中,服务器发布websocket端点,客户端使用url连接到服务器。建立连接后,服务器和客户端就可以互相发送消息。客户端通常连接到一台服务器,服务器接受多个客户端的连接。

1.1 websocket协议

websocket协议有两个部分:握手和传输。客户端通过向服务端url发送握手请求来建立连接。握手与现有的基于http的基础结构相兼容。web服务器将其解释为升级版的http连接请求。
一个客户端建立连接的握手请求:

get /path/to/websocket/endpoint http/1.1
host: localhost
upgrade: websocket
connection: upgrade
sec-websocket-key: xqbt3imnzjbyqrinxeflkg==
origin: http://localhost
sec-websocket-version: 13

一个服务端响应:

http/1.1 101 switching protocols
upgrade: websocket
connection: upgrade
sec-websocket-accept: k7djldlooiwig/mopvwfb3y3fe8=

从上面的请求和响应中可以看出来,一个websocket连接的建立,需要客户端和服务端维护一个key来作为该连接的连接凭证。
客户端向服务端发送websocketkey,服务器根据websocketkey生成websocketaccept返回给客户端,客户端对websocketkey的值再进行相同的操作,如果与服务器返回的accept的值相匹配,就表示握手成功。握手之后客户端与服务端就互相发送消息。

1.2 websocket支持的消息类型

websocket支持文本消息(utf-8编码)和二进制消息。websocket的控制消息由close、ping、pong组成。ping和pong也有可能包含应用程序信息。
websocket端点具有如下的uri形式表示:

ws://host:port/path?query
wss://host:port/path?query

ws代表未加密的连接,默认端口是80
wss代表加密的连接,默认端口是443
path:表示服务器内端点的位置
query:路径参数信息

二、创建一个websocket程序

创建和部署websocket端点的过程如下:
1、创建一个端点类
2、实现端点的生命周期方法
3、将业务逻辑添加到端点
4、将端点部署到web应用程序中

注意:与servlet相反,websocket端点类会被实例化多次,容器针对与其部署的uri的每个连接都创建一个实例。每个实例都与一个连接相关联。因为在任何时间都只有一个线程执行端点实例的代码,所以有助于保持每个连接的用户状态简化开发。

2.1 生命周期方法

endpoint类中定义了三个生命周期方法:onopen、onclose、onerror
使用注解方式创建服务类

@serverendpoint("/echo")
public class echoendpoint {
   @onmessage
   public void onmessage(session session, string msg) {
      try {
         session.getbasicremote().sendtext(msg);
      } catch (ioexception e) { ... }
   }
}

2.2 业务逻辑方法

@serverendpoint("/receive")
public class receiveendpoint {
   @onmessage
   public void textmessage(session session, string msg) {
      system.out.println("text message: " + msg);
   }
   @onmessage
   public void binarymessage(session session, bytebuffer msg) {
      system.out.println("binary message: " + msg.tostring());
   }
   @onmessage
   public void pongmessage(session session, pongmessage msg) {
      system.out.println("pong message: " + 
                          msg.getapplicationdata().tostring());
   }
}

注意:一个服务类最多可以有三个onmessage注解,每个消息类型分别使用一种方法:text、binary、pong

2.3 维护客户状态

有时在程序中我们可能需要在连接中维护一些用户参数,websocket也提供了这样的服务
session.getuserproperties获取用户参数信息
如果要存储所有连接的客户端共有的信息,可以使用静态变量,但是需要用户保证对数据的线程安全访问。

@serverendpoint("/delayedecho")
public class delayedechoendpoint {
   @onopen
   public void open(session session) {
      session.getuserproperties().put("previousmsg", " ");
   }
   @onmessage
   public void message(session session, string msg) {
      string prev = (string) session.getuserproperties()
                                    .get("previousmsg");
      session.getuserproperties().put("previousmsg", msg);
      try {
         session.getbasicremote().sendtext(prev);
      } catch (ioexception e) { ... }
   }
}

2.4 数据格式的编码与解码

由于客户端和服务端交互可能涉及数据格式的转换,所以提供了decoder和encoder的方式解决。
同时由于websocket的@message注解只能有一个用来传输text信息或binary信息,所以要进行最常用的json->entity转换解析就需要该方法
encoder

encoder.text 用于文本消息encoder.binary 用于二进制消息

使用方法:

1、创建编解码类

public class messageatextencoder implements encoder.text<messagea> {
   @override
   public void init(endpointconfig ec) { }
   @override
   public void destroy() { }
   @override
   public string encode(messagea msga) throws encodeexception {
      // access msga's properties and convert to json text...
      return msgajsonstring;
   }
}

2、在端点类注解中添加该encoder

@serverendpoint(
   value = "/myendpoint",
   encoders = { messageatextencoder.class, messagebtextencoder.class }
)
public class encendpoint { ... }

3、这时候就可以发送messagea和messageb两种类型的text数据

messagea msga = new messagea(...);
messageb msgb = new messageb(...);
session.getbasicremote.sendobject(msga);
session.getbasicremote.sendobject(msgb);

注意:websocket会自动寻找使用哪种编码器,所以发送数据统一使用sendobject即可

decoder

实现decoder以将websocket消息转换为java对象

  • decoder.text 用于文本消息
  • decoder.binary 用于二进制消息

使用方法

与encoder类似

注意:与encoder不同,decoder最多可以指定一个binary和一个text类型的decoder,如果有两种以上的java类型作为文本消息进行发送和接收需要进行定义处理。可以使多个消息继承一个公共的消息父类

1、编写decoder类,对收到消息类型的不同进行不同的解码

public class messagetextdecoder implements decoder.text<message> {
   @override
   public void init(endpointconfig ec) { }
   @override
   public void destroy() { }
   @override
   public message decode(string string) throws decodeexception {
      // read message...
      if ( /* message is an a message */ )
         return new messagea(...);
      else if ( /* message is a b message */ )
         return new messageb(...);
   }
   @override
   public boolean willdecode(string string) {
      // determine if the message can be converted into either a
      // messagea object or a messageb object...
      return candecode;
   }
}

2、在端点类中添加decoders={messagedecoder.class}

@serverendpoint(
   value = "/myendpoint",
   encoders = { messageatextencoder.class, messagebtextencoder.class },
   decoders = { messagetextdecoder.class }
)
public class encdecendpoint { ... }

3、在@onmessage方法中使用

@onmessage
public void message(session session, message msg) {
   if (msg instanceof messagea) {
      // we received a messagea object...
   } else if (msg instanceof messageb) {
      // we received a messageb object...
   }
}

到此这篇关于教你怎么使用java websocket的文章就介绍到这了,更多相关java websocket详解内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!