nodejs 高级编程-通信

news2024/11/15 4:47:52

一、通信基本原理

通信必要条件

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

在这里插入图片描述

二、网络通讯方式

常见的通讯方式

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

如何建立多台主机互连?

在这里插入图片描述
如何定位局域网中的其他主机?

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

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

明确目标主机IP地址
在这里插入图片描述

三、网络层次模型

七层模型

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

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

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

TCP协议

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

在这里插入图片描述
常见控制字段

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

三次握手
在这里插入图片描述
看着4次握手,但是中间两次是同时进行的,进行合并,这样最终就有了3次握手

在这里插入图片描述

四次挥手
在这里插入图片描述
TCP协议

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

五、通讯过程-net模块

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
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拥塞机制决定发送机制

在这里插入图片描述
可以看到数据粘在了一起

解决方式:可以加延迟

在这里插入图片描述

七、封包拆包实现

在这里插入图片描述

在这里插入图片描述
数据传输过程

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

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('外部服务端启动了')
})

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

解决方案:因为服务端访问服务端是不需要跨域的,所以在本地搭建一个服务
在这里插入图片描述
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>

在这里插入图片描述

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

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

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

创建结构:
在这里插入图片描述

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

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

在这里插入图片描述
在 www.js 里写上说明行的东西 #! /usr/bin/env node
再随便输出个东西:console.log(‘执行了’)

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

直接运行 lgserve

在这里插入图片描述

OK, 全局的命令 lgserve 就生成了
利用第三方工具包: npm install commander,注意:这里当前是
"commander": "^6.0.0" 版本
在这里插入图片描述

#! /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)

在这里插入图片描述
添加上示例和修改当前 Usage name:

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

program.name('mylgserver')

在这里插入图片描述

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

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

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述
执行:lgserve -p 1234 -d d:
在这里插入图片描述

#! /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()

在这里插入图片描述

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

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

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

在这里插入图片描述

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

module.exports = Server

在这里插入图片描述

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

在这里插入图片描述
加上参数:lgserve -p 3307 -d c:
在这里插入图片描述
启动一个服务:

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

在这里插入图片描述
在这里插入图片描述

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

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

在这里插入图片描述

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

已经存在的 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>

在这里插入图片描述

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

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>

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/738854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hcip笔记---ospf的LSA限制和不规则区域

有关ACL&#xff1a;例如&#xff1a;1.1.1.0 0.0.0.255这个网段以及后面跟随的通配符&#xff0c;通配符和反掩码长得很像&#xff0c;同时都是用0标识不可变&#xff0c;1标识可变&#xff0c;但反掩码里的1和0必须连续出现&#xff0c;而通配符则不需要遵循这个规则&#xf…

深入思考Sui的独特性如何构建出跨时代的产品

近日&#xff0c;我们与Mysten Labs产品总监Janet Wu面对面探讨了Web3的产品开发过程&#xff0c;了解了她对Sui上最激动人心的产品用例的看法&#xff0c;以及她对该行业未来的展望。 您能简单介绍一下在Mysten Labs担任产品总监意味着什么吗&#xff1f; 对我而言&#xff…

0基础学习VR全景平台篇 第59篇:专业版功能-跨账号复制

功能位置示意 一、本功能将用在哪里&#xff1f; 跨账号复制&#xff0c;是指将本账号中已发布的VR漫游作品一键复制给其他账号使用。 复制成功后&#xff0c;其他账号中也会生成同样的作品以及获得相关的全景、音频、图片、视频等素材。 并且原作品和复制品可以独立编辑&am…

K8s为什么需要calico? calico 原理深入理解.

文章目录 为什么需要calico&#xff1f;-网络插件”千千万”&#xff0c;为何k8s要用calicocalico的架构calico Pod 跨node通信tunl0 的作用&#xff1f;为什么所有pod的默认网关都是169.254.1.1 &#xff1f;什么是ARP 代理&#xff1f;jksj BGP模式的calico工作原理calico BG…

vue3 报错解决:找不到模块‘xxx.vue’或其相应的类型声明。(Vue 3 can not find module)

src下面建立一个xx.d.ts的文件 declare module *.vue {import { ComponentOptions } from vueconst componentOptions: ComponentOptionsexport default componentOptions }

使用3DEXPERIENCE平台有效管理设计变更,随时处理问题

临时处理设计变更&#xff0c;电脑却不在身边怎么办?借助3DEXPERIENCE平台&#xff0c;我们可以轻松的用手机打开模型&#xff0c;还能够随时随地查看其他人的工作进展并进行审批。 在工作过程中&#xff0c;工程师小A发现&#xff0c;装配体的零件强度有点弱&#xff0c;小A…

HTML 第二部分 (前端学习)

由于&#xff0c;HTML的部分实在是太多了&#xff0c;第一部分&#xff0c;还没学一半&#xff0c;就已经抄了1w字。而且可能&#xff0c;真正用上的也比较少&#xff0c;更何况&#xff0c;一直坚持&#xff0c;一个不落的学下去&#xff0c;也存在一点注意力分散的困难&#…

