回顾 http 请求

  1. 普通模式

  2. 长连接模式

net 模块能干什么

  1. net 是一个通信模块

  2. 利用它,可以实现 进程间的通信 IPC网络通信 TCP/IP

通信事件和方法

API 描述
listening 事件 开始监听端口后触发的事件
connection 事件 新的连接建立时触发,服务端会返回一个 socket 双工流对象
close 事件 当连接关闭时触发,如果当前还有连接存在,直到所有连接都结束之后才会触发这个事件
error 事件 当错误出现的时候触发
data 事件 从可读流中消费数据的操作
end 事件 当数据被消费完成之后,可读流关闭之前触发,一般用于服务端
write 方法 用于写入数据,在 socket 上发送数据
end 方法 结束写入,有数据传人则代表最后一次写入

创建客户端

const net = require("net");

// 由于访问的服务端协议是 http,数据传输的格式必须满足 http 协议规范
// 如果访问的服务端是 tcp/ip,则数据格式没有限制,http 是基于 tcp/ip 
const socket = net.createConnection(
  { host: "duyi.ke.qq.com", port: 80 },
  () => console.log("连接成功")
);

/**
 * 提炼出响应字符串的消息头和消息体
 * @param {*} response
 */
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() };
}

var receive = null;
function isOver() {
  // 需要接收的消息体的总字节数
  const contentLength = +receive.header["Content-Length"];
  const curReceivedLength = Buffer.from(receive.body, "utf-8").byteLength;
  console.log(contentLength, curReceivedLength);
  return curReceivedLength > contentLength;
}

socket.on("data", chunk => {
  const response = chunk.toString("utf-8");
  if (!receive) {
    receive = parseResponse(response); // 只解析第一次,解析请求头

    if (isOver()) {
      socket.end();
      return;
    }
  }else{
    receive.body += response;

    if (isOver()) {
      socket.end();
      return;
    }
  }
});


/**
 * 请求行
 * GET / HTTP/1.1
 * 
 * 请求头
 * Host: duyi.ke.qq.com 
 * Connection: keep-alive
 * 
 * 请求体: 请求行后跟着两个换行符,之后的内容是请求体
 */
socket.write(`GET / HTTP/1.1
Host: duyi.ke.qq.com
Connection: keep-alive

`);

socket.on("close", () => {
  console.log(receive.body);
  console.log("结束了!");
});

创建服务端

const net = require("net");
const fs = require("fs");
const path = require("path");

const server = net.createServer();
server.listen(9527); // 服务器监听 9527 端口,浏览器访问 localhost:9527

// 开始监听端口后触发的事件
server.on("listening", () => {
  console.log("server listen 9527");
});

server.on("connection", socket => {
  // 每次连接都会返回一个 socket 对象
  console.log("有客户端连接到服务器");

  socket.on("data", async chunk => {
    const filename = path.resolve(__dirname, "./hsq.jpg");
    const bodyBuffer = await fs.promises.readFile(filename);

    // http 协议规范
    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();
  });

  socket.on("end", () => {
    console.log("连接关闭了");
  });
});
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 回顾 http 请求
  2. 2. net 模块能干什么
  3. 3. 通信事件和方法
  4. 4. 创建客户端
  5. 5. 创建服务端