nodejs 高级编程-通信

这篇具有很好参考价值的文章主要介绍了nodejs 高级编程-通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、通信基本原理

通信必要条件

  • 主机之间需要有传输介质
  • 主机上必须有网卡设备
  • 主机之间需要协商网络速率

nodejs 高级编程-通信,网络,智能路由器,node.js

二、网络通讯方式

常见的通讯方式

  • 交换机通讯
  • 路由器通讯

如何建立多台主机互连?

nodejs 高级编程-通信,网络,智能路由器,node.js
如何定位局域网中的其他主机?

通过Mac地址来唯一标识一台主机

  • 交换机接口数量有上限
  • 局域网存在大量主机会造成广播风暴

明确目标主机IP地址
nodejs 高级编程-通信,网络,智能路由器,node.js

三、网络层次模型

七层模型

  • 应用层:用户与网络的接口
  • 表示层:数据加密、转换、压缩
  • 会话层:控制网络连接建立与终止
  • 传输层:控制数据传输可靠性
  • 网络层:确定目标网络
  • 数据链路层:确定目标主机
  • 物理层:各种物理设备和标准

数据从A至B,先封装再解封

四、TCP三次握手和四次挥手

TCP协议

  1. TCP属于传输层协议
  2. TCP是面向连接的协议
  3. TCP用于处理实时通信

nodejs 高级编程-通信,网络,智能路由器,node.js
常见控制字段

  • SYN=1表示请求建立连接
  • FIN=1表示请求断开连接
  • ACK=1表示数据信息确认

三次握手
nodejs 高级编程-通信,网络,智能路由器,node.js
看着4次握手,但是中间两次是同时进行的,进行合并,这样最终就有了3次握手

nodejs 高级编程-通信,网络,智能路由器,node.js

四次挥手
nodejs 高级编程-通信,网络,智能路由器,node.js
1-客户端发送断开连接请求给服务端
2-服务端发送消息确认给客户端
3-服务端发送断开连接请求给客户端
4-客户端发送消息确认给服务端

为什么是三次握手四次挥手呢

三次握手的原因是:防止过期的连接请求到达服务器端,如果只有两次握手,则服务器端会建立一个不需要的连接,因此会造成服务器资源的浪费。

四次挥手的原因是:四次挥手的2-3不能合并,因为一个服务端要服务于多个客户端,不能保证某一个客户端发送断开请求之后服务端立即将结果数据全部传输回给这个客户端

详解参考:https://blog.csdn.net/qzwzsl/article/details/126252110

https://mp.weixin.qq.com/s?__biz=MzI4NjE4NTUwNQ==&mid=2247494421&idx=1&sn=8a1e925f02a3c491c3a0b34f201c344c&chksm=ebe26a5bdc95e34d590609df45c207948c0fd97ec9baee54c70a8993e2c7937c8d0da2086ab2&scene=27
TCP协议

  • TCP处于传输层,基于端口,面向连接
  • 主机之间要想通信需要先建立双向数据通道
  • TCP的握手和挥手本质上都是四次

五、通讯过程-net模块(模拟三次握手与四次挥手)

Net 模块实现了底层通信接口

通信过程

  • 创建服务端:接收和会写客户端数据
  • 创建客户端:发送和接收服务端数据
  • 数据传输:内置服务事件和方法读写数据

通信事件

  • listening 事件:调用 server.listen 方法之后触发
  • connection 事件:新的连接建立时触发
  • close 事件:当 server 关闭时触发
  • error 事件:当错误出现时触发

通信事件&方法

  • data 事件:当接收到数据的时候触发该事件
  • write 方法:在 socket 上发送数据,默认是 UTF8 编码
  • end 操作:当 socket 的一端发送 FIN 包时触发,结束可读端

server.js

const net = require('net')

// 创建服务端实例
const server = net.createServer()

const PORT = 1234
const HOST = 'localhost'

server.listen(PORT, HOST)

server.on('listening', () => {
  console.log(`服务端已经开启在 ${HOST}: ${PORT}`)
})

