您好,登錄后才能下訂單哦!
WebSocket協(xié)議的作用是什么,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
WebSocket 是一種網(wǎng)絡(luò)通信協(xié)議。RFC6455 定義了它的通信標(biāo)準(zhǔn)。
WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協(xié)議。
了解計算機網(wǎng)絡(luò)協(xié)議的人,應(yīng)該都知道:HTTP 協(xié)議是一種無狀態(tài)的、無連接的、單向的應(yīng)用層協(xié)議。它采用了請求/響應(yīng)模型。通信請求只能由客戶端發(fā)起,服務(wù)端對請求做出應(yīng)答處理。
這種通信模型有一個弊端:HTTP 協(xié)議無法實現(xiàn)服務(wù)器主動向客戶端發(fā)起消息。
這種單向請求的特點,注定了如果服務(wù)器有連續(xù)的狀態(tài)變化,客戶端要獲知就非常麻煩。大多數(shù) Web 應(yīng)用程序?qū)⑼ㄟ^頻繁的異步 JavaScript 和 XML(AJAX)請求實現(xiàn)長輪詢。輪詢的效率低,非常浪費資源(因為必須不停連接,或者 HTTP 連接始終打開)。
因此,工程師們一直在思考,有沒有更好的方法。WebSocket 就是這樣發(fā)明的。WebSocket 連接允許客戶端和服務(wù)器之間進行全雙工通信,以便任一方都可以通過建立的連接將數(shù)據(jù)推送到另一端。WebSocket 只需要建立一次連接,就可以一直保持連接狀態(tài)。這相比于輪詢方式的不停建立連接顯然效率要大大提高。
既然是基于瀏覽器的web技術(shù),那么它的通信肯定少不了HTTP,websocket本身雖然也是一種新的應(yīng)用層協(xié)議,但是它也不能夠脫離HTTP而單獨存在。
具體來說,我們在客戶端構(gòu)建一個websocket實例,并且為它綁定一個需要連接到的服務(wù)器地址,當(dāng)客戶端連接到服務(wù)端的時候會向服務(wù)端發(fā)送一個類似下面的HTTP報文:
可以看到,這是一個HTTP的get請求報文,注意該報文中有一個upgrade首部,它的作用是告訴服務(wù)端需要將通信協(xié)議切換到websocket。如果服務(wù)端支持websocket協(xié)議,那么它就會將自己的通信協(xié)議切換到websocket,同時發(fā)給客戶端類似于以下的一個響應(yīng)報文頭:
返回的狀態(tài)碼為101,表示同意客戶端協(xié)議轉(zhuǎn)換請求,并將它轉(zhuǎn)換為websocket協(xié)議。以上過程都是利用HTTP通信完成的,稱之為websocket協(xié)議握手。
經(jīng)過這握手之后,客戶端和服務(wù)端就建立了websocket連接,以后的通信走的都是websocket協(xié)議了。所以總結(jié)為:websocket握手需要借助于HTTP協(xié)議,建立連接后通信過程使用websocket協(xié)議。
同時需要了解的是,該websocket連接還是基于我們剛才發(fā)起HTTP連接的那個TCP連接,一旦建立連接之后,我們就可以進行數(shù)據(jù)傳輸了。在websocket中,提供兩種數(shù)據(jù)傳輸:文本數(shù)據(jù)和二進制數(shù)據(jù)。
基于以上分析,我們可以看到,websocket能夠提供低延遲,高性能的客戶端和服務(wù)端的雙向數(shù)據(jù)通信。它顛覆了之前web開發(fā)的請求處理響應(yīng)模式,并且提供了一種真正意義上的客戶端請求,服務(wù)器推送數(shù)據(jù)的模式,特別適合實時數(shù)據(jù)交互應(yīng)用開發(fā)
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>菜鳥教程(runoob.com)</title> <script type="text/javascript"> WebSocketTest(); function WebSocketTest() { if ("WebSocket">
以下 API 用于創(chuàng)建 WebSocket 對象。
var Socket = new WebSocket(url, [protocol] );
以上代碼中的第一個參數(shù) url, 指定連接的 URL。第二個參數(shù) protocol 是可選的,指定了可接受的子協(xié)議。
以下是 WebSocket 對象的屬性。假定我們使用了以上代碼創(chuàng)建了 Socket 對象:
屬性 | 描述 |
---|---|
Socket.readyState | 只讀屬性 readyState 表示連接狀態(tài),可以是以下值:0 - 表示連接尚未建立。1 - 表示連接已建立,可以進行通信。2 - 表示連接正在進行關(guān)閉。3 - 表示連接已經(jīng)關(guān)閉或者連接不能打開。 |
Socket.bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,但是還沒有發(fā)出的 UTF-8 文本字節(jié)數(shù)。 |
以下是 WebSocket 對象的相關(guān)事件。假定我們使用了以上代碼創(chuàng)建了 Socket 對象:
事件 | 事件處理程序 | 描述 |
---|---|---|
open | Socket.onopen | 連接建立時觸發(fā) |
message | Socket.onmessage | 客戶端接收服務(wù)端數(shù)據(jù)時觸發(fā) |
error | Socket.onerror | 通信發(fā)生錯誤時觸發(fā) |
close | Socket.onclose | 連接關(guān)閉時觸發(fā) |
以下是 WebSocket 對象的相關(guān)方法。假定我們使用了以上代碼創(chuàng)建了 Socket 對象:
方法 | 描述 |
---|---|
Socket.send() | 使用連接發(fā)送數(shù)據(jù) |
Socket.close() | 關(guān)閉連接 |
WebSocket 服務(wù)端
package com.gaofei.servlet; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import com.gaofei.entry.MyMessageInbound; public class DemoServlet extends WebSocketServlet{ private static final long serialVersionUID = -4853540828121130946L; /* * (non-Javadoc) * 創(chuàng)建一個webSocekt對象,第一個參數(shù)表示協(xié)議,第二個參數(shù)httqrequest對象 * @see org.apache.catalina.websocket.WebSocketServlet#createWebSocketInbound(java.lang.String, javax.servlet.http.HttpServletRequest) * 返回一個綁定的消息 */ @Override protected StreamInbound createWebSocketInbound(String str,HttpServletRequest req) { System.out.println( req.getRemoteAddr()); System.out.println(str); return new MyMessageInbound(); } }
package com.gaofei.entry; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.WsOutbound; public class MyMessageInbound extends MessageInbound{ WsOutbound wsOutbount;//用于向客戶端發(fā)送數(shù)據(jù)對象 @Override protected void onBinaryMessage(ByteBuffer arg0) throws IOException {//接收數(shù)據(jù)觸發(fā),二進制消息文件 // TODO Auto-generated method stub } @Override protected void onTextMessage(CharBuffer message) throws IOException {//接收數(shù)據(jù)觸發(fā),文本消息文件 System.out.println("收到文本消息:"+message); int i=1; Long ms0=System.currentTimeMillis()/10000; for(;i>0;i++) { Long ms01=System.currentTimeMillis()/1000; Long ms01_0=ms01-ms0; if(ms01_0>10) { wsOutbount.writeTextMessage(CharBuffer.wrap(i+"來了")); //客戶端發(fā)送的數(shù)據(jù) ms0=System.currentTimeMillis()/1000; } } } @Override protected void onClose(int status) {//斷開連接觸發(fā) // TODO Auto-generated method stub super.onClose(status); System.out.println("斷開握手"); } @Override protected void onOpen(WsOutbound outbound) {//連接成功觸發(fā) super.onOpen(outbound); System.out.println("握手成功"); this.wsOutbount=outbound; try { this.wsOutbount.writeTextMessage(CharBuffer.wrap("你好??!")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
pom 配置文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>om.gaof.webSocketServer</groupId> <artifactId>webSocketServer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>7.0.39</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-coyote</artifactId> <version>7.0.39</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>websocketServer</finalName> <plugins> <!-- java編譯插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <!-- 指定端口 --> <port>8080</port> <!-- 請求路徑 --> <path>/</path> </configuration> </plugin> </plugins> </build> </project>
web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>wsServlet</servlet-name> <servlet-class>com.gaofei.servlet.DemoServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>wsServlet</servlet-name> <url-pattern>/wsServlet</url-pattern> </servlet-mapping> </web-app>
如果把 WebSocket 的通信看成是電話連接,Nginx 的角色則像是電話接線員,負責(zé)將發(fā)起電話連接的電話轉(zhuǎn)接到指定的客服。
Nginx 從 1.3 版開始正式支持 WebSocket 代理。如果你的 web 應(yīng)用使用了代理服務(wù)器 Nginx,那么你還需要為 Nginx 做一些配置,使得它開啟 WebSocket 代理功能。
以下為參考配置:
server { # this section is specific to the WebSockets proxying location /socket.io { proxy_pass http://app_server_wsgiapp/socket.io; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 600; } }
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。