资讯专栏INFORMATION COLUMN

WebSocket网络通信协议

xuhong / 3384人阅读

摘要:而双工通讯协议,不仅客户端能向服务端发起请求,服务端也可以主动推送信息给客户端。目的即时通讯,替代轮询协议在年诞生,年成为国际标准。与协议有着良好的兼容性。是一个基于的,用于实时通信的一个软件包包括端和端,完全由实现。

上一篇文章简要的介绍了一下http协议,这次再介绍一下WebSocket协议,两者之间有很大的区别,WebSocket协议是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

简单的理解一下什么是双工通讯协议,之前有讲过http协议只能客户端向服务端发起请求,是单向的应用层协议。而双工通讯协议,不仅客户端能向服务端发起请求,服务端也可以主动推送信息给客户端。

目的:即时通讯,替代轮询

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

相比于http协议,websoket协议给我们带来了极大的方便,举个例子:

之前,我们在做消息通知的时候,需要设置定时器,频繁的向后台发起异步ajax请求实现长轮询,获取最新的数据,这样效率非常低,非常浪费资源,因为不停的发起http请求,不停的与服务端建立连接,或者http链接始终打开。
而现在有了websocket,就解决了轮询的问题,websocket只需要建立一次连接,就可以保持长久连接,相比轮询不停的建立连接,大大的提升了效率,这样只要服务端有数据变化,就可以立即通知前台了。

websocket协议与http协议之间的关系

首先HTTP有 1.1 和 1.0 之说,也就是所谓的 keep-alive ,把多个HTTP请求合并为一个,但是 Websocket 其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充,Websocket是借用了HTTP的协议来完成一部分握手。

websocket有以下特点:

建立在 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这个库就可以了。前后台都需要引用该库。

下面针对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文件


    

connecting to server...

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 + "(" + data + "): " + 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 + "(" + date + "):  
" + ""; 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...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/53319.html

相关文章

  • 初探WebSocket

    摘要:流控制通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。和长链接以上几种服务器推的技术中长轮询和流控制其实都是基于长链接来实现的,也就是中所谓的。通信协议于年被定为标准,并被所补充规范。 初探WebSocket node websocket socket.io 我们平常开发的大部分web页面都是主动‘拉’的形式,如果需要更新页面内容,则需要刷新一个,但Slack工...

    Channe 评论0 收藏0
  • WebSocket 与 Socket.IO

    摘要:当数据发生变化,便将数据发送给。与网络应用中,两个应用程序同时需要向对方发送消息的能力即全双工通信,所利用到的技术就是,其能够提供端对端的通信。其不仅支持,还支持许多种轮询机制以及其他实时通信方式,并封装了通用的接口。 WebSocket 与 Socket.IO 最近小组在做一个智慧交通的项目,其中有个 分享屏幕 的功能,即一个 client 能够将自己当前的页面分享到另外一个 cli...

    snifes 评论0 收藏0
  • Websocket解析及实现

    摘要:早期的轮询是通过不断自动刷新页面而实现的。长轮询的另一个问题是缺乏标准实现。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。协议解析协议包含两部分一部分是握手,一部分是数据传输。 Websocket是什么? Websocket是一个因为应用场景越来越复杂而提出的,针对浏览器和web服务器之间双向持续通信而设计,而且优雅地兼容HTTP的协议(我猜想:同...

    XboxYan 评论0 收藏0
  • WebSocket就这么回事儿

    摘要:服务端确认协议版本,升级为协议。自己写了一个例子,服务端在开始连接后,利用定时器主动向客户端发送随机数,客户端也可以发给服务器消息,然后服务器返回这条消息给客户端。做的事情就是给页面的元素绑定事件。 写在前面webSocket是一项可以让服务器将数据主动推送给客户端的技术。前几天写了一个日志功能,日志数据需要实时更新。正好项目中有封装好的WebSocket组件,且接口支持webSock...

    ruicbAndroid 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<