B/S結構的軟件項目中有時客戶端需要實時的獲得服務器消息,但默認HTTP協議只支持請求響應模式,這樣做可以簡化Web服務器,減少服務器的負擔,加快響應速度,因為服務器不需要與客戶端長時間建立一個通信鏈接,但不容易直接完成實時的消息推送功能,如聊天室、後台信息提示、實時更新數據等功能,但通過polling、Long polling、長連接、Flash Socket以及HTML5中定義的WebSocket能完成該功能需要。
Socket又稱"套接字",應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。Socket的英文原義是“孔”或“插座”,作為UNIX的進程通信機制。Socket可以實現應用程序間網絡通信。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>WebSocket 客戶端</title>
</head>
<body>
<div>
<input type="button" id="btnConnection" value="連接" />
<input type="button" id="btnClose" value="關閉" />
<input type="button" id="btnSend" value="發送" />
</div>
<script src="js/jquery-1.11.1.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var socket;
if(typeof(WebSocket) == "undefined") {
alert("您的浏覽器不支持WebSocket");
return;
}
$("#btnConnection").click(function() {
//實現化WebSocket對象,指定要連接的服務器地址與端口
socket = new WebSocket("ws://192.168.1.2:8888");
//打開事件
socket.onopen = function() {
alert("Socket 已打開");
//socket.send("這是來自客戶端的消息" + location.href + new Date());
};
//獲得消息事件
socket.onmessage = function(msg) {
alert(msg.data);
};
//關閉事件
socket.onclose = function() {
alert("Socket已關閉");
};
//發生了錯誤事件
socket.onerror = function() {
alert("發生了錯誤");
}
});
//發送消息
$("#btnSend").click(function() {
socket.send("這是來自客戶端的消息" + location.href + new Date());
});
//關閉
$("#btnClose").click(function() {
socket.close();
});
</script>
</body>
</html>
JSR356定義了WebSocket的規范,Tomcat7中實現了該標准。JSR356 的 WebSocket 規范使用 javax.websocket.*的 API,可以將一個普通 Java 對象(POJO)使用 @ServerEndpoint 注釋作為 WebSocket 服務器的端點。
@ServerEndpoint("/push") public class EchoEndpoint { @OnOpen public void onOpen(Session session) throws IOException { //以下代碼省略... } @OnMessage public String onMessage(String message) { //以下代碼省略... } @Message(maxMessageSize=6) public void receiveMessage(String s) { //以下代碼省略... } @OnError public void onError(Throwable t) { //以下代碼省略... } @OnClose public void onClose(Session session, CloseReason reason) { //以下代碼省略... } }
上面簡潔代碼即建立了一個WebSocket的服務端,@ServerEndpoint("/push")的annotation注釋端點表示將WebSocket服務端運行在ws://[Server端IP或域名]:[Server端口]/項目/push的訪問端點,客戶端浏覽器已經可以對WebSocket客戶端API發起HTTP長連接了。
使用ServerEndpoint注釋的類必須有一個公共的無參數構造函數,@onMessage注解的Java方法用於接收傳入的WebSocket信息,這個信息可以是文本格式,也可以是二進制格式。
OnOpen在這個端點一個新的連接建立時被調用。參數提供了連接的另一端的更多細節。Session表明兩個WebSocket端點對話連接的另一端,可以理解為類似HTTPSession的概念。
OnClose在連接被終止時調用。參數closeReason可封裝更多細節,如為什麼一個WebSocket連接關閉。
更高級的定制如@Message注釋,MaxMessageSize屬性可以被用來定義消息字節最大限制,在示例程序中,如果超過6個字節的信息被接收,就報告錯誤和連接關閉。
package action; import javax.websocket.CloseReason; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; //ws://127.0.0.1:8087/Demo1/ws/張三 @ServerEndpoint("/ws/{user}") public class WSServer { private String currentUser; //連接打開時執行 @OnOpen public void onOpen(@PathParam("user") String user, Session session) { currentUser = user; System.out.println("Connected ... " + session.getId()); } //收到消息時執行 @OnMessage public String onMessage(String message, Session session) { System.out.println(currentUser + ":" + message); return currentUser + ":" + message; } //連接關閉時執行 @OnClose public void onClose(Session session, CloseReason closeReason) { System.out.println(String.format("Session %s closed because of %s", session.getId(), closeReason)); } //連接錯誤時執行 @OnError public void onError(Throwable t) { t.printStackTrace(); } }
url中的字符張三是的路徑參數,響應請求的方法將自動映射。
Socket在應用程序間通信被廣泛使用,如果需要兼容低版本的浏覽器,建議使用反向ajax或長鏈接實現;如果純移動端或不需考慮非現代浏覽器則可以直接使用websocket。Flash實現推送消息的方法不建議使用,因為依賴插件且手機端支持不好。關於反向ajax也有一些封裝好的插件如“Pushlet”
Pushlet 是一個開源的 Comet 框架,Pushlet 使用了觀察者模型:客戶端發送請求,訂閱感興趣的事件;服務器端為每個客戶端分配一個會話 ID 作為標記,事件源會把新產生的事件以多播的方式發送到訂閱者的事件隊列裡。
源碼地址:https://github.com/wjw465150/Pushlet
Pushlet是一種comet實現:在Servlet機制下,數據從server端的Java對象直接推送(push)到(動態)HTML頁面,而無需任何Javaapplet或者插件的幫助。它使server端可以周期性地更新client的web頁面,這與傳統的request/response方式相悖。浏覽器client為兼容JavaScript1.4版本以上的浏覽器(如InternetExplorer、FireFox),並使用JavaScript/DynamicHTML特性。而底層實現使用一個servlet通過Http連接到JavaScript所在的浏覽器,並將數據推送到後者。
SignalR是一個ASP .NET下的類庫,可以在ASP .NET的Web項目中實現實時通信。在Web網頁與服務器端間建立Socket連接,當WebSockets可用時(即浏覽器支持Html5)SignalR使用WebSockets,當不支持時SignalR將使用長輪詢來保證達到相同效果。
官網:http://signalr.net/
源碼:https://github.com/SignalR/SignalR
點擊下載服務器端代碼
點擊下載客戶端代碼
點擊下載DotNet服務器端手動連接實現代碼
點擊下載DotNet下使用SuperWebSocket三方庫實現代碼