socket.io

socket

  1. 客户端连接服务器(TCP / IP),三次握手,建立了连接通道
  2. 客户端和服务器通过socket接口发送消息和接收消息,任何一端在任何时候,都可以向另一端发送任何消息
  3. 有一端断开了,通道销毁

http

  1. 客户端连接服务器(TCP / IP),三次握手,建立了连接通道
  2. 客户端发送一个http格式的消息(消息头 消息体),服务器响应http格式的消息(消息头 消息体)
  3. 客户端或服务器断开,通道销毁

实时性的问题:

  1. 轮询
  2. 长连接

websocket

专门用于解决实时传输的问题

  1. 客户端连接服务器(TCP / IP),三次握手,建立了连接通道
  2. 客户端发送一个http格式的消息(特殊格式),服务器也响应一个http格式的消息(特殊格式),称之为http握手
  3. 双发自由通信,通信格式按照websocket的要求进行
  4. 客户端或服务器断开,通道销毁

websocket 可以用来解决客户端长时间的连接

这里推荐socker.io插件的 使用 省去了手写websocket
因为socket的 http是特殊格式 使用 直接用socket.io 省去很多麻烦
而且socket.io 也很方便

下载

npm i socket.io

使用

node中使用

const express = require("express");
const socketIO = require("socket.io");
const http = require("http");
const path = require("path");

// express
const app = express();
const server = http.createServer(app);
app.use(express.static(path.resolve(__dirname, "public")));

// websocket
const io = socketIO(server);

io.on("connection", (socket) => {
  // 当有一个新的客户端连接到服务器成功之后,触发的事件
  console.log("新的客户端连接进来了");
  socket.on("msg", (chunk) => {
    // 监听客户端的msg消息
    console.log(chunk.toString("utf-8"));
  });
  const timer = setInterval(function () {
    //每隔两秒钟,发送一个消息给客户端,消息为test
    socket.emit("test", "test message from server");
  }, 2000);

  socket.on("disconnect", () => {
    clearInterval(timer);
    console.log("closed");
  });
});

// 监听端口
server.listen(5008, () => {
  console.log("server listening on 5008");
});

有很多配置 可以参考socket.io官网https://socket.io

利用

利用socket.io 创建一个在想的聊天室
node环境

  • 服务端配置
const socketIO = require("socket.io")

let users = [] //保存当前登录的用户

module.exports = function (server) {
  const io = socketIO(server)
  io.on('connection', (socket) => {
    let curUser = '';
    // console.log('连接成功');
    socket.on('login', (data) => {
      if (data === '所有人' || users.filter((u) => u.username === data).length > 0) {
        //昵称不可用
        socket.emit('login', false)
      } else {
        curUser = data;
        users.push({
          username: data,
          socket,
        })
        socket.emit('login', true)
        // console.log(data);
        socket.broadcast.emit('userin', data)
      }

    })

    socket.on("users", () => {  //将登录的用户抛给客户端展示
      const arr = users.map((u) => u.username);
      socket.emit("users", arr);
    });
    socket.on("msg", (data) => {
      if (data.to) {
        // 发送给指定的用户
        const us = users.filter((u) => u.username === data.to);
        const u = us[0];
        u.socket.emit("new msg", {
          from: curUser,
          content: data.content,
          to: data.to,
        });
      } else {
        // 发送给所有人
        socket.broadcast.emit("new msg", {
          from: curUser,
          content: data.content,
          to: data.to,
        });
      }
    });
    socket.on("disconnect", () => {
      socket.broadcast.emit("userout", curUser);
      users = users.filter((u) => u.username !== curUser);
    });
  })
}

1.客户端按回车登录之后,会把可用的username和socket对象保存到users里面 并且触发客户端的login事件和给其他socket对象广播userin事件 然后客户端会执行login事件且触发服务端users事件 其他socket对象会执行客户端userin事件 然后客户端users事件执行会触发客户端的users事件 之后就会把登录的用户展示在页面 相当于用来更新用户列表
2. 客户端关闭连接之后 服务端会触发disconnect事件 然后会清除该退出的用户名称 并且触发其他socket的 客户端的 useout事件 告诉其他 谁退出聊天室
3. 客户端发送信息 会触发 服务端的msg事件 然后服务端会接收到 消息来自于谁 内容是什么 发给谁 然后服务端就会获取到 发给谁 然后触发客户端的new msg事件 将 来自于 内容 和发给谁 传过去 然后客户端执行并且更新界面

  • 客户端配置
const socket = io.connect();