// 接收消息 回写消息
server.on('connection', (socket) => {
  socket.on('data', (chunk) => {
    const msg = chunk.toString()
    console.log(msg)

    // 回数据
    socket.write(Buffer.from('您好' + msg))
  })
})

server.on('close', () => {
  console.log('服务端关闭了')
})

server.on('error', (err) => {
  if (err.code == 'EADDRINUSE') {
    console.log('地址正在被使用')
  }else{
    console.log(err)
  }
})

client.js

const net = require('net')

const client = net.createConnection({
  port: 1234, 
  host: '127.0.0.1'
})

client.on('connect', () => {
  client.write('success')
})

client.on('data', (chunk) => {
  console.log(chunk.toString())
})

client.on('error', (err) => {
  console.log(err)
})

client.on('close', () => {
  console.log('客户端断开连接')
})

六、TCP粘包及解决

通信包括数据的发送端和接收端

发送端累积数据统一发送

接受端缓冲数据之后再消费

TCP拥塞机制决定发送机制

nodejs 高级编程-通信,网络,智能路由器,node.js
可以看到数据粘在了一起

解决方式:可以加延迟

nodejs 高级编程-通信,网络,智能路由器,node.js

七、封包拆包实现

nodejs 高级编程-通信,网络,智能路由器,node.js

nodejs 高级编程-通信,网络,智能路由器,node.js
数据传输过程

  • 进行数据编码,获取二进制数据包
  • 按规则拆解数据,获取指定长度的数据

Buffer数据读写

  • writeInt16BE:将value从指定位置写入。
  • readInt16BE:从指定位置开始读取数据。

transform.js

class MyTransformCode{
  constructor() {
    this.packageHeaderLen = 4 //字节
    this.serialNum = 0
    this.serialLen = 2
  }

  // 编码
  encode(data, serialNum) {
    const body = Buffer.from(data)

    // 01 先按照指定的长度来申请一片内存空间做为 header 来使用
    const headerBuf = Buffer.alloc(this.packageHeaderLen)

    // 02 
    headerBuf.writeInt16BE(serialNum || this.serialNum)

    headerBuf.writeInt16BE(body.length, this.serialLen)

    if (serialNum == undefined) {
      serialNum++
    }

    return Buffer.concat([headerBuf, body])
  }

  // 解码
  decode(buffer) {
    const headerBuf = buffer.slice(0, this.packageHeaderLen)
    const bodyBuf = buffer.slice(this.packageHeaderLen)

    return {
      serialNum: headerBuf.readInt16BE(),
      bodyLength: headerBuf.readInt16BE(this.serialLen),
      body: bodyBuf.toString()
    }
  }

  // 获取包长度的方法
  getPackageLen(buffer) {
    if (buffer.length < this.packageHeaderLen) {
      return 0
    } else {
      return this.packageHeaderLen + buffer.readInt16BE(this.serialLen)
    }
  }
}

module.exports = MyTransformCode

test.js

const MyTransform = require('./myTransform.js')

let ts = new MyTransform()

let str1 = '11'

// console.log(Buffer.from(str1))
// console.log(ts.encode(str1, 1))

let encodeBuf = ts.encode(str1, 1)

/*let a = ts.decode(encodeBuf)
console.log(a) */

let len = ts.getPackageLen(encodeBuf)
console.log(len)

八、封包解决粘包

server.js

const net = require('net')
const MyTransform = require('./myTransform.js')

const server = net.createServer()

let overageBuffer = null
let ts = new MyTransform()

server.listen('1234', 'localhost')

server.on('listening', () => {
  console.log('服务端运行在 localhost:1234')
})

server.on('connection', (socket) => {
  socket.on('data', (chunk) => {
    if (overageBuffer) {
      chunk = Buffer.concat([overageBuffer, chunk])
    }
    let packageLen = 0
    while(packageLen = ts.getPackageLen(chunk)) {
      const packageCon = chunk.slice(0, packageLen)
      chunk = chunk.slice(packageLen)

      const ret = ts.decode(packageCon)
      console.log(ret)

      socket.write(ts.encode(ret.body, ret.serialNum))
    }
    overageBuffer = chunk
  })
})

