溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

websocket實戰(zhàn)(2) 信息處理發(fā)送、接收和編碼

發(fā)布時間:2020-09-18 14:20:17 來源:網(wǎng)絡(luò) 閱讀:12526 作者:randy_shandong 欄目:開發(fā)技術(shù)

websocket 和傳統(tǒng)意義上的socket編程雖然存在差別,但也存在相通概念,也分服務端和客戶端。

主要區(qū)別

  1. 對于websocket,客戶端的編寫方式是通過JS編寫回調(diào)函數(shù)完成交互;而傳統(tǒng)socket,則需要連接端口,通過輸入輸出流來傳遞信息,完成交互;

  2. 傳統(tǒng)的socket,服務端則需要綁定端口,通過accept 方法,等待客戶端的連接。websocket 規(guī)范則把處理細節(jié)由web服務器來完成。

數(shù)據(jù)處理是websocket的一項主要工作。按工作階段劃分,主要包括以下方面。

  1. 信息發(fā)送

  2. 信息解碼

  3. 信息編碼

  4. 信息接收

按傳遞數(shù)據(jù)劃分,分為

  1. 文本信息

  2. 二進制流信息

  3. ping/pong信息

上面的內(nèi)容,僅限于服務端,websocket html5相關(guān)暫時不討論

1.信息發(fā)送( Sending Messages)

表示服務端,將消息傳遞給客戶端(peer)

1.1將消息廣播到所有連接客戶端

@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) { ... }
   }
}

信息發(fā)送三步

1.Obtain the Session object from the connection.(通過在參數(shù)中添加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返回值,作為信息發(fā)送

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

2.信息解碼和編碼(codec)

拿打電話為例,如果電話雙方,都用一樣的標準普通話溝通,就沒必要用翻譯器了。如果電話雙方,一邊用著標準的牛津話,一方操著標準的山東土話,想想也能想想出來,溝通直接亂掉了,這時候必須要用到雙方必須都需要翻譯器了。websocket的編碼和解碼部分就是“翻譯器”的角色。

編碼及×××位置

websocket實戰(zhàn)(2) 信息處理發(fā)送、接收和編碼

可以簡單理解為:解碼就是反序列化的過程;編碼就是序列化的過程。

2.1 使用Encoders 反序列化對象

響應信息需要轉(zhuǎn)換成二進制,才能進行網(wǎng)絡(luò)傳遞。

來自j2ee的例子

1.實現(xiàn)Encoder.Text<T> 或Encoder.Binary<T>接口

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 屬性中

@ServerEndpoint(
   value = "/myendpoint",
   encoders = { MessageATextEncoder.class, MessageBTextEncoder.class }
)
public class EncEndpoint { ... }

3.使用RemoteEndpoint.Basic or RemoteEndpoint.Async 的sendObject發(fā)送對象。

MessageA msgA = new MessageA(...);
MessageB msgB = new MessageB(...);
session.getBasicRemote.sendObject(msgA);
session.getBasicRemote.sendObject(msgB);

2.2 使用Decoders 序列化信息

將請求信息轉(zhuǎn)換成對象,才方便ServerPoint處理響應

與Encoders處理步驟類似

1.實現(xiàn)Decoder.Text<T>或Decoder.Binary<T>接口

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 屬性中

@ServerEndpoint(
   value = "/myendpoint",
   encoders = { MessageATextEncoder.class, MessageBTextEncoder.class },
   decoders = { MessageTextDecoder.class }
)
public class EncDecEndpoint { ... }

3. 這時候就可以在@OnMessage注解的參數(shù)方法中直接使用Decoder.decode返回的對象類型了。

@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

  • (XML)編碼解密處理(codec)

  • (JSON)編碼解密處理(codec)

3.信息接收(Receiving Messages)

3.1 接收三種不同形式消息

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規(guī)范是個快速變化中的規(guī)范。有的直接編譯期出錯;有的運行時錯誤。(有可能和我選擇不同版本的開發(fā)工具有關(guān)系,不太確定,一樣的代碼,表現(xiàn)不同的行為,蹊蹺)

需要注意的是被OnMessage注解的三個方法,分別接收不同的消息類型。

3.2 錯誤代碼

@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方法。

參考資源

https://docs.oracle.com/javaee/7/tutorial/websocket005.htm

結(jié)論:主要討論了消息相關(guān)的內(nèi)容 按消息處理的不同階段進行總結(jié)。接下來即將討論websocket相關(guān)的配置信息,及錯誤處理。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI