Socket又稱"套接字",應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求。Socket的英文原義是「孔」或「插座」,做爲UNIX的進程通訊機制。Socket能夠實現應用程序間網絡通訊。javascript
Socket可使用TCP/IP協議或UDP協議。html
TCP/IP協議前端
TCP/IP協議是目前應用最爲普遍的協議,是構成Internet國際互聯網協議的最爲基礎的協議,由TCP和IP協議組成:
TCP協議:面向鏈接的、可靠的、基於字節流的傳輸層通訊協議,負責數據的可靠性傳輸的問題。java
IP協議:用於報文交換網絡的一種面向數據的協議,主要負責給每臺網絡設備一個網絡地址,保證數據傳輸到正確的目的地。web
UDP協議後端
UDP特色:無鏈接、不可靠、基於報文的傳輸層協議,優勢是發送後不用管,速度比TCP快。瀏覽器
B/S架構的系統多使用HTTP協議,HTTP協議的特色:安全
1 無狀態協議
2 用於經過 Internet 發送請求消息和響應消息
3 使用端口接收和發送消息,默認爲80端口
底層通訊仍是使用Socket完成。服務器
HTTP協議決定了服務器與客戶端之間的鏈接方式,沒法直接實現消息推送(F5已壞),一些變相的解決辦法:websocket
雙向通訊與消息推送
輪詢:客戶端定時向服務器發送Ajax請求,服務器接到請求後立刻返回響應信息並關閉鏈接。 優勢:後端程序編寫比較容易。 缺點:請求中有大半是無用,浪費帶寬和服務器資源。 實例:適於小型應用。
長輪詢:客戶端向服務器發送Ajax請求,服務器接到請求後hold住鏈接,直到有新消息才返回響應信息並關閉鏈接,客戶端處理完響應信息後再向服務器發送新的請求。 優勢:在無消息的狀況下不會頻繁的請求,耗費資小。 缺點:服務器hold鏈接會消耗資源,返回數據順序無保證,難於管理維護。 Comet異步的ashx,實例:WebQQ、Hi網頁版、Facebook IM。
長鏈接:在頁面裏嵌入一個隱蔵iframe,將這個隱蔵iframe的src屬性設爲對一個長鏈接的請求或是採用xhr請求,服務器端就能源源不斷地往客戶端輸入數據。 優勢:消息即時到達,不發無用請求;管理起來也相對便。 缺點:服務器維護一個長鏈接會增長開銷。 實例:Gmail聊天
Flash Socket:在頁面中內嵌入一個使用了Socket類的 Flash 程序JavaScript經過調用此Flash程序提供的Socket接口與服務器端的Socket接口進行通訊,JavaScript在收到服務器端傳送的信息後控制頁面的顯示。 優勢:實現真正的即時通訊,而不是僞即時。 缺點:客戶端必須安裝Flash插件;非HTTP協議,沒法自動穿越防火牆。 實例:網絡互動遊戲。
Websocket:
WebSocket是HTML5開始提供的一種瀏覽器與服務器間進行全雙工通信的網絡技術。依靠這種技術能夠實現客戶端和服務器端的長鏈接,雙向實時通訊。
特色:
事件驅動
異步
使用ws或者wss協議的客戶端socket
可以實現真正意義上的推送功能
缺點:
少部分瀏覽器不支持,瀏覽器支持的程度與方式有區別。
客戶端(Web主頁)代碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>WebSocket前端</title> </head> <body> Welcome<br/><input id="text" type="text"/> <button onclick="send()">發送消息</button> <hr/> <button onclick="closeWebSocket">關閉WebSocket</button> <hr/> <div id="message"></div> </body> <script type="text/javascript"> var websocket=null; //判斷當前瀏覽器是否支持WebSocket if('WebSocket' in window){ websocket=new WebSocket("ws://localhost:8080/websocket"); }else{ alert("當前瀏覽器 Not support websocket"); } //鏈接發生錯誤的回調方法 websocket.onerror=function(){ setMessageInnerHTML("WebSocket鏈接發生錯誤"); } //接收到消息的回調方法 websocket.onmessage=function (event) { setMessageInnerHTML(event.data); } //鏈接關閉的回調方法 websocket.onclose=function () { setMessageInnerHTML("WebSocket鏈接關閉"); } //監聽窗口關閉時間,當窗口關閉時,主動去關閉websocket鏈接,防止鏈接還沒斷開就關閉窗口,server端會拋出異常。 window.onbeforeprint=function () { closeWebSocket(); } //將消息顯示在網頁上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML+=innerHTML+'<br/>'; } //關閉WebSocket鏈接 function closeWebSocket() { websocket.close(); } //發送消息 function send() { var message=document.getElementById('text').value; websocket.send(message); } </script> </html>
後臺代碼:
package com; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; @ServerEndpoint("/websocket") public class WebSocketTest { //靜態變量,用來記錄當前在線鏈接數。應該把它設計成線程安全的。 private static int onlineCount = 0; //concurrent包的線程安全Set,用來存放每一個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通訊的話,可使用Map來存放,其中Key能夠爲用戶標識 private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>(); //與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據 private Session session; /** * 鏈接創建成功調用的方法 * @param session 可選的參數。session爲與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據 */ @OnOpen public void onOpen(Session session){ this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在線數加1 System.out.println("有新鏈接加入!當前在線人數爲" + getOnlineCount()); } /** * 鏈接關閉調用的方法 */ @OnClose public void onClose(){ webSocketSet.remove(this); //從set中刪除 subOnlineCount(); //在線數減1 System.out.println("有一鏈接關閉!當前在線人數爲" + getOnlineCount()); } /** * 收到客戶端消息後調用的方法 * @param message 客戶端發送過來的消息 * @param session 可選的參數 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("來自客戶端的消息:" + message); //羣發消息 for(WebSocketTest item: webSocketSet){ try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); continue; } } } /** * 發生錯誤時調用 * @param session * @param error */ @OnError public void onError(Session session, Throwable error){ System.out.println("發生錯誤"); error.printStackTrace(); } /** * 這個方法與上面幾個方法不同。沒有用註解,是根據本身須要添加的方法。 * @param message * @throws IOException */ public void sendMessage(String message) throws IOException{ this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketTest.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketTest.onlineCount--; } }