Node之net模块

Node之net模块

net 模块是建立在 tcp/ip 协议上的。同时还可以进行进程间的通信 ipc 。我们之前的 http 请求是一次请求一次响应。普通模式是三次握手之后进行一次请求和响应然后第四次挥手。长连接模式就是在握手和挥手之间不进行中断,直到客户端或者服务器有一方提出中断,使用 keep-alive连接方式。

而 tcp/ip 可以在握手和挥手之间传递任意数据,不受限制,不需要消息头,消息体。握手和挥手也是 tcp/ip 上的内容,它们在操作系统上被执行。我们只能在浏览器上看到请求和响应。

js 复制代码
const net = require('net')
const socket = net.createConnection({
    host: 'duyi.ke.qq.com',
    port: 80
}, () => {
    console.log('连接成功')
})
socket.on('data', chunk => {
    console.log(chunk.toString('utf-8'))
})
socket.write(`GET / HTTP/1.1
Host: duyi.ke.qq.com
Connection: keep-alive

`)

可以通过 net.createConnection 的方式创建一个客户端。会返回一个双工流 socket 。它是一个特殊的文件,与网卡相关联,可以随时写入读取。在进行读取前必须先写入数据。里面可以传入两个参数,第一个参数是配置对象,第二个参数是监听函数,它可以在完成连接之后调用。

这是因为 http 协议有固定的模式和格式。必须先进行请求然后才能拿到响应结果。请求的格式包括请求行,请求头,请求体。请求行一个换行到请求头,然后两个换行到请求体,请求体可以没有,但必须进行两次换行。

js 复制代码
const net = require('net')
const socket = net.createConnection({
    host: 'duyi.ke.qq.com',
    port: 80
}, () => {
    console.log('连接成功')
})
function parseResponse(response) {
    const index = response.indexOf('\r\n\r\n');
    const head = response.substring(0, index);
    const body = response.substring(index + 2);
    const headParts = head.split('\r\n');
    const headerArray = headParts.slice(1).map(str => {
        return str.split(':').map(s => s.trim())
    })
    const header = headerArray.reduce((a, b) => {
        a[b[0]] = b[1];
        return a;
    }, {})
    return {
        header,
        body: body.trimStart()
    }
}
function isOver() {
    const contentLength = receive.header['Content-Length'];
    const curReceivedLength = Buffer.from(receive.body, 'utf-8').byteLength;
    console.log(contentLength, curReceivedLength);
    return curReceivedLength > contentLength;
 }
let receive = null;
socket.on('data', chunk => {
    const response = chunk.toString('utf-8')
    if (!receive) {
        //第一次接受数据
        receive = parseResponse(response)
        if (isOver()) {
            socket.end()
        }
        return;
    }
    receive.body += response;
    if (isOver()) {
        socket.end()
        return;
    }
    console.log('来自服务器的消息');
});
socket.write(`GET / HTTP/1.1
Host: duyi.ke.qq.com
Connection: keep-alive

 `);
socket.on('close', () => {
    console.log(receive.body)
    console.log('关闭了');
});

我们将 header 里面的东西提取出来,变成一个对象。并找到对象里的 Content-Length 然后看是否当前的字符长度达到了要求的长度。如果第一次已经达到,就直接结束,如果没有达到,就在 body 里不断加入拿到的响应结果加进去,直到达到要求的字符长度。并在最后结束的时候将 body 输出。

js 复制代码
const fs = require('fs');
const path = require('path');
const server = net.createServer();
server.listen(8000);
server.on('listening', () => {
    console.log("server listen 8000")
})
server.on("connection", (socket) => {
    console.log("有新的连接");
    socket.on("data", async chunk => {
        const filename=path.resolve(__dirname, "./myfiles/avatar.jpeg");
        const bodyBuffer = await fs.promises.readFile(filename);
        const headBuffer = Buffer.from(`HTTP/1.1 200 OK
Content-Type: image/jpeg

`,
          "utf-8"
        );
        const result = Buffer.concat([headBuffer, bodyBuffer]);
        socket.write(result);
        socket.end();
    });
});
server.on("close", () => {
    console.log("server close")
});

创建一个服务器,可以传入一个监听函数,表示服务器是否创建。服务器需要监听一个端口,并且在监听之后可以通过 listening 事件得知。

当与客户端成功连接之后,会创建一个 socket ,即使是同一个客户端断开之后,也会重新创建一个 socket ,socket 在一次连接过后或者长时间断开之后销毁。使用 connection 可以监听连接。

可以读取客户端传来的 socket ,然后再写入 socket 作为响应结果。

在连接结束之后,关闭服务器。

相关推荐
Jonathan Star1 小时前
沉浸式雨天海岸:用A-Frame打造WebXR互动场景
前端·javascript
工业甲酰苯胺2 小时前
实现 json path 来评估函数式解析器的损耗
java·前端·json
老前端的功夫2 小时前
Web应用的永生之术:PWA落地与实践深度指南
java·开发语言·前端·javascript·css·node.js
LilySesy2 小时前
ABAP+WHERE字段长度不一致报错解决
java·前端·javascript·bug·sap·abap·alv
Wang's Blog3 小时前
前端FAQ: Vue 3 与 Vue 2 相⽐有哪些重要的改进?
前端·javascript·vue.js
再希3 小时前
React+Tailwind CSS+Shadcn UI
前端·react.js·ui
用户47949283569154 小时前
JavaScript 的 NaN !== NaN 之谜:从 CPU 指令到 IEEE 754 标准的完整解密
前端·javascript
群联云防护小杜4 小时前
国产化环境下 Web 应用如何满足等保 2.0?从 Nginx 配置到 AI 防护实战
运维·前端·nginx
醉方休4 小时前
Web3.js 全面解析
前端·javascript·electron
前端开发爱好者5 小时前
前端新玩具:Vike 发布!
前端·javascript