websocket实战(2) 信息处理发送、接收和编码

简介:

websocket 和传统意义上的socket编程虽然存在差别,但也存在相通概念,也分服务端和客户端。

主要区别

  1. 对于websocket,客户端的编写方式是通过JS编写回调函数完成交互;而传统socket,则需要连接端口,通过输入输出流来传递信息,完成交互;

  2. 传统的socket,服务端则需要绑定端口,通过accept 方法,等待客户端的连接。websocket 规范则把处理细节由web服务器来完成。

数据处理是websocket的一项主要工作。按工作阶段划分,主要包括以下方面。

  1. 信息发送

  2. 信息解码

  3. 信息编码

  4. 信息接收

按传递数据划分,分为

  1. 文本信息

  2. 二进制流信息

  3. ping/pong信息

上面的内容,仅限于服务端,websocket html5相关暂时不讨论

1.信息发送( Sending Messages)

表示服务端,将消息传递给客户端(peer)

1.1将消息广播到所有连接客户端

1
2
3
4
5
6
7
8
9
10
11
12
@ServerEndpoint ( "/echoall" )
public  class  EchoAllEndpoint {
    @OnMessage
    public  void  onMessage(Session session, String msg) { //1
       try  {
          for  (Session sess : session.getOpenSessions()) {
             if  (sess.isOpen())
                sess.getBasicRemote().sendText(msg); //2,3
          }
       catch  (IOException e) { ... }
    }
}

信息发送三步

1.Obtain the Session object from the connection.(通过在参数中添加Session,获取Session)

2.Use the Session object to obtain a RemoteEndpoint object.

3.Use the RemoteEndpoint object to send messages to the peer.

1.2返回值,作为信息发送

1
2
3
4
5
@OnMessage
public  String onMessage(String message,Session session) {
     System.out.println( "Received : " + message);
     return  message+ "-" +session.getId();
}

2.信息解码和编码(codec)

拿打电话为例,如果电话双方,都用一样的标准普通话沟通,就没必要用翻译器了。如果电话双方,一边用着标准的牛津话,一方操着标准的山东土话,想想也能想想出来,沟通直接乱掉了,这时候必须要用到双方必须都需要翻译器了。websocket的编码和解码部分就是“翻译器”的角色。

编码及解码器位置

wKiom1flQOrjYxZkAAA-cTPuJaw973.png

可以简单理解为:解码就是反序列化的过程;编码就是序列化的过程。

2.1 使用Encoders 反序列化对象

响应信息需要转换成二进制,才能进行网络传递。

来自j2ee的例子

1.实现Encoder.Text<T> 或Encoder.Binary<T>接口

1
2
3
4
5
6
7
8
9
10
11
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 注解的encoders 属性中

1
2
3
4
5
@ServerEndpoint (
    value =  "/myendpoint" ,
    encoders = { MessageATextEncoder. class , MessageBTextEncoder. class  }
)
public  class  EncEndpoint { ... }

3.使用RemoteEndpoint.Basic or RemoteEndpoint.Async 的sendObject发送对象。

1
2
3
4
MessageA msgA =  new  MessageA(...);
MessageB msgB =  new  MessageB(...);
session.getBasicRemote.sendObject(msgA);
session.getBasicRemote.sendObject(msgB);

2.2 使用Decoders 序列化信息

将请求信息转换成对象,才方便ServerPoint处理响应

与Encoders处理步骤类似

1.实现Decoder.Text<T>或Decoder.Binary<T>接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
    }
}

请注意willDecode方法,决定是否进行解码


2. 新建的Decoder,添加到ServerEndpoint 注解的decoders 属性中

1
2
3
4
5
6
@ServerEndpoint (
    value =  "/myendpoint" ,
    encoders = { MessageATextEncoder. class , MessageBTextEncoder. class  },
    decoders = { MessageTextDecoder. class  }
)
public  class  EncDecEndpoint { ... }

