关于 socket.io 、 node 的一些问题

1,075 阅读3分钟

webscoket

webscoket可以在用户的浏览器和服务器之间打开交互式通信会话。使用此API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。

webscoket

webscoket是什么/有什么用?

找到一个比较细的文章socket.io

将webscoket到scoket.io都讲了一遍?

在平常的开发中 也多使用scoket.io居多,因为它解决了很多类似于兼容性的问题。

下面的例子我们也使用它来做。

另外我了解到,当你使用scoket.io 那么必须使用对应的 scoket.io-client作为前端的操作工具。

scoket.io 的一些常用api总结。

具体的api请看这个 scoket.io

有几个常用的api

on : 监听约定的事件

  • socket.on()用于监听获取发送过来的数据

  • socket.on('monitorName', callBack)有两个参数:

    • monitorName:监听的标识

    • callBack:是一个回调函数

emit : 触发指定的事件 播给 所有人

  • socket.emit()用于发送数据

  • socket.emit('monitorName', sendData)有两个参数:

    • monitorName:监听的标识

    • sendData:可以是字符串,也可以是{}JSON对象,这是向后端发送过去的数据

broadcast.emit : 事件广播

  • 广播给除自己以外的所有人

io.to(clientId): 向指定的人广播

  • clientId : 指定人的连接ID

webscoket 怎么用(前端)?

拿 vue组件举个例子

假设我们的后端使用的就是scoket.io

那么前端,首先你需要在命令行安装 scoket.io-client

然后在main.js中引用它

如下:


  // 终端
  npm i socket.io-client

  // main.js
  import io from 'socket.io-client';

我们通常在mounted中对一些插件进行初始化


{
  mounted(){

    // 这个实例化需要传递一个地址如:http://localhost:8888/self
    let myScoket = io.connect('http://localhost:8888/self')

    // 实时监听后端返回数据
    myScoket.on('事件名',()=>{

    })

    // 主动发送给后端数据
    myScoket.emit('事件名',()=>{

    })

    
  }
}

webscoket 怎么用(后端)?

以nodejs koa2框架为例子


  # npm安装socket.io
  
  $ npm install --save socket.io

服务端挂载有两种方式


  // 方式1

  // 这种方式将和服务公用一个端口 ,但是需要配置 cors:true 来避免跨域
  var http = require('http');

  var port = normalizePort(process.env.PORT || '3000');

  var server = http.createServer(app.callback());

  const io = require('socket.io')(server,{
    cors:true,
    serveClient: false,
    pingInterval: 10000,
    pingTimeout: 5000,
  });

  server.listen(port);

  // 方式2
  // 直接定义端口
  // 目前看没什么不同
  const io = require('socket.io')(3000, {
    path: '/path',
    serveClient: false,
    // below are engine.IO options
    pingInterval: 10000,
    pingTimeout: 5000,
    cookie: false
  });


服务端处理链接 和 分发数据.


  // 开启一个命名空间
  const typing = io.of('typing')

  // 设置一个游戏链接池
  let games = {}

  typing.on('connection', client => {
    
    // 我们每次连接都将连接id 对应为空
    
    if (!games[client.id]) {
      games[client.id] = null
    }

    // 并且广播出去

    client.broadcast.emit('userList', {games})

    // 这里发现广播不能广播给自己  所以,我们增加一个发送事件把当前的状态给到前端
    client.emit('init', {games})

    // 检查自己和目标用户是不是已经和别人连接游戏,如果没有就请求连接游戏
    client.on("send_request_to_server", (data) => {
      if (!games[data.clientId] && !games[client.id]) {
        // 使用to函数传入对应的链接id,给对应的链接发送链接请求
        typing.to(data.clientId).emit('send_request_to_client', {
          clientId: client.id
        });
      }
    })

    // 这里我们设置P1 P2 为一组游戏
    // 监听用户点击接受请求
    client.on('request_ok_to_server', (data) => {
      // 我们建立链接 将P1的ID 对应 P2的ID 
      games[client.id] = data.clientId
      games[data.clientId] = client.id
      // 并且通知前端 可以开始游戏了
      typing.to(client.id).emit('start')
      typing.to(data.clientId).emit('start')
      client.broadcast.emit('userList', {games})
    })

    // 我们监听P1清除 然后给P2发送P1状态值 
    client.on('delete_to_server', (data) => {
      let p2 = games[client.id]
      if (p2) {
        typing.to(p2).emit('delete_to_client', data)
      }
    })

    // 监听添加 原理同上
    client.on('push_to_server', (data) => {
      let p2 = games[client.id]
      if (p2) {
        typing.to(p2).emit('push_to_client', data)
      }
    })

    // 断开链接
    client.on('disconnect', () => {
      // 从游戏池种删除自己
      delete games[client.id]

      // 断开与游戏好友的游戏
      for (const gamesKey in games) {
        if (games[gamesKey] === client.id) {
          games[gamesKey] = null
        }
      }
      
      client.broadcast.emit('userList', {games})

    });

  });