client.js

const net = require('net')
const MyTransform = require('./myTransform.js')

let overageBuffer = null 
let ts = new MyTransform()

const client = net.createConnection({
  host: 'localhost', 
  port: 1234
})

client.write(ts.encode('11'))
client.write(ts.encode('22'))
client.write(ts.encode('33'))
client.write(ts.encode('44'))
client.write(ts.encode('55'))

client.on('data', (chunk) => {
  if (overageBuffer) {
    chunk = Buffer.concat([overageBuffer, chunk])
  }
  let packageLen = 0
  while(packageLen = ts.getPackageLen(chunk)) {
    const packageCon = chunk.slice(0, packageLen)
    chunk = chunk.slice(packageLen)

    const ret = ts.decode(packageCon)
    console.log(ret)
  }
  overageBuffer = chunk
})

mytransform.js

class MyTransformCode{
  constructor() {
    this.packageHeaderLen = 4 // 字节
    this.serialNum = 0 
    this.serialLen = 2
  }

  // 编码
  encode(data, serialNum) {
    const body = Buffer.from(data)

    // 01 先按照指定的长度来申请一片内存空间做为 header 来使用
    const headerBuf = Buffer.alloc(this.packageHeaderLen)

    // 02 
    headerBuf.writeInt16BE(serialNum || this.serialNum)

    headerBuf.writeInt16BE(body.length, this.serialLen)

    if (serialNum == undefined) {
      this.serialNum++
    }

    return Buffer.concat([headerBuf, body])
  }

  // 解码
  decode(buffer) {
    const headerBuf = buffer.slice(0, this.packageHeaderLen)
    const bodyBuf = buffer.slice(this.packageHeaderLen)

    return {
      serialNum: headerBuf.readInt16BE(),
      bodyLength: headerBuf.readInt16BE(this.serialLen),
      body: bodyBuf.toString()
    }
  }

  // 获取包长度的方法
  getPackageLen(buffer) {
    if (buffer.length < this.packageHeaderLen) {
      return 0
    } else {
      return this.packageHeaderLen + buffer.readInt16BE(this.serialLen)
    }
  }
}

module.exports = MyTransformCode

九、模拟一个http协议请求

server.js

const net = require('net')

// 创建服务端
let server = net.createServer()
server.listen(1234, () => {
  console.log('服务端启动了....')
})

server.on('connection', (socket) => {
  socket.on('data', (data) => {
    console.log(data.toString())
  })
  socket.end('test http request')
})

client.js

const http = require('http')

// 创建服务端
let server = http.createServer((req, res) => {
  // 针对于请求和响应完成各自的操作
  console.log('1111')
})
server.listen(1234, () => {
  console.log('server is running......')
})

十、获取http请求信息

request.js

const http = require('http')
const url = require('url')

const server = http.createServer((req, res) => {
  // console.log('请求进来了')

  // 请求路径
  let {pathname, query} = url.parse(req.url, true)
  console.log(pathname, '----', query)

  // 请求方式
  console.log(req.method)

  // 版本号
  // console.log(req.httpVersion)

  // 请求头
  // console.log(req.headers)

  // 请求体数据获取
  let arr = []
  req.on('data', (data) => {
    arr.push(data)
  })
  req.on('end', () => {
    console.log(Buffer.concat(arr).toString())
  })

})
server.listen(1234, () => {
  console.log('server is start......')
})

十一、设置http响应

response.js

const http = require('http')

const server = http.createServer((req, res) => {
  console.log('有请求进来了')

  // res
  // res.write('ok')
  // res.end()
  // res.end('test ok')
  res.statusCode = 302
  res.setHeader('Content-type', 'text/html;charset=utf-8')
  res.end('success')
})

server.listen(1234, () => {
  console.log('server is start.....')
})

十二、代理客户端