3. 这时候就可以在@OnMessage注解的参数方法中直接使用Decoder.decode返回的对象类型了。

1
2
3
4
5
6
7
8
@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...
    }
}

具体例子,见我的github项目。https://github.com/janecms/websocket_example

3.信息接收(Receiving Messages)

3.1 接收三种不同形式消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package  com.sample.websocket.endpoint;
import  javax.websocket.OnMessage;
import  javax.websocket.PongMessage;
import  javax.websocket.Session;
import  javax.websocket.server.ServerEndpoint;
import  java.nio.ByteBuffer;
 
@ServerEndpoint ( "/receive" )
public  class  ReceiveEndpoint {
    @OnMessage
    public  void  textMessage(Session session, String msg) {
       System.out.println( "Text message: "  + msg);
    }
     @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());
    }
}

一个奇怪的情况,不同版本的Tomcat,对@OnMessage注解的方法限制有所不同。也进一步说明,websocket规范是个快速变化中的规范。有的直接编译期出错;有的运行时错误。(有可能和我选择不同版本的开发工具有关系,不太确定,一样的代码,表现不同的行为,蹊跷)

需要注意的是被OnMessage注解的三个方法,分别接收不同的消息类型。

3.2 错误代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ServerEndpoint ( "/echo" )
public  class  EchoEndpoint {
     @OnMessage
     public  String onMessage(String message,Session session) {
         System.out.println( "Received : " + message);
         return  message+ "-" +session.getId();
     }
 
     @OnMessage
     public  String onMessage2(String message,Session session) {
         System.out.println( "Received : " + message);
         return  message+ "####" +session.getId();
     }
}

代码,报运行时异常。

javax.servlet.ServletException: javax.websocket.DeploymentException: Duplicate annotation

一种消息类型,只能对应一个OnMessage方法。




本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1855978,如需转载请自行联系原作者

相关文章
|
2月前
|
前端开发 网络协议 Java
WebSocket理论和实战
WebSocket详解与实战操作
|
6月前
|
前端开发 Java 程序员
Spring Boot+Netty+Websocket实现后台向前端推送信息
学过 Netty 的都知道,Netty 对 NIO 进行了很好的封装,简单的 API,庞大的开源社区。深受广大程序员喜爱。基于此本文分享一下基础的 netty 使用。实战制作一个 Netty + websocket 的消息推送小栗子。
|
3月前
|
传感器 监控 网络协议
WebSocket 实战:构建高效的实时应用
WebSocket 实战:构建高效的实时应用
WebSocket 实战:构建高效的实时应用
|
9月前
|
存储 数据安全/隐私保护
Netty实战(十三)WebSocket协议(一)
WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息,因此,这也就要求它们异步地处理消息回执。
162 0
|
12月前
|
消息中间件 前端开发 JavaScript
Spring Boot+Netty+Websocket实现后台向前端推送信息
Spring Boot+Netty+Websocket实现后台向前端推送信息
|
6月前
|
移动开发 前端开发 网络协议
WebSocket从入门到实战
WebSocket从入门到实战
172 0
|
9月前
|
数据安全/隐私保护
Netty实战(十四)WebSocket协议(二)
我们之前说过为了将 ChannelHandler 安装到 ChannelPipeline 中,需要扩展了ChannelInitializer,并实现 initChannel()方法
106 0
|
9月前
|
JavaScript 前端开发 Java
java springboot websocket vue 实现发送信息
java springboot websocket vue 实现发送信息
|
10月前
|
前端开发 Java Spring
websocket作为服务端收发信息的demo
websocket作为服务端收发信息的demo
90 0
|
前端开发 网络协议 Windows
记一次 websocket 实战,“我没有拿到回执呀”
web 前端 A1 与后端 C1 建立 websocket,等后端 C2 推送给 C1 一个 callBack 消息后,C1 再将这个消息推回给 A1,最后 A1 拿到这个回执后渲染界面;