WebSocket網絡通訊協議

上一篇文章簡要的介紹了一下http協議,此次再介紹一下WebSocket協議,二者之間有很大的區別,WebSocket協議是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。html

簡單的理解一下什麼是雙工通信協議,以前有講過http協議只能客戶端向服務端發起請求,是單向的應用層協議。而雙工通信協議,不只客戶端能向服務端發起請求,服務端也能夠主動推送信息給客戶端。node

目的:即時通信,替代輪詢

WebSocket 協議在2008年誕生,2011年成爲國際標準。全部瀏覽器都已經支持了。ios

相比於http協議,websoket協議給咱們帶來了極大的方便,舉個例子:git

以前,咱們在作消息通知的時候,須要設置定時器,頻繁的向後臺發起異步ajax請求實現長輪詢,獲取最新的數據,這樣效率很是低,很是浪費資源,由於不停的發起http請求,不停的與服務端創建鏈接,或者http連接始終打開。
而如今有了websocket,就解決了輪詢的問題,websocket只須要創建一次鏈接,就能夠保持長久鏈接,相比輪詢不停的創建鏈接,大大的提高了效率,這樣只要服務端有數據變化,就能夠當即通知前臺了。github

websocket協議與http協議之間的關係

首先HTTP有 1.1 和 1.0 之說,也就是所謂的 keep-alive ,把多個HTTP請求合併爲一個,可是 Websocket 實際上是一個新協議,跟HTTP協議基本沒有關係,只是爲了兼容現有瀏覽器的握手規範而已,也就是說它是HTTP協議上的一種補充,Websocket是借用了HTTP的協議來完成一部分握手。web

websocket有如下特色:ajax

  • 創建在 TCP 協議之上,服務器端的實現比較容易。
  • 與 HTTP 協議有着良好的兼容性。默認端口也是80和443,而且握手階段採用 HTTP 協議,所以握手時不容易屏蔽,能經過各類 HTTP
    代理服務器。
  • 屬於長鏈接(http協議無狀態)
  • 雙向通訊(http是單向通訊)
  • 能夠跨域,不受瀏覽器同源策略的限制(http協議不可跨域)
  • 數據格式比較輕量,性能開銷小,通訊高效
  • 能夠發送文本,也能夠發送二進制數據。
  • 協議標識符是ws(若是加密,則爲wss),服務器網址就是 URL。如:ws://example.com:80/some/path

websocket協議應用

目前websocket對大部分瀏覽器有很好的兼容,但對於IE10如下的瀏覽器沒法兼容。爲了解決兼容性,Socket.IO就出現了。
Socket.IO是一個基於Nodejs的,用於實時通訊的一個軟件包(包括client端和server端),Socket.IO徹底由JavaScript實現。
平時在應用的時候,能夠直接引入socket.io這個庫就能夠了。先後臺都須要引用該庫。express

下面針對nodejs的服務端如何使用舉個例子:跨域

服務端代碼:瀏覽器

const http = require('http');
const fs = require('fs');
const express = require('express');
const io = require('socket.io');


const app = express();

const httpServer = http.createServer(app);
app.use('/', express.static(__dirname + '/www'));

httpServer.listen(8081);

const ioserve = io.listen(httpServer);

let users = [];

ioserve.on('connection', (socket) => {
    socket.on('login', (nickname) => {
        if (users.indexOf(nickname) > -1) {
            socket.emit('nickExisted');
        } else {
            socket.userIndex = users.length;
            socket.nickname = nickname;

            users.push(nickname);
            socket.emit('loginSuccess');

            ioserve.sockets.emit('system', nickname, users.length, 'login');
        }
    });

    socket.on('postMsg', function (msg) {
        socket.broadcast.emit('newMsg', socket.nickname, msg);
    });

    socket.on('img', function (imgData) {
        socket.broadcast.emit('newImg', socket.nickname, imgData);

    })

    socket.on('disconnect', function () {
        users.splice(socket.userIndex, 1);
        socket.broadcast.emit('system', socket.nickname, users.length, 'logout');
    });

})

前臺代碼

html文件

