詳解一個基于套接字實(shí)現(xiàn)長連接的express
邏輯: 首先把routerUrl目錄下的函數(shù)初始化緩存起來,通過Router.request調(diào)用緩存起來的函數(shù),這個函數(shù)實(shí)際上是register.set方法,主要是開始運(yùn)行函數(shù)鏈,通過register.next 運(yùn)行下一個函數(shù)。
函數(shù)流 main.js --> Router.request --> register.set --> register.next --> sock.write
main.js
'use strict';
const routerUrl = 'router'; // 當(dāng)前目錄下的router地址
const Router = require('./net/Router'); // 初始化路由
const net = require('net');
const port = '3000';
Router.init(routerUrl);
const app = sock => {
sock.on('data', function (data) {
try {
Router.request(data, sock);
} catch (error) {
console.log(error)
}
});
sock.on('error', (err) => {
console.log(err)
})
// 為這個socket實(shí)例添加一個"close"事件處理函數(shù)
sock.on('close', function (data) {
console.log('clone')
})
}
const server = net.createServer(app);
server.listen(port, () => {
console.log(`Startu in env ${process.env.NODE_ENV || 'development'} on port ${port}`);
});
server.on('error', (err) => {
console.log(err)
})
路由加載:
Router.js文件
const fs = require('fs');
const _ = require('lodash');
var path = require("path");
var ROOT_PATH = path.resolve(__dirname);
class Router {
constructor() {
this.routeMap = {};
}
/**
* 通過routerUrl來匹配目錄下的文件,加載進(jìn)來
* @param {*} routerUrl
*/
init(routerUrl) {
let files = fs.readdirSync(path.join(ROOT_PATH, `../${routerUrl}`));
return _.reduce(files, (config, file) => {
let svc = require(path.join(ROOT_PATH, `../${routerUrl}/${file}`));
this.routeMap = {
[file.split('.')[0]]: svc.get()
};
}, {})
}
/**
* 通過url匹配加載的router, 其他字段可自定義,url這里的邏輯也可改成配置文件進(jìn)行配置,類似于protobuf
* @param {*} data {url, body}
* @param {*} sock
*/
request(data, sock) {
try {
this.routeMap[result.url.split('/')[1]][result.url.replace(`/${result.url.split('/')[1]}`, '')](data, sock);
} catch (error) {
sock.write(error);
}
}
}
module.exports = new Router();
中間件:
register.js文件
const Next = require('./next');
class Register {
constructor() {
this._init = {};
}
<!-- 初始化router函數(shù),開始運(yùn)行函數(shù)鏈 -->
set(url, ...handlers) {
this._init[url] = async (data, sock) => {
try {
let next = new Next(handlers);
next.run(data, sock);
} catch (error) {
sock.write(error);
}
};
}
<!-- 獲取初始化的router函數(shù) -->
get() {
return this._init;
}
}
module.exports = new Register();
nest.js文件
class Next {
constructor(stack) {
this.index = 0;
this.stack = stack;
this.data = null;
this.sock = null;
}
<!-- 運(yùn)行中間件 -->
run(data, sock) {
this.data = data;
this.sock = sock;
this.stack[this.index](data, sock, this.next.bind(this));
}
<!-- 調(diào)到下一個中間件,若帶參數(shù)就跳到第arguments[0]步 -->
next() {
if (arguments[0] && arguments[0] === +arguments[0] && +arguments[0] < this.stack.length) {
this.index = +arguments[0];
return this.run(data, this.sock);
}
this.index++;
this.run(this.data, this.sock);
}
}
module.exports = Next;
注冊文件
const init = require('../net/register');
init.set('/test',
(data, sock, next) => {
next()
},
async (data, sock) => {
try {
sock.write(test);
} catch (e) {
sock.write(e);
}
});
總結(jié):這個項(xiàng)目只是用來歇息express的思想,要用在實(shí)際開發(fā)中還需要斷線重連,優(yōu)化連接,異常處理等功能。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Node.js數(shù)據(jù)庫操作之查詢MySQL數(shù)據(jù)庫(二)
這篇文章主要介紹了Node.js數(shù)據(jù)庫操作之查詢MySQL數(shù)據(jù)庫的相關(guān)資料,文中介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用mysql能帶來一定的幫助,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03
Nodejs進(jìn)階:如何將圖片轉(zhuǎn)成datauri嵌入到網(wǎng)頁中去實(shí)例
這篇文章主要介紹了Nodejs進(jìn)階:如何將圖片轉(zhuǎn)成datauri嵌入到網(wǎng)頁中去,有興趣的可以了解一下。2016-11-11
Electron如何通過ffi-napi調(diào)用dll導(dǎo)出接口
文章介紹了如何在Electron項(xiàng)目中使用ffi-napi模塊調(diào)用DLL文件,并詳細(xì)描述了環(huán)境搭建、安裝Electron和ffi-napi、配置Visual Studio和Python環(huán)境、解決常見問題等步驟,感興趣的朋友跟隨小編一起看看吧2025-02-02
node.js express捕獲全局異常的三種方法實(shí)例分析
這篇文章主要介紹了node.js express捕獲全局異常的三種方法,結(jié)合實(shí)例形式簡單分析了node.js express捕獲全局異常的常見操作方法與使用注意事項(xiàng),需要的朋友可以參考下2019-12-12
nodejs中使用worker_threads來創(chuàng)建新的線程的方法
這篇文章主要介紹了nodejs中使用worker_threads來創(chuàng)建新的線程的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
node 安裝 windows-build-tools全過程
這篇文章主要介紹了node 安裝 windows-build-tools全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10