// // 客户端发送消息给服务器
page.onLogin = function (username) {
  socket.emit("login", username);
};

page.onSendMsg = function (me, msg, to) {
  socket.emit("msg", {
    to,
    content: msg,
  });
  page.addMsg(me, msg, to);
  page.clearInput();
};

// 客户端监听服务器消息
socket.on("login", (result) => {
  if (result) {
    page.intoChatRoom();
    socket.emit("users", "");
  } else {
    alert("昵称不可用,请更换昵称");
  }
});

socket.on("users", (users) => { //为了添加用户 进行展示
  page.initChatRoom();
  console.log(users);
  for (const u of users) {
    page.addUser(u);
  }
});

socket.on("userin", (username) => {
  page.addUser(username);
  console.log(username);
  // page.initChatRoom();
});

socket.on("userout", (username) => {
  page.removeUser(username);
});

socket.on("new msg", (result) => {
  page.addMsg(result.from, result.content, result.to);
});
  • 页面其他代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>在线聊天室</title>
    <link rel="stylesheet" href="./css/global.css" />
    <link rel="stylesheet" href="./css/index.css" />
  </head>
  <body>
    <div class="login">
      <div class="form">
        <h1>请输入你的昵称,回车后进入聊天室</h1>
        <input type="text" />
      </div>
    </div>
    <div class="chat" style="display: none;">
      <div class="user-list">
        <div class="title">在线人数:<span>0</span></div>
        <ul class="users">
          <li class="all">所有人</li>
        </ul>
      </div>

      <div class="main">
        <ul class="chat-list">
          <li class="log">欢迎来到渡一聊天室</li>
        </ul>
        <div class="sendmsg">
          <span class="gray"></span>
          <span class="user">所有人</span>
          <span class="gray">说:</span>
          <input type="text" />
        </div>
      </div>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <script src="js/ui.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
    <script src="./js/chat.js"></script>
  </body>
</html>

ui.js

const page = (function () {
  const userList = $(".users");
  const chatList = $(".chat-list");
  function intoChatRoom() {
    $(".login").hide();
    $(".chat").show();
  }

  function addUser(userName) {
    $("<li>").text(userName).attr("user", userName).appendTo(userList);
    const number = +$(".user-list .title span").text();
    $(".user-list .title span").text(number + 1);
    addLog(`<span class="user">${userName}</span> 进入聊天室`);
    chatList.scrollTop(chatList.prop("scrollHeight"), 0);
  }

  function addLog(log) {
    $("<li>").addClass("log").html(log).appendTo(chatList);
  }

  function removeUser(userName) {
    const li = userList.find(`li[user="${userName}"`);
    if (!li.length) {
      return;
    }
    li.remove();
    const number = +$(".user-list .title span").text();
    $(".user-list .title span").text(number - 1);
    addLog(`<span class="user">${userName}</span> 退出了聊天室`);
  }

  function clearInput() {
    $(".sendmsg input").val("");
  }

  function addMsg(from, msg, to) {
    const li = $("<li>")
      .html(`<span class="user">${from}</span> <span class="gray">对</span> 
    <span class="user">${
      to ? to : "所有人"
    }</span> <span class="gray">说:</span> `);
    const msgSpan = $("<span>").text(msg);
    li.append(msgSpan).appendTo(chatList);
    chatList.scrollTop(chatList.prop("scrollHeight"), 0);
  }

  function getTargetUser() {
    const user = $(".sendmsg .user").text();
    return user === "所有人" ? null : user;
  }

  function initChatRoom() {
    userList.html(`<li class="all">所有人</li>`);
    $(".user-list .title span").text(0);
    chatList.html(`<li class="log">欢迎来到渡一聊天室</li>`);
  }

  userList.click((e) => {
    if (e.target.tagName === "LI") {
      $(".sendmsg .user").text(e.target.innerText);
    }
  });

  return {
    me: null,
    intoChatRoom,
    initChatRoom,
    addUser,
    addLog,
    removeUser,
    addMsg,
    clearInput,
    getTargetUser,
    onLogin: null,
    onSendMsg: null,
  };
})();

(function () {
  $(".login input").keydown((e) => {
    if (e.key === "Enter") {
      page.me = $(e.target).val();
      page.onLogin && page.onLogin(page.me);
    }
  });
  $(".sendmsg input").keydown((e) => {
    if (e.key === "Enter") {
      page.onSendMsg &&
        page.onSendMsg(page.me, $(e.target).val(), page.getTargetUser());
    }
  });
})();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值