服务端-》服务端 是没有跨域的
client.js

const http = require('http')

let options = {
  host: 'localhost', 
  port: 1234, 
  path: '/',
  method: 'POST'
}

let server = http.createServer((request, response) => {
  let req = http.request(options, (res) => {
    let arr = []
    res.on('data', (data) => {
      arr.push(data)
    })
    res.on('end', () => {
      // console.log(Buffer.concat(arr).toString())
      let ret = Buffer.concat(arr).toString()
      response.setHeader('Content-type', 'text/html;charset=utf-8')
      response.end(ret)
    })
  })
  
  req.end('success')
})

server.listen(2345, () => {
  console.log('本地的服务端启动了')
})

server.js

const http = require('http')

const server = http.createServer((req, res) => {
  // console.log('请求进来了')
  let arr = []
  req.on('data', (data) => {
    arr.push(data)
  })
  req.on('end', () => {
    console.log(Buffer.concat(arr).toString())
    res.end('111111')
  })
})
server.listen(1234, () => {
  console.log('外部服务端启动了')
})

十三、代理客户端解决跨域

解决方案:因为服务端访问服务端是不需要跨域的,所以在本地搭建一个服务
nodejs 高级编程-通信,网络,智能路由器,node.js
server.js

const http = require('http')

const server = http.createServer((req, res) => {
  // console.log('请求进来了')
  let arr = []
  req.on('data', (data) => {
    arr.push(data)
  })
  req.on('end', () => {
    console.log(Buffer.concat(arr).toString())
    res.end('111111')
  })
})
server.listen(1234, () => {
  console.log('外部服务端启动了')
})

agent-client.js

const http = require('http')

let options = {
  host: 'localhost', 
  port: 1234, 
  path: '/',
  method: 'POST'
}

let server = http.createServer((request, response) => {
  let req = http.request(options, (res) => {
    let arr = []
    res.on('data', (data) => {
      arr.push(data)
    })
    res.on('end', () => {
      // console.log(Buffer.concat(arr).toString())
      let ret = Buffer.concat(arr).toString()
      response.setHeader('Content-type', 'text/html;charset=utf-8')
      response.end(ret)
    })
  })
  
  req.end('拉勾教育')
})

server.listen(2345, () => {
  console.log('本地的服务端启动了')
})

十四、http静态服务

server.js

const mime = require(‘mime’)获取文件类型

const http = require('http')
const url = require('url')
const path = require('path')
const fs = require('fs')
const mime = require('mime')

const server = http.createServer((req, res) => {
  // console.log('请求进来了')
  // 1 路径处理
  let {pathname, query} = url.parse(req.url)
  pathname = decodeURIComponent(pathname)
  let absPath = path.join(__dirname, pathname)
  // console.log(absPath)
  // 2 目标资源状态处理
  fs.stat(absPath, (err, statObj) => {
    if(err) {
      res.statusCode = 404
      res.end('Not Found')
      return
    }
    if (statObj.isFile()) {
      // 此时说明路径对应的目标是一个文件,可以直接读取然后回写
      fs.readFile(absPath, (err, data) => {
        res.setHeader('Content-type', mime.getType(absPath) + ';charset=utf-8')
        res.end(data)
      })
    } else {
      fs.readFile(path.join(absPath, 'index.html'), (err, data) => {
        res.setHeader('Content-type', mime.getType(absPath) + ';charset=utf-8')
        res.end(data)
      })
    }
  })
})
server.listen(1234, () => {
  console.log('server is start.....')
})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <h2>测试内容1111</h2>
</body>
</html>

nodejs 高级编程-通信,网络,智能路由器,node.js

十五、开发命令行工具- 命令行配置

利用一些 node 内置的核心模块,配合着一些第三方工具包,实现自己的命令行工具,使可以调用相应的命令,在指定的目录下来启动一个 web 服务,接着就可以使用浏览器来访问当前目录下的所有静态资源。

这里参照一个已经存在的 server 工具的使用。

