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 作为响应结果。

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

相关推荐
李逍16 小时前
pragmatic-drag-and-drop 拖拽神器上手
前端·javascript
阿笑带你学前端16 小时前
当手机遇上电视:Flutter实现局域网遥控输入的奇妙之旅
前端·flutter
张可16 小时前
Kotlin 函数式编程思想
android·前端·kotlin
A了LONE16 小时前
uniapp的上拉加载H5和小程序
前端·javascript·vue.js
光年像素16 小时前
前端开发的“三剑客”—— HTML、CSS、JavaScript
javascript·css·html5
早起的年轻人16 小时前
Flutter 3.35.2 以上版本中 数字转字符串的方法指南
前端·flutter
前端小巷子16 小时前
Vue 路由传参的四种方式
前端·vue.js·面试
CodeSheep16 小时前
宇树科技 IPO 时间,定了!
前端·后端·程序员
Mo_jon16 小时前
CSS 瀑布流图片简易实现
前端·css·css3