网络分层

了解计算机网络的同学都知道 OSI 七层网络模型TCP/IP 模型。OSI 七层模型是理论上的网络通信模型,而 TCP/IP 是现实中的网络通信概念模型。它们之间的对比关系参考下图。

本文主旨不在于解释网络通信模型,因此此处略去各层的介绍,只关注应用层与传输层,即 TCP/IP 模型中的应用层和传输层。

我们知道 HTTP 协议工作在应用层,属于应用层协议,TCP/IP 协议工作在传输层,属于传输层协议。在实际的网络通信中,一端的数据以报文的形式,从上到下经过层层封装发送给另一端,而接收数据的一端则从下到上层层解析数据报文,最后将数据传递给应用层。

从编程的角度来看,上面的数据报文的传输是如何实现的呢?或者说,应用层是如何与传输层通信的呢?这就需要说到 socket 了。

socket

所谓 socket,也就是俗称的套接字,是计算机网络中可以发送和接收数据的一个端点,包含源 IP 地址和目的 IP 地址以及源端口号和目的端口号。

其实,socket 类似于插排上的插孔,当插头插入插孔时,便可实现通电。对于 socket 来说,当连接建立之后,相当于一条通信线路连接了通信双方的 socket,通信双方就可以通过 socket 进行通信了。

Node.js 中的 socket 被封装在了 net 模块和 dgram 模块中,分别对应与 TCP 协议UDP 协议。下面以 net 模块为例,说明 socket 的使用。

先看服务端代码:

'use strict';

const net = require('net');

const HOST = '127.0.0.1';
const PORT = 9999; net.createServer(function(socket) {
console.log(`接收到远端访问: ${socket.remoteAddress}:${socket.remotePort}`); // 接收客户端发送的数据
socket.on('data', function(data) {
console.log(`from client: ${data}`); // 将接收到的数据返回给客户端
socket.write(data);
}); // 为这个socketet实例添加一个"close"事件处理函数
socket.on('close', function(data) {
console.log(`来自 ${socket.remoteAddress}:${socket.remotePort} 的连接已经关闭。`);
});
}).listen(PORT, HOST); console.log('Server listening on ' + HOST +':'+ PORT);

在服务端,通过 net.createServer 添加对 connection 事件的监听,获取 socket 实例,并在 socket 实例上做数据收发操作。

以下是客户端代码:

'use strict';

const net = require('net');

const HOST = '127.0.0.1';
const PORT = 9999; let talk = 0; const client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log(`已经建立与 ${HOST}:${PORT} 的连接`);
// 建立连接后立即向服务器发送数据,服务器将收到这些数据
client.write('hello, I am client!');
}); // 为客户端添加“data”事件处理函数,接收服务端返回的数据
client.on('data', function(data) {
console.log(`from server: ${data}`);
talk++;
if (talk < 3) {
// 接受到数据后,再次发送数据给客户端
client.write(`talk: ${talk}`);
} else {
client.end();
}
}); // 为客户端添加“close”事件处理函数
client.on('close', function() {
console.log('连接已经关闭!');
});

客户端直接创建 socket 实例,收发数据。

分别执行服务端和客户端代码,分别获取命令行输出如下。

服务端每次会将接收到的客户端数据回发给客户端,客户端接收到三次数据后,主动关闭 socket 连接。

整个 net 模块,提供了两个类: net.Servernet.Socketnet.Socket 负责通信双方之间的通信,而 net.Server 负责建立本地服务器,提供了对本地服务器的管理,每接收到一个连接就会建立一个 socket 与对端实现通信。

http

http 协议前端同学应该都很熟悉。在 Node.js 中,http 协议由 http 模块(底层基于 net 模块)实现。

http 模块提供了如下几个类:

  • http.Agent
  • http.ClientRequest
  • http.Server
  • http.ServerResponse
  • http.IncomingMessage

我们通过一段代码,简述每个类的作用,以及内部实现原理。

先看服务端代码:

'use strict';

const http = require('http');

const server = http.createServer((req, res) => {
req.on('data', (data) => {
console.log(`接收到远端请求数据: ${data}`);
});
req.on('end', () => {
res.write('请求已收到');
res.statusCode = 200;
res.end();
});
}); server.listen(9999);
console.log('server listening on 9999');

服务端通过 http.createServer 创建服务器并监听 request 事件,在事件处理函数中获取 reqres做请求处理和响应。其中 req 就是 http.IncomingMessage,用于描述远端过来的请求,而res 就是 http.ServerResponse,用于描述服务端做出的响应。

在上面的代码中,我们通过 req 监听 data 事件获取请求的数据,并通过 res 向客户端发送响应数据。一读一写,不禁让人联想到 reqres 是否就对应于 socket 的读和写呢?查了下 Node.js 的源代码,http.IncomingMessagehttp.ServerResponse 的确是共用了一个 socket,而这个 socket 正是 net.Server 在接收到请求连接时所创建。

再看客户端代码:

'use strict';

const http = require('http');

const postData = 'post_data';
const options = {
hostname: 'localhost',
port: 9999,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
console.log('获取到服务端响应');
res.on('data', (data) => {
console.log(`服务端响应: ${data}`);
});
});
req.write(postData);
req.end();

在上面代码中,通过 http.request 创建 http.ClientRequest,用于描述一个进行中的请求,在 http.ClientRequest 之上添加 response 事件监听,可以获取到服务端的响应描述 http.IncomingMessage,从而获取服务端响应数据。

