第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

websocket

網(wǎng)頁中的絕大多數(shù)請求使用的是 HTTP 協(xié)議,HTTP 是一個(gè)無狀態(tài)的應(yīng)用層協(xié)議,它有著即開即用的優(yōu)點(diǎn),每次請求都是相互獨(dú)立的,這對于密集程度較低的網(wǎng)絡(luò)請求來說是優(yōu)點(diǎn),因?yàn)闊o需創(chuàng)建請求的上下文條件,但是對于密集度或者實(shí)時(shí)性要求較高的網(wǎng)絡(luò)請求(例如 IM 聊天)場景來說,可能 HTTP 會(huì)力不從心,因?yàn)槊縿?chuàng)建一個(gè) HTTP 請求對服務(wù)器來說都是一個(gè)很大的資源開銷。這時(shí)我們可以考慮一個(gè)相對性能較高的網(wǎng)絡(luò)協(xié)議 Socket,他的網(wǎng)頁版本被稱為 Websocket。

1. 背景

近年來,隨著 HTML5 和 w3c 的推廣開來,WebSocket 協(xié)議被提出,它實(shí)現(xiàn)了瀏覽器與服務(wù)器的實(shí)時(shí)通信,使服務(wù)端也能主動(dòng)向客戶端發(fā)送數(shù)據(jù)。在 WebSocket 協(xié)議提出之前,開發(fā)人員若要實(shí)現(xiàn)這些實(shí)時(shí)性較強(qiáng)的功能,經(jīng)常會(huì)使用一種替代性的解決方案——輪詢。

輪詢的原理是采用定時(shí)的方式不斷的向服務(wù)端發(fā)送 HTTP 請求,頻繁地請求數(shù)據(jù)。明顯地,這種方法命中率較低,浪費(fèi)服務(wù)器資源。伴隨著 WebSocket 協(xié)議的推廣,真正實(shí)現(xiàn)了 Web 的即時(shí)通信。

WebSocket 的原理是通過 JavaScript 向服務(wù)端發(fā)出建立 WebSocket 連接的請求,在 WebSocket 連接建立成功后,客戶端和服務(wù)端可以實(shí)現(xiàn)一個(gè)長連接的網(wǎng)絡(luò)管道。因?yàn)?WebSocket 本質(zhì)上是 TCP 連接,它是一個(gè)長連接,除非斷開連接否則無需重新創(chuàng)建連接,所以其開銷相對 HTTP 節(jié)省了很多。

2. API

2.1 創(chuàng)建連接

通過使用新建一個(gè) websocket 對象的方式創(chuàng)建一個(gè)新的連接,不過在創(chuàng)建之前需要檢測一下瀏覽器是否支持 Websocket,因?yàn)橹挥兄С?HTML5 的瀏覽器才能支持 Websocket,如下:

if(typeof window.WebSocket == 'function'){
    var ws = new WebSocket('http://127.0.0.1:8003');//創(chuàng)建基于本地的8003端口的websocket連接
}else alert("您的瀏覽器不支持websocket");

上述代碼會(huì)對本地的 8003 接口請求 Websocket 連接,前提是本地的服務(wù)器有進(jìn)程監(jiān)聽 8003 端口,不然的話會(huì)連接失敗。

2.2 創(chuàng)建成功

由于 JavaScript 的各種 IO 操作是基于事件回調(diào)的,所以 Websocket 也不例外,我們需要?jiǎng)?chuàng)建一個(gè)連接成功的回調(diào)函數(shù)來處理連接創(chuàng)建成功之后的業(yè)務(wù)處理,如下:

ws.onopen = function(){//通過監(jiān)聽 open 時(shí)間來做創(chuàng)建成功的回調(diào)處理
    console.log('websocket連接創(chuàng)建成功')
    //進(jìn)行業(yè)務(wù)處理
}

2.3 接收消息

