1、簡介
作為下一代的Web標準,HTML5擁有許多引人注目的新特性,如 Canvas、本地存儲、多媒體編程接口、WebSocket等等。這其中有“Web的 TCP”之稱的 WebSocket格外吸引開發人員的注意。WebSocket的出現使得瀏覽器提供對 Socket的支持成為可能,從而在瀏覽器和服務器之間提供了一個基于TCP連接的雙向通道。Web開發人員可以非常方便地使用WebSocket構建實時 web 應用,開發人員的手中從此又多了一柄神兵利器。
Web 應用的信息交互過程通常是客戶端通過瀏覽器發出一個請求,服務器端接收和審核完請求后進行處理并返回結果給客戶端,然后客戶端瀏覽器將信息呈現出來,這種機制對于信息變化不是特別頻繁的應用尚能相安無事,但是對于那些實時要求比較高的應用來說,比如說在線游戲、在線證券、設備監控、新聞在線播報、RSS訂閱推送等等,當客戶端瀏覽器準備呈現這些信息的時候,這些信息在服務器端可能已經過時了。
所以保持客戶端和服務器端的信息同步是實時 Web應用的關鍵要素,對 Web開發人員來說也是一個難題。在 WebSocket規范出來之前,開發人員想實現這些實時的Web應用,不得不采用一些折衷的方案,其中最常用的就是輪詢(Polling)和 Comet 技術,而Comet技術實際上是輪詢技術的改進,又可細分為兩種實現方式,一種是長輪詢機制,一種稱為流技術。
Html5 WebSocket 設計出來的目的就是要取代輪詢和 Comet技術,使客戶端瀏覽器具備像 C/S架構下桌面系統的實時通訊能力。瀏覽器通過JavaScript向服務器發出建立 WebSocket連接的請求,連接建立以后,客戶端和服務器端就可以通過 TCP連接直接交換數據。因為 WebSocket連接本質上就是一個TCP連接,所以在數據傳輸的穩定性和數據傳輸量的大小方面,和輪詢以及Comet技術比較,具有很大的性能優勢。
但是鑒于web socket 對瀏覽器要求比較高,為了解決這個問題,推出了sockJS,SockJS是一個JavaScript庫,提供跨瀏覽器javascript的API,創建了一個低延遲、全雙工的瀏覽器和web服務器之間通信通道。
2、相關環境要求
Spring4.0.6(要選擇4.0+),tomcat7.0.55版本,JDK1.7。
3、具體代碼
(以下代碼親測可用!)
(1)web.xml:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<? xmlversionxmlversion = "1.0" encoding = "UTF-8" ?> < web-app version = "3.1" xmlns = "http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" > < description >用來測試WebSocket基礎上推送的功能</ description > < distributable /> < filter > < filter-name >encodingFilter</ filter-name > < filter-class >org.springframework.web.filter.CharacterEncodingFilter</ filter-class > < async-supported >true</ async-supported > < init-param > < param-name >encoding</ param-name > < param-value >UTF-8</ param-value > </ init-param > < init-param > < param-name >forceEncoding</ param-name > < param-value >true</ param-value > </ init-param > </ filter > < filter-mapping > < filter-name >encodingFilter</ filter-name > < url-pattern >/*</ url-pattern > </ filter-mapping > < listener > < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class > </ listener > <!-- Spring 刷新Introspector防止內存泄露 --> < listener > < listener-class >org.springframework.web.util.IntrospectorCleanupListener</ listener-class > </ listener > < servlet > < servlet-name >dispatcher</ servlet-name > < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > < init-param > < param-name >contextConfigLocation</ param-name > < param-value >classpath:dispatcher-servlet.xml</ param-value > </ init-param > < load-on-startup >1</ load-on-startup > < async-supported >true</ async-supported > </ servlet > < servlet-mapping > < servlet-name >dispatcher</ servlet-name > < url-pattern >/</ url-pattern > </ servlet-mapping > < session-config > < session-timeout > 30 </ session-timeout > </ session-config > < welcome-file-list > < welcome-file >testSocket.jsp</ welcome-file > </ welcome-file-list > </ web-app > |
(2) dispatcher-servlet.xml
1
2
3
4
5
6
7
8
9
10
11
12
|
<? xmlversionxmlversion = "1.0" encoding = "UTF-8" ?> < beans:beansxmlnsbeans:beansxmlns = "http://www.springframework.org/schema/mvc" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:beans = "http://www.springframework.org/schema/beans" xmlns:context = "http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> < annotation-driven /> <!-- 自動掃描的包名 --> < context:component-scanbase-packagecontext:component-scanbase-package = "zyy.sockjs.config" ></ context:component-scan > </ beans:beans > |
(3)HandshakeInterceptor.java
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 zyy.sockjs.config; import java.util.Map; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; @Component public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { System.out.println( "Before Handshake" ); return super .beforeHandshake(request,response,wsHandler,attributes); } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { System.out.println( "After Handshake" ); super .afterHandshake(request,response,wsHandler,ex); } } |
(4)InfoSocketEndPoint.Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package zyy.sockjs.config; import org.springframework.stereotype.Component; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; @Component public class InfoSocketEndPoint extends TextWebSocketHandler { public InfoSocketEndPoint() { } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super .handleTextMessage(session, message); TextMessage returnMessage = new TextMessage(message.getPayload() + " received at server" ); session.sendMessage(returnMessage); } } |
(5)SystemWebSocketHandler.java
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package zyy.sockjs.config; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; /** * * @author dayu */ @Component public class SystemWebSocketHandler implements WebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println( "connect to the websocket success......" ); session.sendMessage( new TextMessage( "Server:connected OK!" )); } @Override public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception { TextMessage returnMessage = new TextMessage(wsm.getPayload() + " received at server" ); wss.sendMessage(returnMessage); } @Override public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception { if (wss.isOpen()){ wss.close(); } System.out.println( "websocket connection closed......" ); } @Override public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception { System.out.println( "websocket connection closed......" ); } @Override public boolean supportsPartialMessages() { return false ; } } |
(6)WebSocketConfig.java
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
27
28
29
30
31
|
package zyy.sockjs.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebMvc @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { public WebSocketConfig() { } @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(systemWebSocketHandler(), "/websck" ).addInterceptors( new HandshakeInterceptor()); System.out.println( "registed!" ); registry.addHandler(systemWebSocketHandler(), "/sockjs/websck/info" ).addInterceptors( new HandshakeInterceptor()) .withSockJS(); } @Bean public WebSocketHandler systemWebSocketHandler() { return new SystemWebSocketHandler(); } } |
(7)testSocket.jsp
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
<%@ page language= "java" contentType= "text/html; charset=ISO-8859-1" pageEncoding= "ISO-8859-1" %> <!DOCTYPE htmlPUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <meta http-equiv= "Content-Type" content= "text/html; charset=ISO-8859-1" > <title>WebSocket/SockJS Echo Sample (Adapted from Tomcat 's echo sample)</title> <style type="text/css"> #connect-container { float: left; width: 400px } #connect-container div { padding: 5px; } #console-container { float: left; margin-left: 15px; width: 400px; } #console { border:1px solid #CCCCCC; border-right-color:#33333333; border-bottom-color:#999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } #console p { padding: 0; margin: 0; } </style> <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> <script type="text/javascript"> var ws = null; var url = null; var transports = []; function setConnected(connected) { document.getElementById(' connect ').disabled = connected; document.getElementById(' disconnect ').disabled = !connected; document.getElementById(' echo ').disabled = !connected; } function connect() { if (!url) { log(' Select whether to use W3C WebSocket or SockJS '); return; } //ws = (url.indexOf(' sockjs ') != -1) ?new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url); if (' WebSocket 'in window) { ws= new WebSocket("ws://localhost:8080/SpringSocketJs/websck"); }else { ws = new SockJS("http://localhost:8080/SpringSocketJs/sockjs/websck/info"); } //websocket = new SockJS("http://localhost:8084/SpringWebSocketPush/sockjs/websck"); ws.onopen = function () { setConnected(true); //log(' Info: connection opened. '); }; ws.onmessage = function (event) { log(' Received: ' + event.data); }; ws.onclose = function (event) { setConnected(false); log(' Info: connection closed. '); log(event); }; } function disconnect() { if (ws != null) { ws.close(); ws = null; } setConnected(false); } function echo() { if (ws != null) { var message = document.getElementById(' message ').value; log(' Sent: ' + message); ws.send(message); } else { alert(' connection not established, please connect. '); } } function updateUrl(urlPath) { if (urlPath.indexOf(' sockjs ') != -1) { url = urlPath; document.getElementById(' sockJsTransportSelect ').style.visibility =' visible '; } else { if (window.location.protocol ==' http: ') { url = ' ws: //' + window.location.host + urlPath; } else { url = 'wss: //' + window.location.host + urlPath; } document.getElementById('sockJsTransportSelect ').style.visibility =' hidden '; } } function updateTransport(transport) { transports = (transport == ' all ') ? [] : [transport]; } function log(message) { var console = document.getElementById(' console '); var p = document.createElement(' p '); p.style.wordWrap = ' break -word '; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; } </script> </head> <body> <noscript><h2 style="color:#ff0000">Seems your browser doesn' t supportJavascript!Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!</h2></noscript> <div> <div id= "connect-container" > <input id= "radio1" type= "radio" name= "group1" onclick= "updateUrl('/SpringSocketJs/websocket');" > <label for = "radio1" >W3C WebSocket</label> <br> <input id= "radio2" type= "radio" name= "group1" onclick= "updateUrl('/SpringSocketJs/sockjs/websocket');" > <label for = "radio2" >SockJS</label> <div id= "sockJsTransportSelect" style= "visibility:hidden;" > SockJS transport: <select onchange= "updateTransport(this.value)" > <option value= "all" >all</option> <option value= "websocket" >websocket</option> <option value= "xhr-polling" >xhr-polling</option> <option value= "jsonp-polling" >jsonp-polling</option> <option value= "xhr-streaming" >xhr-streaming</option> <option value= "iframe-eventsource" >iframe-eventsource</option> <option value= "iframe-htmlfile" >iframe-htmlfile</option> </select> </div> <div> <button id= "connect" onclick= "connect();" >Connect</button> <button id= "disconnect" disabled= "disabled" onclick= "disconnect();" >Disconnect</button> </div> <div> <textarea id= "message" style= "width:350px" >Here is a message!</textarea> </div> <div> <button id= "echo" onclick= "echo();" disabled= "disabled" >Echo message</button> </div> </div> <div id= "console-container" > <div id= "console" ></div> </div> </div> </body> </html> |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/u011991249/article/details/51472020