创建结构:
nodejs 高级编程-通信,网络,智能路由器,node.js

为了便于看语法,www 先加上.js

再运行 npm init -y 生成 package.json 文件,修改 bin 里边的指令路径为 bin/www.js

nodejs 高级编程-通信,网络,智能路由器,node.js
在 www.js 里写上说明行的东西 #! /usr/bin/env node
再随便输出个东西:console.log(‘执行了’)

然后再将这个包link到全局,npm link 即可

直接运行 lgserve

nodejs 高级编程-通信,网络,智能路由器,node.js

OK, 全局的命令 lgserve 就生成了
利用第三方工具包: npm install commander,注意:这里当前是
"commander": "^6.0.0" 版本
nodejs 高级编程-通信,网络,智能路由器,node.js

#! /usr/bin/env node

const {program} = require('commander');
// program.option('-p --port', 'set server port')
// 配置信息
let options = {
    '-p --port <dir>': {
        'description': 'init server port',
        'example': 'myloserver -p 3306',
    },
    '-d --directory <dir>': {
        'description': 'init server directory',
        'example': 'myloserver -d c:',
    },
}

function formatConfig(configs, callback){
    Object.entries(configs).forEach(([key, val])=>{
        callback(key, val)
    })
}

formatConfig(options, (cmd, val)=>{
    program.option(cmd, val.description)
})

program.parse(process.argv)

nodejs 高级编程-通信,网络,智能路由器,node.js
添加上示例和修改当前 Usage name:

program.on('--help', ()=>{
    console.log('examples: ');
    formatConfig(options, (cmd, val)=>{
        console.log(val.example)
    })
})

program.name('mylgserver')

nodejs 高级编程-通信,网络,智能路由器,node.js

添加上版本号:注意,版本号在 package.json 里边

const version = require('../package.json').version;
program.version(version)

nodejs 高级编程-通信,网络,智能路由器,node.js
nodejs 高级编程-通信,网络,智能路由器,node.js

nodejs 高级编程-通信,网络,智能路由器,node.js

let cmdConfig = program.parse(process.argv)
console.log(cmdConfig);

nodejs 高级编程-通信,网络,智能路由器,node.js
执行:lgserve -p 1234 -d d:
nodejs 高级编程-通信,网络,智能路由器,node.js

#! /usr/bin/env node

const {program} = require('commander')

// console.log('执行了')
// program.option('-p --port', 'set server port')

// 配置信息
let options = {
  '-p --port <dir>': {
    'description': 'init server port',
    'example': 'lgserve -p 3306'
  },
  '-d --directory <dir>': {
    'description': 'init server directory',
    'example': 'lgserve -d c:'
  }
}

function formatConfig (configs, cb) {
  Object.entries(configs).forEach(([key, val]) => {
    cb(key, val)
  })
}

formatConfig(options, (cmd, val) => {
  program.option(cmd, val.description)
})

program.on('--help', () => {
  console.log('Examples: ')
  formatConfig(options, (cmd, val) => {
    console.log(val.example)
  })
})

program.name('lgserve')
let version = require('../package.json').version
program.version(version)

let cmdConfig = program.parse(process.argv)
// console.log(cmdConfig)

let Server = require('../main.js')
new Server(cmdConfig).start()

nodejs 高级编程-通信,网络,智能路由器,node.js

十六、开发命令行工具- 启动web服务

这里的主要逻辑都放在 main.js 里在www.js 里直接引入就行,也可以直接放在 www.js 里,比较臃肿就不便于维护了

const Server = require('../main.js');
new Server(cmdConfig).start()

nodejs 高级编程-通信,网络,智能路由器,node.js

// main.js
const http = require('http');
class Server{
    constructor(config){
        this.config = config
    }
    start(){
        console.log('服务端已经运行了');
    }
}

module.exports = Server

nodejs 高级编程-通信,网络,智能路由器,node.js

const http = require('http');

function mergeConfig(config){
    return {
        port: 1234,
        directory: process.cwd(),
        ...config
    }
}

