socket.io/get started

原文链接:https://socket.io/get-started/chat/

仅用于学习参考,欢迎指出翻译错误Q^Q

开始:聊天应用

我们将在这个指导手册中创建一个简单的聊天应用。使用这个手册,你几乎不需要有任何有关于Node.JS或者Socket.IO的知识,所以,这个手册适合任何知识层级的人使用。

简介

用当下流行的web技术栈比如LAMP(PHP)写一个聊天应用是非常困难的。它需要不断的轮询服务器以期做出改变,也需要持续跟踪时间戳,而且这比期望的慢。

Sockets是传统意义上的聊天系统架构的解决方案,它为服务器和客户端提供了双向的通信渠道。

网页框架

第一个任务就是建立一个能向服务器端发送消息的包含一个表单和列表的的简易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:

npm install --save express@4.15.2

我们已经安装了express,现在我们可以创建一个index.js文件以便开始写我们的应用。

var app = require('express')();
var http = require('http').Server(app);

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

上面的语句解释如下:

  1. Express初始化的用于函数处理的app可以提供一个http服务器(第二行)。
  2. 我们定义了一个处理路径/用于在我们访问主页面时执行回调函数。
  3. 我们让这个http服务器监听3000端口

如果你执行node index.js命令,则可以看到以下内容:
在控制台输出的监听端口号

如果你用浏览器打开http://localhost: 3000:
打开链接能看到的页面内容

传输HTML文件

到目前为止在index.js中,我们调用了res.send并传给它一个HTML字符串。如果我们把所有的HTML应用代码都放在这里,我们的代码看起来会极具迷惑性。所以,我们要单独创建一个index.html文件并传输它。

让我们重构路径处理部分,用sendFile来替代:

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; 
      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>
</html>

如果你重启进程(通过点击Control+C终止后再次执行node index.js)并且刷新页面,页面会显示如下:
重启刷新后的页面

结合Socket.IO提供服务

Socket.IO由两部分组成:

  • 一个是基于Node.JS HTTP Server的serversocket.io
  • 一个是从浏览器加载的客户端的库:socket.io-client

在开发过程中,socket.io为我们客户端提供的服务是自动的,到目前为止,我们知道,我们只需要安装了一个模块:

npm install --save socket.io

这个操作会安装相应的模块并把依赖添加到package.json中,现在让我们来修改并增加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('a user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

值得注意的是,我通过传递http(the HTTP server)对象初始化了一个socket.io实例。然后,通过监听connection事件来得到发来的信息并打印出来。

把如下代码片段添加到index.html中的</body>标签前:

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

这是加载socket.io-client所需要做的全部,这里定义了一个全局的io,这样就能前后端通信了。

在这里值得注意的是当我调用io()时并没有指定具体的URL,因为它默认会尝试连接主机服务该页面。

如果你现在重启服务器刷新页面,你可以看见控制台中打印出的"a user connected"。试着打开几个页面,你可以看见相应数量的信息输出:
有页面接入的输出信息

每个socket也都带有一个特殊的disconnect事件:

io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });
});

再次刷新一个网页窗口几次你可以看见以下改变:
断开连接输出相应消息

事件传输

Socket.IO的主要思想既是你可以发送和接收所有你想要发送和接收的事件数据。所有对象都可以编码为JSON,同时也支持二进制数据。

让我们来实现一个当用户键入信息时服务器可以接收到一个聊天信息的事件的功能。现在,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(){
      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);
  });
});

结果如动图所示:https://i.cloudup.com/transcoded/zboNrGSsai.mp4

广播

接下来的目标是把事件从服务器发送到其余连接的用户处。

为了把事件发送给所有人,Socket.IO提供了io.emit:

io.emit('some event', { for: 'everyone' });

如果你想要发送一个消息给所有人而不是某个具体的socket,我们可以用broadcast标记:

io.on('connection', function(socket){
  socket.broadcast.emit('hi');
});

在这种情况下, 我们可以简单的把消息发送到每个人,包括发送这个消息的人。

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

同时在客户端当我们捕获一个消息事件时我们把这个消息呈现在页面上。现在客户端的JavaScript代码如下所示:

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

在20行代码内完成了我们完整的聊天应用,下面是它的样子:https://i.cloudup.com/transcoded/J4xwRU9DRn.mp4

克隆这个例子
$ git clone https://github.com/socketio/chat-example.git