ATM自助取款系统(Java)

文章目录 完整程序1. 课程设计目的2. 课程设计任务与要求3. 课程设计说明书3.1 需求分析3.1.1 功能分析3.1.2 性能要求分析 3.2 概要设计3.2.1 功能模块图&#xff0c;如图1。 3.3 详细设计3.3.1 实体类的设计3.3.2 实现数据库处理 3.4 主要程序功能流程图 4. 课程设计成果4.1 …

Linux——进程信号的发送

目录 一.信号发送的概念 首先来讲几个发送术语&#xff1a; 它有三种情况&#xff1a; 注意&#xff1a; 二.信号在内核中的表示示意图 三.信号捕捉 所以总结一下&#xff1a; 此时&#xff0c;会出现这样一个疑问&#xff1a;操作系统是如何得知现在被执行的进程是用户态…

DuDuTalk:4G录音工牌如何帮企业实现,线下服务的远程实时监督?

数字化时代&#xff0c;企业越来越重视客户体验。而线下服务是企业的员工跟客户直接互动最重要的环节&#xff0c;这直接关乎到客户对品牌、产品、服务的最直观评价和反馈&#xff0c;最终影响客户的购买和成交。 但企业的线下服务场景往往又是企业数字化最薄弱的一环&#xf…

Qt,day4

闹钟 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);this->setWindowTitle("闹钟");this->setWindowIcon(QIcon("D:\\HQYJRJ\\QT\\day1\\…

【Python爬虫开发基础⑫】requests库概述(文件上传、cookies处理、状态码处理、异常处理等)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;python网络爬虫从基础到实战 欢迎订阅&#xff01;后面的内容会越来越有意思~ &#x1f4a1;往期推荐&#xff1a; ⭐️前面比较重要的基础内容&#xff1a; 【Python爬…

数据平台之数仓模型设计

文章目录 前言一、维度建模基本概念1.1 事实表1.2 维度表 二、维度建模三种模式2.1 星型模型2.2 雪花模式2.3 星座模式 三、ChatGPT代替Sql Boy3.1 简单案例3.2 复杂案例 四、总结 前言 看到几篇不错的文章&#xff0c;自己总结合并了分享给小伙伴 金博尔和恩门共同开创的数仓…

vue项目 设置启动时自动运行到电脑默认浏览器中

相信大家很多参与企业开发会发现 别人搭建的vue项目都会自动启动在电脑的默认浏览器上 这个其实React项目自己就会有 但是 vue项目我们需要自己设置一下 在根目录的 vue.config.js 将devServer下 设置 open: true 参考代码如下 module.exports {devServer: {open: true} }这样…

机器学习30:《推荐系统-III》使用 TensorFlow 构建电影推荐系统

本文将介绍基于 MovieLens 数据集创建一个电影推荐系统的方法。具体而言&#xff0c;包括探索电影数据&#xff0c;训练矩阵分解模型&#xff0c;检查嵌入&#xff0c;矩阵分解中的正则化&#xff0c;Softmax 模型训练等内容。 目录 1.准备工作 1.1 导入依赖模块 1.2 加载数…

LeetCode 1107.每日新用户统计

数据准备 Create table If Not Exists Traffic (user_id int, activity ENUM(login, logout, jobs, groups, homepage), activity_date date); Truncate table Traffic; insert into Traffic (user_id, activity, activity_date) values (1, login, 2019-05-01); insert into …

Charles抓包map local后出现“failed: unacceptable content-type: text/plain“

Charles 抓包map local 修改 映射到本地数据 出现如下报错 返回ErrorUrlhttps://xxxx 返回ErrorError Domaincom.alamofire.error.serialization.response Code-1016 "Request failed: unacceptable content-type: text/plain" UserInfo{NSLocalizedDescriptionRequ…

邮票面值-2022年全国青少年信息素养大赛Python国赛第5题

[导读]&#xff1a;超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲&#xff0c;这是超平老师解读Python编程挑战赛真题系列的第7讲。 全国青少年信息素养大赛&#xff08;原全国青少年电子信息智能创新大赛&#xff09;是“世界机器人大会青少年机器人设计…

适配理想全系车型,OPPO首创手表无感蓝牙车钥匙系统

OPPO 宣布与理想汽车深度合作&#xff0c;首家推出系统级手表无感蓝牙车钥匙功能&#xff0c;适配理想全系列车型。此功能早已适配 OPPO 手机。仅支持 OPPO Watch 2、OPPO Watch 3 和 OPPO Watch SE 系列&#xff0c;可独立使用&#xff0c;无需手机即可控制车辆。 OPPO首发数字…

Python:创建一个满足高斯分布的立方体

算法说明&#xff1a; &#xff08;1&#xff09;首先定义一个中心点坐标 center&#xff0c;标准差 sigma 和峰值 amplitude。 &#xff08;2&#xff09;然后通过计算每个点到中心点的欧氏距离&#xff0c;并将欧氏距离应用于高斯分布的公式 amplitude * exp(-distances**2 /…