WebSocket 註解 (一)

Java EE HTML5 WebSocket 示例

返回原文英文原文:Java EE HTML5 WebSocket example

In this tutorial we will implement an HTML5 websocket resorting to the Java EE websocket implementation (ServerEndpoint).

1. Introduction

The HTML5 specification brought the capability for web browsers to establish full-duplex TCP connections with websocket compliant servers.

In other words, browsers are now able to establish a connection with a server and keep sending or receiving data through that same established communication channel without the need of the overhead introduced by the HTTP protocol itself.

In this tutorial we will implement a simple websocket server endpoint in a Java EE environment and also the respective client-side infrastructure for sending and receiving data.

This tutorial considers the following environment:

  1. Ubuntu 12.04
  2. JDK 1.7.0.21
  3. Glassfish 4.0
Note: WebSockets support was introduced in Java EE 7
譯者信息

在本教程中,我們將藉助於Java EE的WebSocket(服務器端)實現一個HTML5的WebSocket連接。

1. 介紹

HTML5給Web瀏覽器帶來了全雙工TCP連接websocket標準服務器的能力。

換句話說,瀏覽器能夠與服務器建立連接,通過已建立的通信信道來發送和接收數據而不需要由HTTP協議引入額外其他的開銷來實現。

在本教程中我們將在Java EE環境下實現一個簡單的websockect服務器端來和客戶端進行數據交互。

本教程需要以下環境:

  1. Ubuntu 12.04
  2. JDK 1.7.0.21
  3. Glassfish 4.0
: Java EE 7中才引入了WebSocket。
 

2. WebSocket server endpoint

Let's define a Java EE websocket server endpoint:

WebSocketTest.java
package com.byteslounge.websockets;

import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/websocket")
public class WebSocketTest {

  @OnMessage
  public void onMessage(String message, Session session) 
    throws IOException, InterruptedException {
  
    // Print the client message for testing purposes
    System.out.println("Received: " + message);
  
    // Send the first message to the client
    session.getBasicRemote().sendText("This is the first server message");
  
    // Send 3 messages to the client every 5 seconds
    int sentMessages = 0;
    while(sentMessages < 3){
      Thread.sleep(5000);
      session.getBasicRemote().
        sendText("This is an intermediate server message. Count: " 
          + sentMessages);
      sentMessages++;
    }
  
    // Send a final message to the client
    session.getBasicRemote().sendText("This is the last server message");
  }
  
  @OnOpen
  public void onOpen() {
    System.out.println("Client connected");
  }

  @OnClose
  public void onClose() {
    System.out.println("Connection closed");
  }
}
As you may have already noticed we are importing several classes from javax.websocket package.

@ServerEndpoint annotation is used at type level and defines the current class as a websocket server endpoint. The value used in this annotation represents the URL where the endpoint will be listening for client connections.

onOpen and onClose methods are annotated with @OnOpen and @OnClose respectively. These annotations are almost self-explanatory: They define which methods will be called upon a new client connection and disconnection.

Method onMessage is annotated with @OnMessage. This annotation defines which method will be called when a new message is received from the client. Note that this method may be defined with an optional parameter of type javax.websocket.Session (in our case the session parameter). If this parameter is defined the container will inject the session that is associated with the current client that sent the message being handled.

In our case we are just writing the client message content to the standard output. Then we proceed to send a message to the client followed by 3 test messages with a 5 second interval. Finally we send a final message to the client.

譯者信息

2. WebSocket服務器端

讓我們定義一個 Java EE websocket服務器端:

WebSocketTest.java

package com.byteslounge.websockets;

import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/websocket")
public class WebSocketTest {

  @OnMessage
  public void onMessage(String message, Session session) 
    throws IOException, InterruptedException {
  
    // Print the client message for testing purposes
    System.out.println("Received: " + message);
  
    // Send the first message to the client
    session.getBasicRemote().sendText("This is the first server message");
  
    // Send 3 messages to the client every 5 seconds
    int sentMessages = 0;
    while(sentMessages < 3){
      Thread.sleep(5000);
      session.getBasicRemote().
        sendText("This is an intermediate server message. Count: " 
          + sentMessages);
      sentMessages++;
    }
  
    // Send a final message to the client
    session.getBasicRemote().sendText("This is the last server message");
  }
  
  @OnOpen
  public void onOpen() {
    System.out.println("Client connected");
  }

  @OnClose
  public void onClose() {
    System.out.println("Connection closed");
  }
}
你可能已經注意到我們從 javax.websocket包中引入了一些類。

@ServerEndpoint 註解是一個類層次的註解,它的功能主要是將目前的類定義成一個websocket服務器端。註解的值將被用於監聽用戶連接的終端訪問URL地址。

onOpen 和 onClose 方法分別被@OnOpen@OnClose 所註解。這兩個註解的作用不言自明:他們定義了當一個新用戶連接和斷開的時候所調用的方法。

onMessage 方法被@OnMessage所註解。這個註解定義了當服務器接收到客戶端發送的消息時所調用的方法。注意:這個方法可能包含一個javax.websocket.Session可選參數(在我們的例子裏就是session參數)。如果有這個參數,容器將會把當前發送消息客戶端的連接Session注入進去。

本例中我們僅僅是將客戶端消息內容打印出來,然後首先我們將發送一條開始消息,之後間隔5秒向客戶端發送1條測試消息,共發送3次,最後向客戶端發送最後一條結束消息。

3. Client side

Now we need to write the client-side of our websocket test application:

page.html
<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
  <div>
    <input type="submit" value="Start" οnclick="start()" />
  </div>
  <div id="messages"></div>
  <script type="text/javascript">
    var webSocket = 
      new WebSocket('ws://localhost:8080/byteslounge/websocket');

    webSocket.onerror = function(event) {
      onError(event)
    };

    webSocket.onopen = function(event) {
      onOpen(event)
    };

    webSocket.onmessage = function(event) {
      onMessage(event)
    };

    function onMessage(event) {
      document.getElementById('messages').innerHTML 
        += '<br />' + event.data;
    }

    function onOpen(event) {
      document.getElementById('messages').innerHTML 
        = 'Connection established';
    }

    function onError(event) {
      alert(event.data);
    }

    function start() {
      webSocket.send('hello');
      return false;
    }
  </script>
</body>
</html>
This is a simple test page that contains the JavaScript that will create a websocket connection to out websocket server endpoint.

onOpen method will be called when we establish a connection with the server endpoint.

onError method is called when an error occurs during client-server communication.

onMessage method will be called when a message is received from the server. In our case we are just appending the messages received from the server to the DOM.

We connect to the websocket server endpoint by using the construct new WebSocket() and passing the endpoint URL:

ws://localhost:8080/byteslounge/websocket

譯者信息

3. 客戶端

現在我們要來寫websocket測試應用的客戶端:

page.html

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
  <div>
    <input type="submit" value="Start" οnclick="start()" />
  </div>
  <div id="messages"></div>
  <script type="text/javascript">
    var webSocket = 
      new WebSocket('ws://localhost:8080/byteslounge/websocket');

    webSocket.onerror = function(event) {
      onError(event)
    };

    webSocket.onopen = function(event) {
      onOpen(event)
    };

    webSocket.onmessage = function(event) {
      onMessage(event)
    };

    function onMessage(event) {
      document.getElementById('messages').innerHTML 
        += '<br />' + event.data;
    }

    function onOpen(event) {
      document.getElementById('messages').innerHTML 
        = 'Connection established';
    }

    function onError(event) {
      alert(event.data);
    }

    function start() {
      webSocket.send('hello');
      return false;
    }
  </script>
</body>
</html>

這是一個簡單的頁面,包含有JavaScript代碼,這些代碼創建了一個websocket連接到websocket服務器端。

onOpen 我們創建一個連接到服務器的連接時將會調用此方法。

onError 當客戶端-服務器通信發生錯誤時將會調用此方法。

onMessage 當從服務器接收到一個消息時將會調用此方法。在我們的例子中,我們只是將從服務器獲得的消息添加到DOM。

我們連接到websocket 服務器端,使用構造函數 new WebSocket() 而且傳之以端點URL:

ws://localhost:8080/byteslounge/websocket

4. Testing

We may now test our application by accessing the testing page:

http://localhost:8080/byteslounge/page.html

We will see the Connection established message as expected:

http://localhost:8080/byteslounge/page.html

Now as soon as we press the button we will send the initial message to the server through the websocket and receive the subsequent test messages sent by the server:

Messages sent by the server and received by the client

譯者信息

4. 測試

現在我們可以訪問測試頁面對我們的應用進行測試:

http://localhost:8080/byteslounge/page.html

正如所期望的,我們將看到 Connection established 消息:

http://localhost:8080/byteslounge/page.html

現在只要我們一按按鈕,就會通過此websocket發送初始化報文給服務器,而且接下來會收到發自服務器的測試消息:

服務器發送、客戶端接收的消息

5. WebSockets Handshake

The TCP connection between the client and the server is established after the occurrence of a handshake over the HTTP protocol. It's easy to observe the handshake by using some HTTP traffic debugger. As soon as we create the WebSocket instance in the client the following request and respective server response will occur:

Note: we will only include HTTP headers that are relevant to the websockets handshake

Request:

GET /byteslounge/websocket HTTP/1.1 
Connection: Upgrade 
Upgrade: websocket 
Sec-WebSocket-Key: wVlUJ/tu9g6EBZEh51iDvQ==

Response:

HTTP/1.1 101 Web Socket Protocol Handshake 
Upgrade: websocket 
Sec-WebSocket-Accept: 2TNh+0h5gTX019lci6mnvS66PSY=

Note that the client is requesting the protocol to be upgraded to the WebSocket protocol by usingConnection: Upgrade and Upgrade: websocket HTTP headers. The server response states that the client request was accepted and it will change protocol to WebSocket (using HTTP status code 101):

HTTP/1.1 101 Web Socket Protocol Handshake

6. Downloadable sample

The example source code is available for download at the end of this page. The test was executed in Glassfish 4 (you will need a Java EE 7 compliant application server).

Download source code from this tutorial

譯者信息

5. WebSockets 握手

客戶端和服務器端TCP連接建立在HTTP協議握手發生之後。通過HTTP流量調試,很容易觀察到握手。客戶端一創建一個 WebSocket實例,就會出現如下請求和服務器端響應: 

注意: 我們只錄入了WebSocket握手所用到的HTTP頭。

請求:

GET /byteslounge/websocket HTTP/1.1 
Connection: Upgrade 
Upgrade: websocket 
Sec-WebSocket-Key: wVlUJ/tu9g6EBZEh51iDvQ==

響應:

HTTP/1.1 101 Web Socket Protocol Handshake 
Upgrade: websocket 
Sec-WebSocket-Accept: 2TNh+0h5gTX019lci6mnvS66PSY=

注意:進行連接需要將通過Upgrade and Upgrade將協議升級到支持websocket HTTP頭的Websocket協議。服務器響應表明請求被接受,協議將轉換到WebSocket協議(HTTP狀態碼101):

HTTP/1.1 101 Web Socket Protocol Handshake

6. 下載源碼

在本頁的末尾有範例源代碼下載鏈接,源碼在Glassfish 4(需要兼容Java EE 7的服務器)上通過測試。
在如下地址下載範例源碼:
發佈了35 篇原創文章 · 獲贊 9 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章