##### 什么是Socket.io
一個(gè)基于 Node.js 的實(shí)時(shí)應(yīng)用程序框架,在即時(shí)通訊、通知與消息推送,實(shí)時(shí)分析等場(chǎng)景中有較為廣泛的應(yīng)用
##### 什么是egg-socket.io
- 對(duì)socket.io的二次封裝, 增加了一些開(kāi)發(fā)規(guī)范
- 增加namespace(命名空間), 可以通過(guò)配置的方式定義
- 增加middleware, 對(duì)每一次socket連接的建立、斷開(kāi)、消息和數(shù)據(jù)傳遞進(jìn)行預(yù)處理
- controller, 相應(yīng)socket.io的event事件
- router, 同一了socket.io的event與框架路由的處理配置方式
##### 把egg-socket.io整合到我們的egg項(xiàng)目中
不知道怎么搭建egg項(xiàng)目的翻下以前的文章
- 安裝egg-socket.io
```
cnpm i egg-socket.io -S
```
- 開(kāi)啟插件
{app_root}/config/plugin.js
```
exports.io = {
? enable: true,
? package: 'egg-socket.io',
};
```
- 配置egg-socket.io
{app_root}/config/config.default.js
```
module.exports = appInfo => {
? const config = exports = {
? ? io: {
? ? ? # namespace命名空間配置為/
? ? ? namespace: {
? ? ? ? '/': {
? ? ? ? ? # 預(yù)處理器中間件, 我們這里配置了一個(gè)auth, 進(jìn)行權(quán)限判斷, 它對(duì)應(yīng)的文件是/app/io/middleware/auth.js, 這里可以配置多個(gè)文件, 用逗號(hào)隔開(kāi)
? ? ? ? ? connectionMiddleware: ['auth'], #這里我們可以做一些權(quán)限校驗(yàn)之類的操作
? ? ? ? ? packetMiddleware: [], # 通常用于對(duì)消息做預(yù)處理,又或者是對(duì)加密消息的解密等操作
? ? ? ? },
? ? ? },
? ? ? # 配置redis, 非必須, 不需要的可以不配置這塊, egg-socket.io內(nèi)置了socket-io-redis, 在cluster模式下, 使用redis可以較為簡(jiǎn)單的實(shí)現(xiàn)clients/rooms等信息共享
? ? ? redis: {
? ? ? ? host: 'ip地址',
? ? ? ? prot: 6379,
? ? ? ? auth_pass: 123456,
? ? ? ? db:0,
? ? ? }
? ? }
? };
? 省略 .....
};
```
到這里egg-socket.io已經(jīng)開(kāi)啟并配置完畢了, 接下來(lái)我們就要編寫路由和控制器了
- 先來(lái)看下egg-socket.io的項(xiàng)目目錄結(jié)構(gòu)
```
your-project-name
├── app
│? ├── extend
│? │? └── helper.js
│? ├── io
│? │? ├── controller
│? │? │? └── chat.js
│? │? └── middleware #插件中間件, 基于 socket 模型設(shè)計(jì),處理 socket.io 請(qǐng)求
│? │? ? ? ├── auth.js #對(duì)應(yīng)剛才配置的connectionMiddleware: ['auth']
│? └── router.js
├── config
└── package.json
```
- 先配置路由
/app/router.js
```
module.exports = app => {
? const { router, controller, io } = app;
? //http 接口, 在對(duì)應(yīng)的控制器中可以直接操作socket, 非常方便
? router.get('/', controller.home.index);
? router.get('/user', controller.user.index);
?
? // socket, 指向app/io/controller/chat.js的index方法
? io.route('chat', app.io.controller.chat.index);
};
```
- 然后創(chuàng)建auth.js
app/io/middleware/auth.js
```
const room = "default_room";
module.exports = () => {
? ? return async(ctx, next) => {
? ? ? ? // 權(quán)限校驗(yàn)通過(guò)
? ? ? ? ctx.socket.emit('res', 'auth success');
? ? ? ? // 加入房間
? ? ? ? socket.join(room);
? ? ? ? // 放行
? ? ? ? await next();
? ? ? ? console.log('斷開(kāi)連接');
? }
};
```
- 最后創(chuàng)建聊天控制器
app/io/controller/chat.js
```
'use strict';
const Controller = require('egg').Controller;
const room = 'default_room';
class ChatController extends Controller {
? ? async index(){
? ? ? ? const {app, socket, logger, helper} = this.ctx;
? ? ? ? const id = socket.id;
? ? ? ? // 根據(jù)id給指定連接發(fā)送消息
? ? ? ? nsp.sockets[id].emit('res', "hello ....");
? ? ? ? // 指定房間連接信息列表
? ? ? ? nsp.adapter.clients([room], (err, clients) => {
? ? ? ? ? ? console.log(JSON.stringify(clients));
? ? ? ? });
? ? ? ? //? 給指定房間的每個(gè)人發(fā)送消息
? ? ? ? this.ctx.app.io.of('/').to(room).emit('online', this.ctx.socket.id+ "上線了");
? ? ? ? // 斷開(kāi)連接
? ? ? ? this.ctx.socket.disconnect();
? ? }
}
module.exports = ChatController;
```
- 通過(guò)調(diào)用http接口給客戶端發(fā)送消息
說(shuō)白了就是在http接口的控制器中發(fā)送socket消息
app/controller/home.js
```
const Controller = require('egg').Controller;
class HomeController extends Controller {
? async index() {
? ? const {app, query} = this.ctx;
? ? // 給誰(shuí)發(fā), socket連接的id
? ? const id = query.id;
? ? const nsp = app.io.of('/');
? ? if(nsp.sockets[id]){
? ? // 通過(guò)id給指定socket連接發(fā)送消息
? ? ? nsp.sockets[id].emit('res', 'hello http....');
? ? }
? ? this.ctx.body = "發(fā)送成功";
? }
}
module.exports = HomeController;
```
到這里服務(wù)端完成, 下面我們來(lái)寫一個(gè)簡(jiǎn)單的socket.io客戶端
```
const socket = require('socket.io-client')('http://127.0.0.1:7001');
// 連接服務(wù)端
socket.on('connect', () => {
? console.log('connect!');
? socket.emit('chat', 'hello world!');
});
//接收消息通知
socket.on('res', msg => {
? console.log('res from server: %s!', msg);
});
// 接收上線通知
socket.on('online', msg=>{
? console.log('online from server: %s!', msg);
});
```
到這就結(jié)束了, 有問(wèn)題留言!!!