我們辛辛苦苦創(chuàng)建了長連接就是為了發(fā)送或者接收網(wǎng)絡(luò)數(shù)據(jù),那么怎么接收呢,跟上邊提到的意義,還是需要在回調(diào)函數(shù)里處理,一不小心就陷入了回調(diào)地獄了:

ws.onmessage = function(event){
    var d = event.data;
    //接收到消息之后的業(yè)務(wù)處理
    switch(typeof d){//判斷數(shù)據(jù)的類型格式
    case "String":
        break;
    case "blob":
        break;
    case "ArrayBuffer":
        break;
    default:
        return;
    }
} 

上述實(shí)例通過監(jiān)聽 message 事件對 websocket 的消息進(jìn)行一定的業(yè)務(wù)處理,這其中需要判斷數(shù)據(jù)類型格式,因?yàn)?Websocket 是基于二進(jìn)制流格式的,傳輸過來的消息可能不一定是基于 utf8 的字符串格式,因此需要對格式進(jìn)行判斷。

2.4 發(fā)送消息

客戶端通過使用 send 函數(shù)向服務(wù)端發(fā)送數(shù)據(jù),例如:

ws.send("一段測試消息");

可以發(fā)送文本格式,也可以發(fā)送二進(jìn)制格式,例如:

var input  = document.getElementById("file"); 
input.onchange = function(){
    var file = this.files[0];
    if(!!file){
        //讀取本地文件,以gbk編碼方式輸出
        var reader = new FileReader();
        reader.readAsBinaryString(file);
        reader.onload = function(){
            //讀取完畢后發(fā)送消息
            ws.send(this.result);
        }
    }
}

2.5 監(jiān)聽錯(cuò)誤信息

類似上述提到的如果創(chuàng)建實(shí)例失敗的情況,系統(tǒng)會(huì)出現(xiàn)異常,但是我們并不能準(zhǔn)確判斷出異常的信息,這時(shí)需要通過監(jiān)聽錯(cuò)誤事件來獲取報(bào)錯(cuò)信息,例如:

ws.onerror = function(event){
    //這里處理錯(cuò)誤信息
}

2.6 關(guān)閉連接

當(dāng)服務(wù)端或者客戶端關(guān)閉 websocket 連接時(shí),系統(tǒng)會(huì)觸發(fā)一個(gè)關(guān)閉事件,例如:

ws.onclose = function (event){
    //這里處理關(guān)閉之后的業(yè)務(wù)
}

2.7 連接的狀態(tài)

通過 websocket 對象的 readyState 屬性可以獲取到當(dāng)前連接的狀態(tài),其中常用的有4種,通過 websocket 對象的幾種定義常量對比判斷:

switch (ws.readyState){
    case WebSocket.CONNECTING:break;//處于正在連接中的狀態(tài)
    case WebSocket.OPEN:break;//表示已經(jīng)連接成功
    case WebSocket.CLOSING:break;//表示連接正在關(guān)閉
    case WebSocket.CLOSE:break;//表示連接已經(jīng)關(guān)閉,或者創(chuàng)建連接失敗
    default:break;
}

3. websocket 實(shí)例

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <style>
        p {
            text-align: left;
            padding-left: 20px;
        }
    </style>
</head>
<body>
<div style="width: 700px;height: 500px;margin: 30px auto;text-align: center">
    <h1>聊天室實(shí)戰(zhàn)</h1>
    <div style="width: 700px;border: 1px solid gray;height: 300px;">
        <div style="width: 200px;height: 300px;float: left;text-align: left;">
            <p><span>當(dāng)前在線:</span><span id="user_num">0</span></p>
            <div id="user_list" style="overflow: auto;">

            </div>
        </div>
        <div id="msg_list" style="width: 598px;border:  1px solid gray; height: 300px;overflow: scroll;float: left;">
        </div>
    </div>
    <br>
    <textarea id="msg_box" rows="6" cols="50" onkeydown="confirm(event)"></textarea><br>
    <input type="button" value="發(fā)送" onclick="send()">
