4

一、基本概念

Socket.IO 是一个基于 Node.js 的实时应用程序框架,在即时通讯、通知与消息推送,实时分析等场景中有较为广泛的应用。

WebSocket 的产生源于 Web 开发中日益增长的实时通信需求,对比基于 http 的轮询方式,它大大节省了网络带宽,同时也降低了服务器的性能消耗; socket.io 支持 websocket、polling 两种数据传输方式以兼容浏览器不支持 WebSocket 场景下的通信需求。

WebSocket是HTML5最新提出的规范,虽然主流浏览器都已经支持,但仍然可能有不兼容的情况,为了兼容所有浏览器,给程序员提供一致的编程体验,SocketIO将WebSocket、AJAX和其它的通信方式全部封装成了统一的通信接口,也就是说,我们在使用SocketIO时,不用担心兼容问题,底层会自动选用最佳的通信方式。因此说,WebSocket是SocketIO的一个子集。

二、应用

首先要制作一个 HTML 页面来提供表单和消息列表。我们使用了基于 Node.JS 的 web 框架 express 。 请确保安装了 Node.JS

首先创建一个 package.json 来描述我们的项目。 推荐新建一个空目录 (这里使用 chat-example)。

{
  "name": "socket-chat-example",
  "version": "0.0.1",
  "description": "my first socket.io app",
  "dependencies": {}
}

安装相关依赖:

npm install --save express@4.15.2
npm install --save socket.io

前端页面:
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; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 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>

  <script src="/socket.io/socket.io.js"></script>
  <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" rel="external nofollow"></script>

<script>
  // 请注意我们在调用 io() 时没有指定任何 URL,因为它默认将尝试连接到提供当前页面的主机。
    /*
    var socket = io();


    $('form').submit(function(){
      alert($('#m').val());
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });
    */

 $(function () {
    var socket = io();
    $('form').submit(function(){
      alert($('#m').val());
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });

    socket.on('chat message', function(msg){
      $('#messages').append($('<li>').text(msg));
    });

    
  });
</script>
</html>

服务端页面 index.js:


// 1、Express 初始化 app 作为 HTTP 服务器的回调函数
var app = require('express')();   
var http = require('http').Server(app)

var io = require('socket.io')(http);


// 2、定义了一个路由 / 来处理首页访问。
/*
app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});
*/
app.get('/', function(req, res) {
  res.sendFile(__dirname + '/index.html');
});


// 3、使 http 服务器监听端口 3000
http.listen(3000, function(){
    console.log('listening on *:3000');
})

// ================== io 通信 =====================
// 客户端页面打开时会和服务端建立连接
/*
io.on('connection', function(socket){
  console.log('a user connected');
});
*/


// 每个 socket 还会触发一个特殊的 disconnect 事件:
/*
io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });
});
*/

// 当用户输入消息时,服务器接收一个 chat message 事件
/*
io.on('connection', function(socket){
   console.log('a user connected');

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

// 广播,讲消息发送给所有用户,包括发送者
io.on('connection', function(socket){
  socket.on('chat message', function(msg){

      // 发送消息给客户端(所有客户端都会收到)
    io.emit('chat message', msg);
  });
});

    

启动服务:

dell@DESKTOP-KPEE6OO MINGW64 /C/work/other/socket-chat
$ node index.js
listening on *:3000

访问界面:
image.png

三、升级版

先看界面:
image.png

服务端 index_plus.js

//创建一个http服务器
var app = require('http').createServer()

// 把http封装成io对象
var io = require('socket.io')(app)

// 运行的服务器端口号
var PORT = 3000
var clientCount = 0

// 监听端口
app.listen(PORT)

io.on('connection', function (socket) {
  // 给每个用户取名字
  clientCount++
  socket.nickname = 'user' + clientCount

  // io.emit代表广播,socket.emit代表私发
  io.emit('enter', socket.nickname + '  comes in')

   // socket.on 表示服务器接收一个客户端message 事件
  socket.on('message', function (str) {
    // io.emit表示从服务端给客户端发送一个消息
    io.emit('message', socket.nickname + ' says: ' + str)
  })

  // 客户端断开,自带事件
  socket.on('disconnect', function () {
    io.emit('leave', socket.nickname + ' left')
  })
})

客户端:index_plus.html

<!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>
  <!-- cdn -->
  <script src="https://cdn.bootcss.com/socket.io/2.3.0/socket.io.js"></script>
</head>

<body>
  <h1>聊天室</h1>
  <input id="sendTxt" type="text" />
  <button id="sendBtn">发送</button>
  <div id="recv"></div>
  <script type="text/javascript">

    var socket = io("ws://localhost:3000/");

    //把接收的数据显示到界面
    function showMessage(str, type) {
      var div = document.createElement('div');
      div.innerHTML = str;
      if (type == "enter") {
        div.style.color = 'blue';
      } else if (type == "leave") {
        div.style.color = "red"
      }
      document.body.appendChild(div)
    }

    // 点击之后发送
    document.getElementById("sendBtn").onclick = function () {
      var txt = document.getElementById("sendTxt").value;
      if (txt) {        // 文本不为空发送
        socket.emit('message', txt);
      }
    }

    // 第一个enter代表是进入事件,第二个enter为了显示需要
    socket.on('enter', function (data) {
      showMessage(data, 'enter')
    })

    socket.on('message', function (data) {
      showMessage(data, 'message')
    })

    socket.on('leave', function (data) {
      showMessage(data, 'leave')
    })


  </script>
</body>
</html>

启动:

dell@DESKTOP-KPEE6OO MINGW64 /C/work/other/socket-chat
$ node index_plus.js

四、事件速查表

io.on('connect', onConnect);

function onConnect(socket){

  // 发送给当前客户端
  socket.emit('hello', 'can you hear me?', 1, 2, 'abc');

  // 发送给所有客户端,除了发送者
  socket.broadcast.emit('broadcast', 'hello friends!');

  // 发送给同在 'game' 房间的所有客户端,除了发送者
  socket.to('game').emit('nice game', "let's play a game");

  // 发送给同在 'game1' 或 'game2' 房间的所有客户端,除了发送者
  socket.to('game1').to('game2').emit('nice game', "let's play a game (too)");

  // 发送给同在 'game' 房间的所有客户端,包括发送者
  io.in('game').emit('big-announcement', 'the game will start soon');

  // 发送给同在 'myNamespace' 命名空间下的所有客户端,包括发送者
  io.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon');

  // 发送给指定 socketid 的客户端(私密消息)
  socket.to(<socketid>).emit('hey', 'I just met you');

  // 包含回执的消息
  socket.emit('question', 'do you think so?', function (answer) {});

  // 不压缩,直接发送
  socket.compress(false).emit('uncompressed', "that's rough");

  // 如果客户端还不能接收消息,那么消息可能丢失
  socket.volatile.emit('maybe', 'do you really need it?');

  // 发送给当前 node 实例下的所有客户端(在使用多个 node 实例的情况下)
  io.local.emit('hi', 'my lovely babies');

};

提示: 下面的事件是保留的,不应该在应用中用作事件名称:

  • error
  • connect
  • disconnect
  • disconnecting
  • newListener
  • removeListener
  • ping
  • pong

相关文章:
Socket.io官方示例
socket.io 快速入门教程——聊天应用
Java SocketIO实现消息推送
WebRTC 入门教程(一)| 搭建WebRTC信令服务器


Corwien
6.3k 声望1.6k 粉丝

为者常成,行者常至。