zoukankan      html  css  js  c++  java
  • 将js进行到底:node学习7

    Node.js之Websocket技术

    我第一次听说websocket之时,HTML5标准尚未公布,当时只有少数前瞻性浏览器携带了这个API。

    我对websocket最大的印象是,他可以解决我对“在线聊天系统”开发的疑惑(我一直想不通http如何保持长连接),这样我们无需使用轮询ajax和php无限循环去模拟,还记得2014年初那会我写了一个在线聊天室,那时候我真的应该用websocket技术的,php无限轮询的方式,只要3-4个人在线就可以让linux+apache服务器崩溃。

    很可惜,我没有在php上使用过Websocket API,今天是我第一次将这个技术用来实践,使用node.js实现

    引入模块

    package.json

    {
        "name":"chat-websocket",
        "version":"0.0.1",
        "description":"use websocket to create a char server",
        "dependencies":{
            "express":"latest",
            "express-ws":"latest"
        }
    }
    

    在引入http必备的express框架后,再引入基于express的中间件——express-ws

    express-ws是express上的websocket中间件,为express提供了websocket请求处理功能

    另外注意:《了不起的node.js》一书中使用的是websocket.io模块,两个东西原理,方法都差不多,我个人觉得io那个老了点,我选择了express-ws模块!主要是因为其与express配合效果更佳,专门为express而设计的中间件,何乐而不用呢?

    做个测试

    先来看看,node中使用express-ws的基本套路:

    index.js

    var express = require("express");
    
    //创建express下的http服务
    var app = express();
    //关联express-ws中间件
    var expressWs = require("express-ws")(app);
    
    //express托管静态文件
    app.use(express.static(__dirname+'/views',{'index':'index.html'}));
    
    
    app.ws('/ws',function(ws,req){
        ws.on('message',function(msg){
            console.log(msg);
        })
    });;
    
    app.listen(80);
    

    这个index.js是服务端代码

    解析:

    • 先引入express模块,并使用express()方法获得app对象
    • 引入express-ws并构造对象,构造函数传入的是app对象,意思大概是绑定到express服务器上
    • 通常接受http请求使用的是app.use(),而websocket请求则使用app.ws(),该方法就是中间件扩展的
    • message事件监听客户端发送的数据,并打印到终端上

    views/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试</title>
    </head>
    <body>
        <input type="text" value="" id="msg">
        <button id="submit">提交</button>
    </body>
    <script>
        window.onload=function(){
            var ws = new WebSocket('ws://localhost/ws')
            var sub = document.getElementById("submit");
            var msg = document.getElementById("msg")
            sub.addEventListener("click",function(){
                ws.send(msg.value);
            });
            ws.addEventListener("open",function(){
                alert("WebSocket has been opened!");
            })
        }
    </script>
    </html>
    

    这些为前端代码:实现了一个简单输入框,输入后主动通过websocket发送给服务端,服务端那边会打印再console中

    效果:

    这里写图片描述

    测试成功,每一次点击提交都会显示!

    WebSocket开发在线聊天室

    功能点

    1. 用户进入输入用户名可开始聊天
    2. 登入后提示当前在线用户
    3. 聊天内容会广播给聊天室其他在线用户
    4. 用户进入后提示xxx用户进入聊天室
    5. 用户关闭后提示xxx用户退出聊天室

    package.json同上不变,具体设计逻辑参考另一篇博客,我用TCP API实现的聊天室程序http://www.cnblogs.com/devilyouwei/p/8423961.html

    前端:index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试</title>
        <style>
            #inchat{
                display:none;
            }
            ul{
                list-style-type:none;
            }
        </style>
    </head>
    <body>
        <div id="inputname">
            <input type="text" value="" id="msg" placeholder="输入一个聊天昵称">
            <button id="submit">提交</button>
        </div>
        <div id="inchat">
            <ul id="chat-content">
            </ul>
            <textarea id="sendContent" value="">
            </textarea>
            <button id="send">发送</button>
        </div>
    </body>
    <script>
        window.onload=function(){
            var ws = new WebSocket('ws://localhost/ws');//需要修改为相应地址
            var sub = document.getElementById("submit");
            var msg = document.getElementById("msg")
            var ul  = document.getElementById("chat-content");
            var send = document.getElementById("send");
            var sendContent = document.getElementById("sendContent");
            sendContent.value="";
            sub.addEventListener("click",function(){
                ws.send(msg.value);
            });
            send.addEventListener("click",function(){
                ws.send(sendContent.value);
                sendContent.value=""
            });
            ws.addEventListener("open",function(){
                alert("WebSocket has been opened!");
            })
            ws.addEventListener("message",function(e){
                var res = JSON.parse(e.data);
                //如果正在聊天中
                if(res.ischat){
                    var li = document.createElement("li");
                    li.innerText = res.info;
                    ul.appendChild(li);
                }else{
                    if(res.status == 1){
                        document.getElementById("inputname").style.display="none";
                        document.getElementById("inchat").style.display="block";
                    }else{
                        alert(res.info);
                    }
                }
            });
        }
    </script>
    </html>
    

    注意:放到公网访问需要把localhost改成ip或者网址!

    后端:index.js

    var express = require("express");
    
    //创建express下的http服务
    var app = express();
    //关联express-ws中间件
    var expressWs = require("express-ws")(app);
    
    var users = {};
    var count = 0;
    
    //express托管静态文件
    app.use(express.static(__dirname+'/views',{'index':'index.html'}));
    
    //用ws方法而不是use方法
    app.ws('/ws',function(ws,req){
        var username = null;
        ws.on('message',function(msg){
            if(!username){
                if(users[msg]){
                    ws.send(JSON.stringify({status:0,info:"用户名重复请重试",ischat:false}));
                }else if(msg == ""){
                    ws.send(JSON.stringify({status:0,info:"用户名不能为空",ischat:false}));
                }else{
                    username = msg;
                    count++;   //用户+1
                    users[msg] = ws;
                    ws.send(JSON.stringify({status:1,info:"注册成功,欢迎"+username,ischat:false}));
                    console.log(username+"用户加入聊天室!当前在线:"+count);
                    broadcast(username+"用户加入聊天室!当前在线:"+count);
                }
            }else{
                broadcast(username+":"+msg);
                console.log(username+":"+msg);
            }
        });
    
        ws.on('close',function(){
            delete users[username];
            count--;
            console.log(username+"用户退出聊天室!当前在线:"+count);
            broadcast(username+"用户退出聊天室!当前在线:"+count);
        })
    });;
    
    app.listen(80);
    
    //需要广播给所有人(不排除自己)
    function broadcast(msg){
        for(var i in users)
            users[i].send(JSON.stringify({status:1,info:msg,ischat:true}));
    }
    

    注意1:express-ws中的ws.send()方法只能发送字符串,并没有express http的res.send()那么强大,故而我在传入js对象时,手动使用JSON.stringify()将对象转换为json字符串,待前端收到后再使用JSON.parse()转换回js对象。

    注意2:WebSocket API中几个最重要的事件:open,close,message,error,对应了连接过程中的打开连接,关闭连接,消息传递,错误事件,无论前端还是后端都需要对这几个事件进行绑定监听,传入回掉函数做必要的处理

    注意3:设计逻辑再讲一遍:users变量存储每一个连接引用,username作为局部变量,再每一次连接域内部,每一个客户端连入都会创建一个,单独的broadcast()方法遍历所有socket连接发送消息,最后再提醒一遍node.js开发一定要特别注意作用域范围!

    效果

    这里写图片描述

  • 相关阅读:
    Building a flexiable renderer
    Indirect Illumination in mental ray
    我的心情
    Cellular Automata
    Subsurface Scattering in mental ray
    Shader Types in mental ray
    BSP Traversal
    我的渲染器终于达到了MR的速度
    How to handle displacement and motion blur
    说明
  • 原文地址:https://www.cnblogs.com/devilyouwei/p/8447287.html
Copyright © 2011-2022 走看看