在本教程中,我們將藉助於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
注: Java EE 7中才引入了WebSocket。
2. WebSocket服務器端
讓我們定義一個 Java EE websocket服務器端:
WebSocketTest.java
01 |
package com.byteslounge.websockets; |
03 |
import java.io.IOException; |
05 |
import javax.websocket.OnClose; |
06 |
import javax.websocket.OnMessage; |
07 |
import javax.websocket.OnOpen; |
08 |
import javax.websocket.Session; |
09 |
import javax.websocket.server.ServerEndpoint; |
11 |
@ServerEndpoint ( "/websocket" ) |
12 |
public class WebSocketTest
{ |
15 |
public void onMessage(String
message, Session session) |
16 |
throws IOException,
InterruptedException { |
19 |
System.out.println( "Received:
" +
message); |
22 |
session.getBasicRemote().sendText( "This
is the first server message" ); |
26 |
while (sentMessages
< 3 ){ |
28 |
session.getBasicRemote(). |
29 |
sendText( "This
is an intermediate server message. Count: " |
35 |
session.getBasicRemote().sendText( "This
is the last server message" ); |
39 |
public void onOpen()
{ |
40 |
System.out.println( "Client
connected" ); |
44 |
public void onClose()
{ |
45 |
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
04 |
<title>Testing
websockets</title> |
08 |
<input
type= "submit" value= "Start" onclick= "start()" /> |
10 |
<div
id= "messages" ></div> |
11 |
<script
type= "text/javascript" > |
13 |
new WebSocket( 'ws://localhost:8080/byteslounge/websocket' ); |
15 |
webSocket.onerror
= function (event)
{ |
19 |
webSocket.onopen
= function (event)
{ |
23 |
webSocket.onmessage
= function (event)
{ |
27 |
function onMessage(event)
{ |
28 |
document.getElementById( 'messages' ).innerHTML |
29 |
+= '<br
/>' +
event.data; |
32 |
function onOpen(event)
{ |
33 |
document.getElementById( 'messages' ).innerHTML |
34 |
= 'Connection
established' ; |
37 |
function onError(event)
{ |
42 |
webSocket.send( 'hello' ); |
這是一個簡單的頁面,包含有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 消息:
http://localhost:8080/byteslounge/page.html
現在只要我們一按按鈕,就會通過此websocket發送初始化報文給服務器,而且接下來會收到發自服務器的測試消息:
服務器發送、客戶端接收的消息
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的服務器)上通過測試。