Node.js学习笔记(五)——WebSocket

前端和后端的交互的方式有哪些?

前台里面能够发送网络请求的标签,基本上都可以和后端实现网络交互。

  • ajax
  • jsonp
  • iframe
  • websocket

我们思考一个问题
在之前,我们知道前后端数据交互的过程中,都是前端发送请求,后端给予响应。但是有没有一种情况就是在前端没有发送请求的情况下,后端自动向前端一个响应?

其实是有这种情况的,就是服务器主动向客户端推信息,我们称之为coment技术(推技术)。

coment技术如何实现?

  • ajax+定时器(轮询long-polling,伪实现)
  • 长链接
  • websocket

WebSocket

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

在这里插入图片描述
为了方便使用,我们可以使用第三方库socket.io

socket.io

socket.io是一个跨浏览器支持WebSocket的实时通讯的JS。

Socket.io支持及时、双向、基于事件的交流,可在不同平台、浏览器、设备上工作,可靠性和速度稳定。最典型的应用场景如:

  • 实时分析:将数据推送到客户端,客户端表现为实时计数器、图表、日志客户。
  • 实时通讯:聊天应用
  • 二进制流传输:socket.io支持任何形式的二进制文件传输,例如图片、视频、音频等。
  • 文档合并:允许多个用户同时编辑一个文档,并能够看到每个用户做出的修改。

Socket.io实际上是WebSocket的父集,Socket.io封装了WebSocket和轮询等方法,会根据情况选择方法来进行通讯。

Node.js提供了高效的服务端运行环境,但由于Browser对HTML5的支持不一,为了兼容所有浏览器,提供实时的用户体验,并为开发者提供客户端与服务端一致的编程体验,于是Socket.io诞生了。

Socket.io将WebSocket和Polling机制以及其它的实时通信方式封装成通用的接口,并在服务端实现了这些实时机制相应代码。

socket.io基本使用方式

  1. 安装
npm install socket.io
  1. 使用
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);

// 静态资源
app.use(express.static('./public'));

app.get('/', (req, res) => {
  res.send("hello")
});

io.on('connection', (socket) => {
    // emit 参数:
    // 参数1:代表是触发事件需要实现在websocket的客户端进行监听
    // 参数2:传递给客户端的数据
    setInterval(() => {
        socket.emit('msg', '服务器端' + Math.random());
    },1000)
});