class Server{
    constructor(config){
        this.config = mergeConfig(config)
        console.log(this.config);
    }
    start(){
        console.log('服务端已经运行了');
    }
}

module.exports = Server

nodejs 高级编程-通信,网络,智能路由器,node.js
加上参数:lgserve -p 3307 -d c:
nodejs 高级编程-通信,网络,智能路由器,node.js
启动一个服务:

start(){
    let server = http.createServer(this.serveHandle.bind(this))
    server.listen(this.config.port, ()=>{
        console.log('服务端已经启动了......')
    })
}
serveHandle(req, res){
    console.log('有请求进来了');
}

nodejs 高级编程-通信,网络,智能路由器,node.js
nodejs 高级编程-通信,网络,智能路由器,node.js

十七、开发命令行工具- 处理文件资源

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs').promises;
const { createReadStream } = require('fs');
const mime = require('mime');

function mergeConfig(config) {
    return {
        port: 1234,
        directory: process.cwd(),
        ...config
    }
}

class Server {
    constructor(config) {
        this.config = mergeConfig(config)
    }
    start() {
        let server = http.createServer(this.serveHandle.bind(this))
        server.listen(this.config.port, () => {
            console.log('服务端已经启动了......')
        })
    }
    async serveHandle(req, res) {
        let { pathname, query } = url.parse(req.url)
        pathname = decodeURIComponent(pathname)
        let absPath = path.join(this.config.directory, pathname)
        console.log(absPath);
        try {
            let statObj = await fs.stat(absPath)
            if (statObj.isFile()) { // 是个文件
                this.fileHandle(req, res, absPath)
            } else { // 是个文件夹
                this.fileHandle(req, res, absPath + '/www.js')
            }
        } catch (error) {
            this.errorHandle(req, res, error)
        }

    }
    fileHandle(req, res, absPath) {
        res.statusCode = 200
        res.setHeader('Content-Type', mime.getType(absPath) + '; charset=utf-8')
        createReadStream(absPath).pipe(res)
    }
    errorHandle(req, res, error) {
        // console.log(error);
        res.statusCode = 404
        res.setHeader('Content-Type', 'text/html; charset=utf-8')
        res.end('Not Found')
    }
}

module.exports = Server

nodejs 高级编程-通信,网络,智能路由器,node.js

十八、开发命令行工具- 处理目录资源

已经存在的 serve 工具的操作是如果我们访问的是一个目录,它就会把它下边的所有资源名称展示出来,放在浏览器所对应的界面当中进行显示,这里也这样操作。

# 使用了 ejs 模板引擎
npm install ejs

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs').promises;
const { createReadStream } = require('fs');
const mime = require('mime');
const ejs = require('ejs');
const { promisify } = require('util')

function mergeConfig(config) {
    return {
        port: 1234,
        directory: process.cwd(),
        ...config
    }
}

class Server {
    constructor(config) {
        this.config = mergeConfig(config)
    }
    start() {
        let server = http.createServer(this.serveHandle.bind(this))
        server.listen(this.config.port, () => {
            console.log('服务端已经启动了......')
        })
    }
    async serveHandle(req, res) {
        console.log('请求进来了')
        console.log(req.url)
        let { pathname, query } = url.parse(req.url)
        pathname = decodeURIComponent(pathname)
        let absPath = path.join(this.config.directory, pathname)
        console.log(absPath);
        try {
            let statObj = await fs.stat(absPath)
            if (statObj.isFile()) { // 是个文件
                this.fileHandle(req, res, absPath)
            } else { // 是个文件夹
                let dirs = await fs.readdir(absPath)
                console.log(dirs);
                // promisify
                let renderFile = promisify(ejs.renderFile)
                let ret = await renderFile(path.resolve(__dirname, 'template.html'), {arr: dirs})
                res.end(ret)
            }
        } catch (error) {
            this.errorHandle(req, res, error)
        }

    }
    fileHandle(req, res, absPath) {
        res.statusCode = 200
        res.setHeader('Content-Type', mime.getType(absPath) + '; charset=utf-8')
        createReadStream(absPath).pipe(res)
    }
    errorHandle(req, res, error) {
        // console.log(error);
        res.statusCode = 404
        res.setHeader('Content-Type', 'text/html; charset=utf-8')
        res.end('Not Found')
    }
}

