zoukankan      html  css  js  c++  java
  • 实现一个简单的WebSocket聊天室

    WebSocket 简介

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
    WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
    在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

    为什么传统的HTTP协议不能做到WebSocket实现的功能?这是因为HTTP协议是一个请求-响应协议,请求必须先由浏览器发给服务器,服务器才能响应这个请求,再把数据发送给浏览器。换句话说,浏览器不主动请求,服务器是没法主动发数据给浏览器的。

    Web

    我们先用 express 搭一个基础的服务端。

    创建 index.js 文件

    var app = require('express')();
    var http = require('http').createServer(app);
    
    app.get('/', function(req, res){
      res.send('<h1>Hello world</h1>');
    });
    
    http.listen(3000, function(){
      console.log('listening on *:3000');
    });
    

    run node index.js,并在浏览器打开 http://localhost:3000,访问成功即可看到

    HTML

    设计我们的主页,实现一个简单的聊天窗口。

    修改 index.js

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

    创建 index.html

    <!doctype html>
    <html>
      <head>
        <title>Socket.IO chat</title>
        <style>
          * { margin: 0; padding: 0; box-sizing: border-box; }
          body { font: 13px Helvetica, Arial; }
          form { background: #000; padding: 3px; position: fixed; bottom: 0;  100%; }
          form input { border: 0; padding: 10px;  90%; margin-right: .5%; }
          form button {  9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
          #messages { list-style-type: none; margin: 0; padding: 0; }
          #messages li { padding: 5px 10px; }
          #messages li:nth-child(odd) { background: #eee; }
        </style>
      </head>
      <body>
        <ul id="messages"></ul>
        <form action="">
          <input id="m" autocomplete="off" /><button>Send</button>
        </form>
      </body>
    </html>
    

    重启应用并刷新页面你就可以看到一个如下图所示

    Socket.io

    引入socket.io

    npm install --save socket.io

    修改 index.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('an user connected');
    });
    
    http.listen(3000, function(){
      console.log('listening on *:3000');
    });
    

    修改 index.html,在</body>下添加如下代码

    <script src="/socket.io/socket.io.js"></script>
    <script>
      var socket = io();
    </script>
    

    重启应用并刷新页面,就可以看到命令行打印如下

    Emitting event

    当用户在聊天窗的输入框内输入,并提交时,触发 emit 事件,服务端监听到该事件并做出相应的反应。

    修改 index.html

    <script src="/socket.io/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
      $(function () {
        var socket = io();
        $('form').submit(function(e){
          e.preventDefault(); // 防止页面重新加载
          socket.emit('chat message', $('#m').val());
          $('#m').val('');
          return false;
        });
      });
    </script>
    

    服务端监听该事件,在 index.js 文件添加该代码

    io.on('connection', function(socket){
      socket.on('chat message', function(msg){
        console.log('message: ' + msg);
      });
    });
    

    展示消息

    当服务端收到用户A发出的消息,服务端重新发出该消息,让客户端接收,客户端监听到该事件后展示该条消息,就可以实现用户 A, B, C 都接收到该消息。

    修改 index.js

    io.on('connection', function(socket){
      socket.on('chat message', function(msg){
        io.emit('chat message', msg);
      });
    });
    

    修改 index.html,实现消息的展示

    <script>
      $(function () {
        var socket = io();
        $('form').submit(function(e){
          e.preventDefault(); // prevents page reloading
          socket.emit('chat message', $('#m').val());
          $('#m').val('');
          return false;
        });
        socket.on('chat message', function(msg){
          $('#messages').append($('<li>').text(msg));
        });
      });
    </script>
    

    重启应用并刷新页面,可以打开多个浏览器页面同时访问 localhost:3000,就可以体验简单聊天室的效果。

    设置昵称

    在每个用户进入的时候,随机生成一个数字作为用户的昵称,并且向所有用户广播该用户进入聊天室。当用户发送消息时,拼接上用户的昵称。

    修改 index.js

    io.on('connection', (socket) => {
      const nickname = 'user' + Math.ceil((Math.random() * 1000))
      socket.broadcast.emit('connection', nickname + ' connected')
    
      socket.on('chat message', (msg) => {
        io.emit('chat message', nickname + ': ' + msg)
      })
    })
    

    修改 index.html,监听 connection 事件

    <script>
      $(() => {
        const socket = io()
        $('form').submit((e) => {
          e.preventDefault()
          socket.emit('chat message', $('#m').val())
          $('#m').val('')
          return false
        });
        socket.on('chat message', (msg) => {
          $('#messages').append($('<li>').text(msg))
        })
        socket.on('connection', (msg) => {
          $('#messages').append($('<li>').text(msg))
        })
      });
    </script>
    

    重启应用并打开多个客户端,可以看到如下效果

    参考资料

    本文大部分案例出自 socket.io 的入门文档 https://socket.io/get-started/chat/

    https://en.wikipedia.org/wiki/WebSocket

    廖雪峰官网 WebSocket

    菜鸟教程 WebSocket

  • 相关阅读:
    吴裕雄--天生自然 Zookeeper学习笔记--ZooKeeper 数据模型 znode 结构详解
    吴裕雄--天生自然 Zookeeper学习笔记--Zookeeper Java 客户端搭建
    吴裕雄--天生自然 Zookeeper学习笔记--Zookeeper linux 服务端集群搭建步骤
    吴裕雄--天生自然 Zookeeper学习笔记--Zookeeper 安装配置
    吴裕雄--天生自然 Zookeeper学习笔记--ZooKeeper
    吴裕雄--天生自然 使用python的pandas_alive包生成动态图
    程序规范示例
    迭代器Iteration
    斐波拉契数列(Fibonacci)--用生成器生成数列
    Python中装饰器的用法
  • 原文地址:https://www.cnblogs.com/chaohangz/p/10745489.html
Copyright © 2011-2022 走看看