http.listen(3000, () => {
  console.log('listening on *:3000');
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>客户端</h1>
    <button id="btn">点击连接websocket服务器</button>
    <div class="content"></div>
</body>
<!-- 书写websocket客户端代码 -->
<!--1. 使用一个第三方的websocket客户端库实现websocket服务-->
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script src="https://cdn.bootcss.com/jquery/2.0.1/jquery.js"></script>

<script>
    // 2. 编写客户端代码
    var socketServerUrl = 'http://localhost:3000';
    $("#btn").click(() => {
        // 3. 发送链接请求
        var socketClient = io(socketServerUrl); 
        // 4. 得到一个websocket客户端
        // 5. connect是客户端一旦链接websocket服务器成功,回调函数立即执行
        socketClient.on('connect', () => {
            console.log("链接服务器成功" )
        })
        socketClient.on('msg', (data) => {
            $(".content").append(data + "<hr>");
        })
    })
</script>
</html>

启动服务,在浏览器地址栏输入:http://localhost:3000/
在这里插入图片描述
点击按钮,客户端和服务器成功链接一次,这次链接后,将保持链接,之后每一秒钟服务器端都会主动向客户端发送响应。

在这里插入图片描述

使用webscoket实现一个简单的即时聊天工具

const express = require('express')
const app = express();
const moment = require('moment')
const http = require('http').createServer(app);
const io = require('socket.io')(http);

// 静态资源
app.use(express.static('./public'));

// 客户端月服务端连接 短连接服务
app.get('/', (req, res) => {
    res.send('hi web!');
});

// websocket 客户端---> websocket 服务器 长链接服务
// on 代表事件监听 connection 链接事件,服务器现在监听websocket客户端的链接,一般 链接成功 回调函数执行,socket 参数代表是当前链接的对象,我们可以通过该对象和客户端进行交互。
io.on('connection', (socket) => {
    // console.log(socket);
    console.log('a user connected');
    // emit 单词翻译过来触发。
    // 参数1:代表是触发事件需要实现在websocket的客户端进行监听
    // 参数2: 传递给客户端的数据

    // 监听客户端发送的 joinUs 事件
    socket.on('joinUs', (data)=> {
        console.log(data);
        // 广播给所有的客户端,有新人加入聊天(暴照)
        io.emit('guangbo', data);
    })

    // 监听 用户发送聊天信息
    socket.on('sendMsg', (data) => {
        // 广播给所有人
        data.time = moment().format('YYYY-MM-DD HH:mm:ss');
        io.emit('chat', data);
    })
});

http.listen(3000, () => {
    console.log('listening on *:3000');
});
<!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>输入用户名</title>
  <link rel="stylesheet" href="./style/style.css">
</head>
<body>
  <div class="i-body">
    <h1>请输入你的昵称:</h1>
    <form id="usernameForm">
      <input type="text" id="nickname">
    </form>
  </div>
</body>
</html>
<script src="https://cdn.bootcss.com/jquery/2.0.1/jquery.js"></script>
<script>
  $("#usernameForm").submit( (event) => {
    event.preventDefault(); // 阻止表单默认的提交
    var nickname = $("#nickname").val().trim();
    // 自己跳转到 room.html
    // 现在要和 room.html 页面共享 nickname这个用户名
    localStorage.setItem('nickname', nickname);
    location.href = '/room.html';

  } )
</script>
<!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>迷你聊天室</title>
  <link rel="stylesheet" href="./style/style.css">
</head>
<body>
  <header class="c-header">
    <h1>迷你聊天室</h1>
    <div class="c-user"><img src="./imgs/1.jpg" title=""></div>
  </header>
  <div class="c-body">
    <div class="c-main">
      <ul class="c-list">
      </ul>

      <div class="c-xxx"></div>
      <div class="c-chat">
        <img class="c-avatar2" src="./imgs/1.jpg" alt="">
        <input class="c-input" type="text" id="content">
        <button class="c-btn" id="msgBtn">发送</button>
      </div>
    </div>
  </div>
</body>
</html>

<script src="https://cdn.bootcss.com/jquery/2.0.1/jquery.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

<script>
  ;(()=>{
    var nickname = localStorage.getItem('nickname');
    if(!nickname){
        location.href = '/index.html';
        return;
    }
    // 设置连接地址
    var socketServerUrl = 'http://localhost:3000';
    // 连接请求
    var socketClient = io(socketServerUrl);
    // connect是客户端一旦链接websocket服务器成功,回调函数立即执行
    socketClient.on('connect', () => {
      console.log('链接服务器成功!');
    })
    // 将数据发送给websocket服务器,发布广播
    socketClient.emit('joinUs', {nickname});
    // 点击发送按钮
    $("#msgBtn").click(()=> {
      var content = $("#content").val().trim();
      if(!content){
        alert('聊天信息不能为空!');
        return;
      }
      // 将数据发送给websocket服务器,发布广播
      socketClient.emit('sendMsg', {nickname, content});
      $("#content").val('');
    })

    // 监听事件
    socketClient.on('guangbo', (data)=>{
      console.log('guangbo', data);
      var html = `<li class="c-item">
          <div class="c-join-info">【${data.nickname}】加入聊天室</div>
        </li>
`;
      $(".c-list").append(html)
    })

    // 监听事件
    socketClient.on('chat', (data) => {
      console.log('data', data);
      // 聊天的信息放置页面 data.nickname 信息发送者
      var html = ``;
      if(nickname == data.nickname){
        // 代表自己发送 my-item 类名 底纹
        html = ` <li class="c-item my-item">
          <img class="c-avatar" src="./imgs/3.jpg" title="">
          <div class="c-box">
            <div class="c-info">
              <div class="c-name">${data.nickname} ${data.time}</div>
            </div>
            <div class="c-content">${data.content}</div>
          </div>
        </li>`;
      }else{
        html = ` <li class="c-item">
          <img class="c-avatar" src="./imgs/3.jpg" title="">
          <div class="c-box">
            <div class="c-info">
              <div class="c-name">${data.nickname} ${data.time}</div>
            </div>
            <div class="c-content">${data.content}</div>
          </div>
        </li>`;
      }
      $('.c-list').append(html);
    })
  })();
</script>

启动服务,在浏览器地址栏输入:http://localhost:3000/index.html
在这里插入图片描述
输入昵称,回车,加入聊天室:
在这里插入图片描述

在这里插入图片描述
可以发送消息:
在这里插入图片描述
当另一个用户也进入了聊天室,可以看到提示:
在这里插入图片描述
当另一个人发送消息:
在这里插入图片描述
至此,简单的聊天室实现了。

当然,在实际开发中,我们大可不必自己写聊天室,有现成的一些网站就提供了很好的即时聊天功能,比如:
http://kedou.workerman.net/
https://www.easemob.com/
https://layim.layui.com/

参考文档:
https://socket.io/get-started/chat/
https://www.jianshu.com/p/4e80b931cdea

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值