Java EE HTML5 WebSocket 示例
在本教程中,我們將借助于Java EE的WebSocket(服務器端)實現一個HTML5的WebSocket連接。
1. 介紹
HTML5給Web瀏覽器帶來了全雙工TCP連接websocket標準服務器的能力。
換句話說,瀏覽器能夠與服務器建立連接,通過已建立的通信信道來發送和接收數據而不需要由HTTP協議引入額外其他的開銷來實現。
在本教程中我們將在Java EE環境下實現一個簡單的websockect服務器端來和客戶端進行數據交互。
本教程需要以下環境:
- Ubuntu 12.04
- JDK 1.7.0.21
- Glassfish 4.0
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. 客戶端
現在我們要來寫websocket測試應用的客戶端:
page.html
<!DOCTYPE html> <html> <head> <title>Testing websockets</title> </head> <body> <div> <input type="submit" value="Start" onclick="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. 測試
現在我們可以訪問測試頁面對我們的應用進行測試:
http://localhost:8080/byteslounge/page.html
正如所期望的,我們將看到 Connection established 消息:

現在只要我們一按按鈕,就會通過此websocket發送初始化報文給服務器,而且接下來會收到發自服務器的測試消息:
5. WebSockets 握手
客戶端和服務器端TCP連接建立在HTTP協議握手發生之后。通過HTTP流量調試,很容易觀察到握手。客戶端一創建一個 WebSocket實例,就會出現如下請求和服務器端響應:注意: 我們只錄入了WebSocket握手所用到的HTTP頭。
請求:
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: wVlUJ/tu9g6EBZEh51iDvQ==
響應:
Upgrade: websocket
Sec-WebSocket-Accept: 2TNh+0h5gTX019lci6mnvS66PSY=
注意:進行連接需要將通過Upgrade and Upgrade將協議升級到支持websocket HTTP頭的Websocket協議。服務器響應表明請求被接受,協議將轉換到WebSocket協議(HTTP狀態碼101):
HTTP/1.1 101 Web Socket Protocol Handshake