除以上各类以外,http 模块还提供了一个 http.Agent 类,该类用于管理客户端的连接,必要时会重用 socket。此处不做详述。

小结

在日常开发过程中,我们很少直接使用 Node.js 原生的类,更多的是使用成熟的框架,比如 expresskoa,阿里集团内部也有成熟的框架,比如 midwayegg。这些框架或多或少的都对 Node.js 提供的原生能力进行了封装,我们在使用这些框架的同时,也应该清楚框架背后 Node.js 的运行机制以及能提供的能力。

在用 Node.js 起服务之前,我们应该知道这些的更多相关文章

  1. 利用OpenShift托管Node.js Web服务进行微信公众号开发

    最近写了一个微信的翻译机器人.用户只要关注该公众号,发送英文的消息,就能收到中文翻译的回复.有兴趣的读者可以扫描下面的二维码关注该公众号,尝试发送英文单词试试看.(有时候第一次发送单词会收到“该公众号 ...

  2. 个推Node.js 微服务实践:基于容器的一站式命令行工具链

    作者:个推Node.js 开发工程师 之诺 背景与摘要 由于工程数量的快速增长,个推在实践基于 Node.js 的微服务开发的过程中,遇到了如下问题: 1. 每次新建项目都需要安装一次依赖,这些依赖之 ...

  3. Node.js微服务实践(一)

    什么是微服务 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独立部署,各个微服务之间是松耦合的.每个微服务仅关注于完成一件任务并很好地完成该任务.在所有情况下 ...

  4. Node.js建立服务、路径处理与响应

    通过Node.js创建一个web服务器,要写的代码可能不是最少的,但是一定是最容易理解的. 用6行代码创建的web服务器 当在浏览器中访问http://127.0.0.1:1337会看到自定义的字样 ...

  5. 基于thrift的node.js rpc服务

    1.在node.js 服务下创建node_modules文件,npm install  thrift 下载thrift到该文件下. 2.编写idl文件.user.thrift 内容如下: struct ...

  6. Node.js启动服务报错SyntaxError: Unexpected token import

    启动服务报错如下: Last login: Wed Nov :: on ttys000 localhost:~ sipeng$ cd /Users/sipeng/Desktop/彭思/2017年学习/ ...

  7. node.js启动服务,不依赖第三方

    好好学习,天天向上,懒惰.颓废让我越来越糟糕,所以分享一下,共同学习 纯node.js搭建一个小服务,下图为文件目录结构,很简单,很小 log文件是自动生成的 index.js文件 const url ...

  8. Serverless Web Function 实践教程(一):快速部署 Node.js Web 服务

    作为目前广受欢迎的 Web 服务开发语言,Node.js 提供了众多支持 HTTP 场景的相关功能,可以说是为 Web 构建而生.因此,基于 Node.js,也诞生了多种 Web 服务框架,它们对 N ...

  9. Node.Js http服务(websocket)

    安装node,下载地址 https://nodejs.org/en/ cmd 中 输入 node -v 安装成功可以查看版本 cmd 中 ctrl - c 可以 结束 和 启动 编辑 js 文本 va ...

随机推荐

  1. linux安装x264 ffmpeg

    1. 安装yasm 2. 安装x264 3. 安装ffmpeg 安装网上很多例子,以下是我主要参考的两篇博客: http://www.cnblogs.com/lidabo/p/3987378.html ...

  2. Grails项目开发——前端请求跨域问题

    Grails项目开发--前端请求跨域问题 最近做项目采用前后端分离的思想,使用Grails作为后台开发Restful API供前端调用. 在项目开发的过程中,遇到前端没办法通过ajax访问到后台接口的 ...

  3. 【小梅哥SOPC学习笔记】切换NIOS II CPU的主内存后软件中需要注意的几点设置

    切换NIOS II CPU的主内存后软件中需要注意的几点设置 有时候,我们可能面对这样一种情况: 1. 我们创建一个SOPC系统,并在QSYS中设置NIOS II的复位地址和异常地址都指向SRAM: ...

  4. cxgrid取消过滤下拉框

    选择tableview1.optionscustomize.columnfiltering=fasle;

  5. [LeetCode 题解]: Valid Palindrome

    Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...

  6. SDOI2013 淘金

    题目链接:戳我 昨天做的题了,今天补一发题解. 是一个比较奇怪的数位DP.详细的我还是写代码注释里好了,感觉直接说不好描述. 代码如下: #include<iostream> #inclu ...

  7. 279. 完全平方数 leetcode JAVA

    题目: 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n.你需要让组成和的完全平方数的个数最少. 示例 1: 输入: n = 12 输出: 3 解释: ...

  8. 新编辑器Cocos Creator发布:对不起我来晚了!

    1月19日,由Cocos创始人王哲亲手撰写的一篇Cocos Creator新品发布稿件在朋友圈被行业人士疯狂转载,短短数小时阅读量突破五位数.Cocos Creator被誉为“注定将揭开Cocos开发 ...

  9. linux命令之网络管理命令(上)

    1.ifconfig:配置或显示网络接口信息 该命令用于配置网卡IP地址等网络参数或显示当前网络的接口状态,该命令配置网卡信息时必须要以root用户的身份来执行. 参数选项 说明 up 激活指定的网络 ...

  10. mysql基础操作学习笔记(一)

    1前期准备: SQL语言包涵以下4个部分: (1)数据定义语言(DDL):包括DROP, CREATE, ALTER等语句 (2)数据操纵语言(DML):包括INSERT, UPDATE, DELET ...