module.exports = Server

<!-- template.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul>
        <% for(let i=0; i< arr.length; i++) { %>
            <!-- <li><%=arr[i]%></li> -->
            <li><a href="#"><%=arr[i]%></a></li>
        <% } %>
    </ul>
</body>
</html>

nodejs 高级编程-通信,网络,智能路由器,node.js

十九、开发命令行工具- 模版数据渲染

main.js

const http = require('http')
const url = require('url')
const path = require('path')
const fs = require('fs').promises
const {createReadStream} = require('fs')
const mime = require('mime')
const ejs = require('ejs')
const {promisify} = require('util')

function mergeConfig (config) {
  return{
    port: 1234, 
    directory: process.cwd(),
    ...config
  }
}

class Server{
  constructor(config) {
    this.config = mergeConfig(config)
    // console.log(this.config)
  }
  start() {
    let server = http.createServer(this.serveHandle.bind(this))
    server.listen(this.config.port, () => {
      console.log('服务端已经启动了.......')
    })
  }
  async serveHandle(req, res) {
    let {pathname} = url.parse(req.url)
    pathname = decodeURIComponent(pathname)
    let abspath = path.join(this.config.directory, pathname)
    // console.log(abspath)
    try {
      let statObj = await fs.stat(abspath)
      if (statObj.isFile()) {
        this.fileHandle(req, res, abspath)
      } else {
        let dirs = await fs.readdir(abspath)
        dirs = dirs.map((item) => {
          return{
            path: path.join(pathname, item),
            dirs: item
          }
        })
        // console.log(dirs)
        let renderFile = promisify(ejs.renderFile)

        let parentpath = path.dirname(pathname)

        let ret = await renderFile(path.resolve(__dirname, 'template.html'), {
          arr: dirs,
          parent: pathname == '/' ? false : true,
          parentpath: parentpath,
          title: path.basename(abspath)
        })
        res.end(ret)
      }
    } catch (err) {
      this.errorHandle(req, res, err)
    }
  }
  errorHandle(req, res, err) {
    console.log(err)
    res.statusCode = 404
    res.setHeader('Content-type', 'text/html;charset=utf-8')
    res.end('Not Found')
  }
  fileHandle(req, res, abspath) {
    res.statusCode = 200
    res.setHeader('Content-type', mime.getType(abspath) + ';charset=utf-8')
    createReadStream(abspath).pipe(res)
  }
}

module.exports = Server

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    *{
      list-style: none;
    }
  </style>
</head>
<body>
  <h3>IndexOf <%=title%></h3>
  <ul>
    <%if(parent) {%>
      <li><a href="<%=parentpath%>">上一层</a></li>
    <%}%>
    
    <%for(let i = 0; i < arr.length; i++) {%>
      <li><a href="<%=arr[i].path%>"><%=arr[i].dirs%></a></li>
    <%}%>
  </ul>
</body>
</html>

nodejs 高级编程-通信,网络,智能路由器,node.js文章来源地址https://www.toymoban.com/news/detail-563959.html

