早期写一个没有socket.io时,写一个即时通讯的web应用是非常困难的,需要不断地向服务端轮询,而且速度非常慢。Socket.io的产生就是为了解决即使通讯,它能够提供一个专门的通道来实现客户端和服务端的双向交流。这意味着,服务端可以实时地向客户端推送消息,你在客户端输入的聊天信息也可以推送到服务端,服务端接收到你的聊天信息,可以转发给其他与其相连的客户端。

通过一个即时聊天应用demo来了解socket.io的使用方法

How To Do

首先使用 npm init 创建一个项目,生成package.json文件。

文件目录结构如下:

1
2
3
4
5
6
7
8
├── README.md
├── node_modules
├── package.json
├── client
│   ├── client.css
│   ├── client.js
│   └── index.html
└── server.js

安装相关依赖库,我们使用 express 作为服务端的框架。

1
2
npm install --save express
npm install --save socket.io

安装完相关依赖我们就可以进行开发,先进行服务端的开发。

创建 server.js 文件作为服务端入口文件

1
2
var express = require('express');
var app = express();

创建一个express应用

1
var server = require('http').Server(app);

创建一个http服务,参数 app 是将所有的请求都交个app来处理

1
var io = require('socket.io')(server);

初始化一个socket.io实例,参数 server 是将这个实例和http服务绑定

1
app.use(express.static(__dirname + '/client'));

app.use() 用来处理http请求的中间件,我理解为定义接受请求后需要依次执行的任务。

express.static 是 express 内置的唯一一个中间件,负责托管 express 应用内的静态资源,把文件目录作为参数传递给该函数,就可以通过路径访问托管的静态资源。

1
2
3
4
var port = process.env.PORT || 3000;
server.listen(3000, function() {
console.log('Server listening at port %d', port);
});

配置服务端访问端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var userNum = 0; // 记录当前建立socket连接的用户数量

io.on('connection', function(socket) {
socket.on('add user', function(username) {

socket.username = username; // 为socket连接进行相关配置
++userNum; // 建立socket连接后加1

// 触发一个信号量,将userNum信息传递给客户端
socket.emit('user login', {
userNum: userNum
});

// 广播一个信号量,目标为其他与服务端建立socket连接的客户端
socket.broadcast.emit('user joined', {
username: socket.username,
userNum: userNum
});
});
});

当接收到客户端连接的请求后,接收一个socket实例,然后进行信号量监听的注册,监听 add user 信号量。代码理解可参看代码中的注释。

接下来我们进行客户端的开发

在client目录下创建 index.htmlclient.jsclient.css 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Socket.IO chat</title>
<link rel="stylesheet" href="client.css">
</head>
<body>
<ul class="pages">
<li class="chat page">
<div class="chatArea">
<ul class="messages"></ul>
</div>
<input class="inputMessage" placeholder="Type here..."/>
</li>
<li class="login page">
<div class="form">
<h3 class="title">What's your nickname?</h3>
<input class="usernameInput" type="text" maxlength="14" />
</div>
</li>
</ul>

<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script src="/client.js"></script>
</body>
</html>

模板中定义了 login pagechat page 两个页面。
引入了 socket.iojquery 库文件,以及自定义的 client.js

$(function() {
    var socket = io(); // 进行socket连接

    var username;

    var setUsername = function() {
        username = $('.usernameInput').val().trim();

        if(username) {
            socket.emit('add user', username);
        }
    };

    var sendMessage = function() {};

    $(window).keydown(function(event) {
        if(event.which === 13) {
            if (username) {
                sendMessage();
            } else {
                setUsername();
            }
        }
    });

    // 发布登录离开信息
    var log = function(data) {
        $('.messages').append('<li class="log">' + data + '</li>');
    };

    // 发布在线人数消息
    var addParticipantsInfo = function(data) {
        $('.messages').append("<li class='log'>" + "there's " + data.userNum + " participant(s)" + "</li>");
    }; 

    // 消息监听
    socket.on('user login', function(data) {
        var welcomeMessage = 'Welcome to Socket.IO Chat - ';
        log(welcomeMessage);

        addParticipantsInfo(data);
    });
});

$(function(){})$(document).ready(function(){}) 的简写,用来在DOM加载完成之后执行一系列预先定义好的函数

var socket = io() 创建了一个socket连接,返回一个socket实例,实例可以进行一系列配置、信号量注册及回调函数的定义。io() 中可进行参数配置,这里使用默认值,与 http://localhost:3000 建立socket连接。

How to Run

在项目就根目录执行 node server.js 开启服务,浏览器中多个Tab页访问 http://localhost:3000 开聊

Resource

完整代码 socket-chart-example