<body>
    <div class="wrapper">
        <div class="banner">
            <h1>HiChat :)</h1>
            <span id="status"></span>
        </div>
        <div id="historyMsg">
        </div>
        <div class="controls">
            <div class="items">
                <input id="colorStyle" type="color" placeHolder='#000' title="font color" />
                <input id="emoji" type="button" value="emoji" title="emoji" />
                <label for="sendImage" class="imageLable">
                    <input type="button" value="image" />
                    <input id="sendImage" type="file" value="image" />
                </label>
                <input id="clearBtn" type="button" value="clear" title="clear screen" />
            </div>
            <textarea id="messageInput" placeHolder="enter to send"></textarea>
            <input id="sendBtn" type="button" value="SEND">
            <div id="emojiWrapper">
            </div>
        </div>
    </div>
    <div id="loginWrapper">
        <p id="info">connecting to server...</p>
        <div id="nickWrapper">
            <input type="text" placeHolder="nickname" id="nicknameInput" />
            <input type="button" value="OK" id="loginBtn" />
        </div>
    </div>
    <script src="/socket.io/socket.io.js"></script>
    <script src="js/hichat.js"></script>
</body>

js文件

; (function () {

    function Hichart() {
        this.socket = null;
    }

    Hichart.prototype = {
        init: function () {
            var that = this;


            this.socket = io.connect();

            this.socket.on('connect', function () {
                document.getElementById('info').textContent = 'get yourself a nickname :)';
                document.getElementById('nickWrapper').style.display = 'block';
                document.getElementById('nicknameInput').focus();


                that.login();

                that.postMsg();

                that.uploadImg();
            });

            this.socket.on('nickExisted', function () {
                document.getElementById('info').textContent = '!nickname is taken, choose another pls';
            });

            this.socket.on('loginSuccess', function () {
                document.title = 'hichat | ' + document.getElementById('nicknameInput').value;
                document.getElementById('loginWrapper').style.display = 'none';//隱藏遮罩層顯聊天界面
                document.getElementById('messageInput').focus();//讓消息輸入框得到焦點
            });

            this.socket.on('system', function (nickname, userCount, type) {
                var msg = nickname + (type === 'login' ? ' joined' : ' left');
                that.displayNewMsg('system ', msg, 'red');
                document.getElementById('status').textContent = userCount + (userCount > 1 ? ' users' : ' user') + ' online';

            });

            this.socket.on('newMsg', function (nickname, msg) {
                that.displayNewMsg(nickname, msg);
            });

            this.socket.on('newImg', function (nickname, newImg) {
                that.displayImage(nickname, newImg);
            });
        },

        login: function () {
            var that = this;
            document.getElementById('loginBtn').addEventListener('click', function () {
                var nickname = document.getElementById('nicknameInput').value;
                if (nickname.trim().length) {
                    that.socket.emit('login', nickname);
                } else {
                    document.getElementById('nicknameInput').focus();
                }
            }, false)

        },

        displayNewMsg: function (user, msg, color) {
            var container = document.getElementById('historyMsg');
            var msgToDisplay = document.createElement('p');
            var data = new Date().toTimeString().substr(0, 8);
            msgToDisplay.style.color = color || '#000';
            msgToDisplay.innerHTML = user + '<span class="timespan">(' + data + '): </span>' + msg;
            container.appendChild(msgToDisplay);
            container.scrollTop = container.scrollHeight;

        },
        displayImage: function (user, imgData, color) {
            var container = document.getElementById('historyMsg'),
                msgToDisplay = document.createElement('p'),
                date = new Date().toTimeString().substr(0, 8);
            msgToDisplay.style.color = color || '#000';
            msgToDisplay.innerHTML = user + '<span class="timespan">(' + date + '): </span> <br/>' + '<a href="' + imgData + '" target="_blank"><img src="' + imgData + '"/></a>';
            container.appendChild(msgToDisplay);
            container.scrollTop = container.scrollHeight;
        },

        postMsg: function () {
            var that = this;
            var sendBtn = document.getElementById('sendBtn');
            var messageInput = document.getElementById('messageInput');

            sendBtn.addEventListener('click', function () {
                var msg = messageInput.value;
                if (msg.trim().length != 0) {
                    messageInput.value = '';
                    messageInput.focus();
                    that.socket.emit('postMsg', msg);
                    that.displayNewMsg('me', msg);
                }
            });
        },

        uploadImg: function () {
            var that = this;
            document.getElementById('sendImage').addEventListener('change', function () {
                if (this.files.length) {
                    var file = this.files[0];
                    var reader = new FileReader();

                    if (!reader) {
                        that.displayNewMsg('system', '!your browser doesn\'t support fileReader', 'red');
                        this.value = '';
                        return;
                    }

                    reader.onload = function (e) {
                        this.value = '';
                        that.socket.emit('img', e.target.result);
                        that.displayImage('me', e.target.result);
                    }

                    reader.readAsDataURL(file);
                }
            })
        }
    }

    window.onload = function () {
        var hichart = new Hichart();

        hichart.init();
    }







})()

完整demo請查看個人github,地址:https://github.com/jianwenjua...

相關文章
相關標籤/搜索