到了这里,关于nodejs 高级编程-通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 小米路由器华为路由器 怎么才能选择一款合适的智能路由器?

    近两年,具有智能概念的路由器风生水起,从互联网巨头到初创公司均涉足到智能路由器的研发。什么样的路由器才算是智能路由?度娘到的资料有些杂乱,但基本的共同点是只要路由器能够支持安装插件扩展路由功能、提供移动设备端App进行管理的路由器均可称为智能路由

    2024年02月08日
    浏览(55)
  • 什么是智能路由器?相比普通路由器有哪些优势

    继智能手机、智能电视火爆之后,如今智能汽车、智能路由器又成为科技界关注的宠儿,如今华为、小米、极路由器、百度、360等业界巨头均纷纷推出了智能路由器。那么什么是智能路由器,其和普通路由器有哪些区别,其作用又是什么呢?这是近段时间不少朋友所思考的一

    2024年02月06日
    浏览(62)
  • 智能路由器和普通路由器之间的区别有哪些

    路由器相信大家都不会陌生,但最近智能路由器逐渐火爆起来,很多科技巨头均纷纷推出智能路由器,像小米路由器、极路由、华为智能路由器等等。那么如今越发火爆的智能路由器和普通路由器又有什么区别?以下小编与大家一起来探讨一番。 智能路由器和普通路由器有什

    2024年02月06日
    浏览(47)
  • 新一代智能无线路由器小米路由器怎么设置

    小米路由器是一款采用Boardcom双核1GHz处理器、256MB DDR3内存。支持802.11ac无线协议标准,可提供2.4GHz+5GHz双频频段,前者的最高传输速率为300Mbps+866Mbps。并且还内置1TB硬盘,是一款顶级发烧新一代智能无线路由器,其支持在电脑和手机中进行路由器设置,废话不多说。下面我们

    2024年02月07日
    浏览(54)
  • 工业5G路由器;小体积 千兆高速通信组网

    计讯物联工业路由器TR232,5G高速网络,超低时延、高可靠性,小体积、易安装、强兼容,串口/网口多设备接入联网,为用户提供高速稳定的数据传输通道 。 小体积5G工业路由器TR323,外形104 78 24mm,体积轻巧,导轨式便捷安装。 全面支持运营商高速5G网络,支持SA/NSA组网,全

    2024年02月05日
    浏览(61)
  • 迅雷智能路由器怎么赚钱 迅雷路由器赚钱原理知识介绍

    迅雷路由号称“全球第一台会赚钱的路由器”,原因就是其内部集成了一款名为“迅雷水晶”的功能,开启该功能,即可有效利用家庭闲置带宽,进行水晶挖矿,并获得现金收益。那么迅雷路由器怎么赚钱?其赚钱原理又是什么呢?下面yii666小编来为大家介绍下。 迅雷水晶工

    2024年02月06日
    浏览(50)
  • 魅族路由器价格是多少?魅族智能路由器售价介绍

    相信还有很多朋友对于魅族智能路由器的价格还不太清楚,下文小编就为大家带来有关魅族智能路由器售价方面的消息,感兴趣的朋友可以一起看看 消息称,魅族将在本月28日举行发布会,而且是四剑齐发。从下面四张宣传图上的“活、智、巧、支”四个来看,除了之

    2024年02月07日
    浏览(41)
  • 联想路由器怎么样?双频AC智能路由器联想云路由开箱图赏

    前不久小米推出了一款129元的小米路由器mini,号称最便宜的双频AC智能路由器。其实联想也正推出了一款与小米路由器mini相似的产品,只是相对低调,目前联想云路由器也已经低调开启公测,其配置与小米路由器mini相当,不过售价目前还未知。废话不多说,以下笔者为大家

    2024年02月07日
    浏览(52)
  • 斐讯无线路由器怎么设置?斐讯K1智能路由器安装教程

    大家都知道,新款斐讯无线路由器设置步骤相比老式本本更为简洁,设置方法与智能路由器类似。今天yii666小编为大家附上斐讯K1智能路由器设置教程,感兴趣的朋友不要错过了。 斐讯无线路由器怎么安装设置 斐讯K1智能路由器设置教程 一、斐讯路由器安装 在路由器设置之

    2024年02月05日
    浏览(59)
  • 智能路由器与普通路由器有哪些区别?最大的不同是什么

    1、智能路由器设置更方便 普通路由器设置往往较为复杂,初次安装设置需要借助电脑,然后登录路由器管理界面,将上网账号等信息填写进去,然后完成设置。 而智能路由器实用更为简单,不仅可以通过电脑完成初次配置,还可以通过智能手机、平板电脑等设备完成设置,

    2024年02月06日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包