</div>
</body>
</html>

<script type="text/javascript">
    var uname = window.prompt('請輸入用戶名', 'user' + uuid(8, 16));
    var ws = new WebSocket("ws://127.0.0.1:8081");
    ws.onopen = function () {
        var data = "系統(tǒng)消息:連接成功";
        listMsg(data);
    };
    ws.onmessage = function (e) {
        var msg = JSON.parse(e.data);
        var data =  msg.content;
        listMsg(data);
    };

    ws.onerror = function () {
        var data = "系統(tǒng)消息 : 出錯(cuò)了,請退出重試.";
        listMsg(data);
    };

    function confirm(event) {
        var key_num = event.keyCode;
        if (13 == key_num) {
            send();
        } else {
            return false;
        }
    }

    /**
     * 發(fā)送并清空消息輸入框內(nèi)的消息
     */
    function send() {
        var msg_box = document.getElementById("msg_box");
        var content = msg_box.value;
        var reg = new RegExp("\r\n", "g");
        content = content.replace(reg, "");
        var msg = {'content': content.trim(), 'type': 'user'};
        sendMsg(msg);
        msg_box.value = '';
    }

    /**
     * 將消息內(nèi)容添加到輸出框中,并將滾動(dòng)條滾動(dòng)到最下方
     */
    function listMsg(data) {
        var msg_list = document.getElementById("msg_list");
        var msg = document.createElement("p");

        msg.innerHTML = data;
        msg_list.appendChild(msg);
        msg_list.scrollTop = msg_list.scrollHeight;
    }

    /**
     * 將數(shù)據(jù)轉(zhuǎn)為json并發(fā)送
     * @param msg
     */
    function sendMsg(msg) {
        var data = JSON.stringify(msg);
        ws.send(data);
    }
</script>
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

上述實(shí)例通過使用 websocket 實(shí)現(xiàn)了一個(gè)簡單的聊天室功能,功能上只實(shí)現(xiàn)了接受和發(fā)送消息的功能,在登錄認(rèn)證和安全性等問題上并沒有做過多的處理,只是為了給大家連貫的展示一下 websocket 在實(shí)際項(xiàng)目中的使用。

4. 注意事項(xiàng)

實(shí)際項(xiàng)目中使用 websocket 需要注意一些問題 :

  • websocket 創(chuàng)建之前需要使用 HTTP 協(xié)議進(jìn)行一次握手請求,服務(wù)端正確回復(fù)相應(yīng)的請求之后才能創(chuàng)建 websocket 連接;
  • 創(chuàng)建 websocket 時(shí)需要進(jìn)行一些類似 token 之類的登錄認(rèn)證,不然任何客戶端都可以向服務(wù)器進(jìn)行 websocket 連接;
  • websocket 是明文傳輸,敏感的數(shù)據(jù)需要進(jìn)行加密處理;
  • 由于 websocket 是長連接,當(dāng)出現(xiàn)異常時(shí)連接會(huì)斷開,服務(wù)端的進(jìn)程也會(huì)丟失,所以服務(wù)端最好有守護(hù)進(jìn)程進(jìn)行監(jiān)控重啟;
  • 服務(wù)器監(jiān)聽的端口最好使用非系統(tǒng)性且不常使用的端口,不然可能會(huì)導(dǎo)致端口沖突

5. 小結(jié)

本章介紹了 websocket 的前世今生,詳細(xì)說明其對應(yīng)的 API 的調(diào)用方式,最后使用了一個(gè)簡單的聊天室的例子來對其函數(shù)串通了一下,最后延伸了一下實(shí)際項(xiàng)目中使用 websocket 需要注意的地方,希望大家在實(shí)際開發(fā)中針對其優(yōu)缺點(diǎn)來選擇合適的使用場景。