zoukankan      html  css  js  c++  java
  • WebSocket实现web即时通信(后端nodejs实现)

    WebSocket实现web即时通信

    一、首先看一下,HTTP、ajax轮询、long poll和WebSocket的区别:

    1、HTTP 协议(短连接):一个 Request 一个 Response。缺陷:通信只能由客户端发起。
    --------------------------------------------------------------------------------
    2、ajax轮询:
    ajax轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
    轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)
    --------------------------------------------------------------------------------
    3、long poll:原理跟ajax轮询差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。基于事件的触发,一个事件接一个事件。long poll需要很高的并发,体现了同时容纳请求的能力。
    --------------------------------------------------------------------------------
    4、WebSocket:是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。WebSocket的优势在于他的高实时性,以及传输过程中的低的资源消耗!
    握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。Websocket的数据传输是frame形式传输的。
    WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
    它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
    其他特点包括:
    (1)建立在 TCP 协议之上,服务器端的实现比较容易。
    (2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
    (3)数据格式比较轻量,性能开销小,通信高效。
    (4)可以发送文本,也可以发送二进制数据。
    (5)没有同源限制,客户端可以与任意服务器通信。
    (6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

    关于WebSocket的更多介绍可以参考
    阮一峰——WebSocket 教程http://www.ruanyifeng.com/blog/2017/05/websocket.html

    ===============================================================================
    二、通过nodejs和javascript实现一个网页聊天室

    (参考:博客https://blog.csdn.net/u010136741/article/details/51612594?utm_source=copy;作者:柳木木_kylin )
    主要包括,聊天,改用户名,查看其他用户在线状态的功能。
    大致流程为,用户访问网页,即进入聊天状态,成为新游客,通过底部的输入框,可以输入自己想说的话,点击发布,信息呈现给所有在聊天的人的页面。用户可以实时修改自己的昵称,用户离线上线都会实时广播给其他用户!
    javascript 部分,连接websocket成功之后,主要是监听数据返回,和发送数据。
    当用户编辑好内容,点击发送按钮是调用sendMessage方法,发送数据,如果需要修改昵称,则发送数据格式为"/nick 昵称"。
    当服务器返回数据到客户端,我们通过appendLog方法对数据做处理,根据type字段,判断是显示用户离线在线信息,还是显示聊天信息。最后更新在线人数。

    服务器端:WebSocket_chart_server.js

    var WebSocket = require('ws');
    var WebSocketServer = WebSocket.Server,
        wss = new WebSocketServer({port: 8180});
    var uuid = require('node-uuid');
     
    var clients = [];
     
    function wsSend(type, client_uuid, nickname, message,clientcount) {
      for(var i=0; i<clients.length; i++) {
        var clientSocket = clients[i].ws;
        if(clientSocket.readyState === WebSocket.OPEN) {
          clientSocket.send(JSON.stringify({
            "type": type,
            "id": client_uuid,
            "nickname": nickname,
            "message": message,
            "clientcount":clientcount,
          }));
        }
      }
    }
     
    var clientIndex = 1;
     
    wss.on('connection', function(ws) {
      var client_uuid = uuid.v4();
      var nickname = "游客"+clientIndex;
      clientIndex+=1;
      clients.push({"id": client_uuid, "ws": ws, "nickname": nickname});
      console.log('client [%s] connected', client_uuid);
     
      var connect_message = nickname + " 来了";
      wsSend("notification", client_uuid, nickname, connect_message,clients.length);
     
      ws.on('message', function(message) {
        if(message.indexOf('/nick') === 0) {
          var nickname_array = message.split(' ');
          if(nickname_array.length >= 2) {
            var old_nickname = nickname;
            nickname = nickname_array[1];
            var nickname_message = "用户 " + old_nickname + " 改名为: " + nickname;
            wsSend("nick_update", client_uuid, nickname, nickname_message,clients.length);
          }
        } else {
          wsSend("message", client_uuid, nickname, message,clients.length);
        }
      });
     
      var closeSocket = function(customMessage) {
        for(var i=0; i<clients.length; i++) {
            if(clients[i].id == client_uuid) {
                var disconnect_message;
                if(customMessage) {
                    disconnect_message = customMessage;
                } else {
                    disconnect_message = nickname + " 走了";
                }
     
              clients.splice(i, 1);
              wsSend("notification", client_uuid, nickname, disconnect_message,clients.length);
            }
        }
      }
      ws.on('close', function() {
          closeSocket();
      });
     
      process.on('SIGINT', function() {
          console.log("Closing things");
          closeSocket('Server has disconnected');
          process.exit();
      });
    });

    web端:WebSocket_chart_web.html

    <!DOCTYPE html>
    <html lang="cn">
    <head>
        <title>WebSocket chart application</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/css/bootstrap.css">
        <link rel="stylesheet" href="http://cdn.bootcss.com/tether/1.3.2/css/tether.css"/>
        <script src="http://cdn.bootcss.com/jquery/2.2.4/jquery.js" ></script>
        <script src="http://cdn.bootcss.com/tether/1.3.2/js/tether.js"></script>
        <script src="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/js/bootstrap.js"></script>
        <script>
            var ws= new WebSocket('ws://localhost:8180');
            var nickname;
            ws.onopen = function(e){
                console.log('Connection to server opened');
            }
              function appendLog(type,nickname, message,clientcount) {
                      var messages = document.getElementById('messages');
                      var messageElem = document.createElement("li");
                      var preface_label;
                if(type==='notification') {
                              preface_label = "<span class="label label-info">*</span>";
                          } else if(type==='nick_update') {
                              preface_label = "<span class="label label-warning">*</span>";
                          } else {
                              preface_label = "<span class="label label-success">" + nickname + "</span>";
                          }
                      var message_text = "<h2>" + preface_label + "  " + message + "</h2>";
                      messageElem.innerHTML = message_text;
                      messages.appendChild(messageElem);
                var count_people = document.getElementById("count_people");
                            count_people.innerHTML = clientcount;
     
                }
            ws.onmessage = function(e){
                var data = JSON.parse(e.data);
                nickname = data.nickname;
                      appendLog(data.type,data.nickname, data.message,data.clientcount);
                    console.log("ID: [%s] = %s", data.id, data.message);
     
     
            }
            function sendMessage(){
                var message = $('#message').val().trim();
                if(message.length<1){
                    alert("不能发送空内容!");
                    return;
                }
                ws.send($('#message').val());
                $('#message').val("");
                $('#message').focus();
                console.log(ws.bufferedAmount);
            }
        </script>
    </head>
    <body lang="cn">
        <div class="vertical-center">
        <div class="container">
            <h2>多人在线聊天DEMO</h2>
        <hr />
        <p>当前在线人数:<span id="count_people">0</span></p>
         <ul id="messages" class="list-unstyled">
     
            </ul>
            <hr />
           <form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
                <div class="form-group">
                    <input class="form-control" type="text" name="message" id="message"
                          placeholder="输入聊天内容" value="" autofocus/>
                </div>
                   <button type="button" id="send" class="btn btn-primary"
              onclick="sendMessage();">发送!</button>
        </form>
        </div>
        </div>
    </body>
    </html>
  • 相关阅读:
    多层交换概述
    多层交换MLS笔记2
    多层交换MLS笔记1
    RSTP Proposal-Agreement
    RSTP Note
    保护STP
    优化STP
    Cisco STP Note
    25、C++的顶层const和底层const
    43、如何用代码判断大小端存储
  • 原文地址:https://www.cnblogs.com/Micang/p/9807005.html
Copyright © 2011-2022 走看看