丑low的聊天室

2019-07-18 18:54:35 浏览数 (1)

笔者第一次上网,学校网络室给定制的首页是一个红泥巴的聊天室。这回去看了下,卧槽还没倒闭:

果然是经得起时间考验的项目了。

socket实现——一个即时终端聊天室

net模块提供一个异步api能够创建基于流的tcp服务器,客户端和服务端建立连接之后,服务器可以获得一个双工socket对象,服务器可以保存socket对象列表,在接受某客户端消息时,推送给其他客户端。

代码语言:javascript复制
// socket.js
const net=require('net');
const chatServer=net.createServer();
const clientList=[];

chatServer.on('connection',client=>{
    client.write('Hin');
    clientList.push(client);
    // 当接收到数据时:
    client.on('data',data=>{
        console.log(`receive:${data.toString()}`);
        clientList.forEach(v=>{
            v.write(data);
        })
    })
});
chatServer.listen(9000);

如何测试呢?这里用到telnet:

telnet本来是mac os 10.13之前的内置服务,在高级版本中,需要本地安装一下:

代码语言:javascript复制
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install telnet

安装完成之后:

代码语言:javascript复制
telnet localhost 9000

打印出'hi'

假设再建立一个客户端:同样也能收到消息。

网络聊天室

http的一个重要弱点在于,只能拉取,不能主动推送。所以后端扯皮时会说:'"你不穿东西给我,我就没东西给你。"这个时候只好做轮询(苦了前端)。

从项目角度说,HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。当需要即时通讯时,通过轮询在特定的时间间隔(如1秒),由浏览器向服务器发送Request请求,然后将最新的数据返回给浏览器。这样的方法最明显的缺点就是需要不断的发送请求,而且通常HTTP request的Header是非常长的,为了传输一个很小的数据 需要付出巨大的代价,是很不合算的,占用了很多的宽带

但如果有了socket.io,事情就好办多了。

Socket.io是一个WebSocket库,包括了客户端的js和服务器端的nodejs,它的目标是构建可以在不同浏览器和移动设备上使用的实时应用。它会自动根据浏览器从WebSocket、AJAX长轮询、Iframe流等等各种方式中选择最佳的方式来实现网络实时应用,非常方便和人性化,而且支持的浏览器最低达IE5.5

代码语言:javascript复制
npm i socket.io -S

在后端基本上不需要做什么处理:

代码语言:javascript复制
// 服务端:chat-socketio.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function (req, res) {
    res.sendFile(__dirname   '/index.html');
});

io.on('connection', function (socket) {
    console.log('a user connected');
    io.emit('chat message', {
        type:'notice',
        time:new Date().toLocaleString(),
        name:'新用户',
        msg:'加入了群聊'
    });


    //响应某用户发送消息
    socket.on('chat message', function (msg) {
        console.log('chat message:'   msg);
        // 广播给所有人
        io.emit('chat message', msg);
        // 广播给除了发送者外所有人
        // socket.broadcast.emit('chat message', msg)
    });
    socket.on('disconnect', function () {
        io.emit('chat message', {
            msg:'用户退出了群聊',
            type:'notice',
            name:'有用户',
            time:new Date().toLocaleString(),
        });
        console.log('user disconnected');
    });
});


http.listen(3000, function () {
    console.log('listening on *:3000');
});

前端:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style type="text/css">
            /* blabla */
    </style>
</head>

<body>
    <div id="root">
        <!-- <input type="file" name="file" id="upload"> -->
        <div id="dialog">

        </div>

        <div id="control">
            <input id="username" type="text">
            <textarea id="msg" cols="30" rows="10"></textarea>
            <button id="send">发送</button>
        </div>
    </div>
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
    <script>
        var dialog = document.querySelector('#dialog');
        var send = document.querySelector('#send');
        var msg = document.querySelector('#msg');
        var socket = io();
        send.addEventListener('click', (e) => {
            socket.emit("chat message", {
                name:document.querySelector('#username').value,
                msg:msg.value,
                time:new Date().toLocaleString(),
                type:'normal'
            });
        })
        socket.on("chat message", function (msg) {
            let html=``;

            switch (msg.type) {
                case 'notice':
                    html=`<div class="notice">
                    ${msg.name} ${msg.msg} <small>${msg.time}</small>
                </div>`;
                    break;

                default:
                    html=`<div class="msg-wrap">
                    <div class="name">${msg.name} <small>${msg.time}</small></div>
                    <div class=""msg">${msg.msg}</div>
                </div>`
                    break;
            }
            dialog.innerHTML =html;
            dialog.scrollTop = dialog.scrollHeight;
        });

    </script>
</body>

</html>

那么就实现了。

0 人点赞