Node.js网络编程
Node.js网络编程
在Web领域,大多数编程语言需要专门的Web服务器容器,如ASP需要IIS服务器,Java需要Tomcat服务器,PHP需要Apache服务器。Node则不需要额外的容器。
Node提供了多个模块:
net:TCP
dgram:UDP
http:HTTP
https:HTTPS
构建TCP服务
TCP:传输控制协议。传输层
大多数网络应用是基于TCP搭建的。
创建会话,服务端和客户端分别提供一个套接字,实现连接。
创建TCP服务器端:
1 | var net = require('net'); |
TCP服务事件:
服务器事件
连接事件
服务器可以同时与多个客户端保持连接,每个连接都是可读可写的Stream对象。
TCP对小数据包有优化策略:Nagle算法。合并成一个大数据包再发送,可以导致延迟,Node默认是开启的,可以关闭。
1 | socket.setNoDelay(true); |
构建UDP服务
UDP:用户数据包服务。不是面向连接的。
在UDP中,一个socket可以与多个UDP服务通信。
适用于允许丢包的场景,如音视频。
创建UDP套接字,既可以作为客户端发送数据,也可以作为服务器接收数据。
1 | var dgram = require('dgram'); |
接收数据
1 | // 监听接收的数据 |
发送数据
1 | var msg = Buffer.form('Hello'); |
构建HTTP服务
TCP和UDP都是传输层协议,用于构建高效的网络应用。如果支持普通的应用,使用应用层协议就绰绰有余,如 HTTP。
HTTP构建在TCP之上
HTTP报文:报文头+报文体
TCP服务以connection为单位,HTTP服务以request为单位,一个TCP会话可以用于多次HTTP请求和响应。
http模块是将connection到request的过程进行了封装。
HTTP服务端
ServerRequest
ServerResponse
1 | var http = require('http'); |
请求报文的主体是一个只读流对象,响应报文的主体是一个可写流对象。
HTTP服务的事件
connection:客户端与服务端建立连接时触发
request:在解析出请求头时触发
close:服务器关闭时(所有连接都断开)触发
connect:当客户端发起CONNECT请求时触发
checkContinue:当客户端发送头部带
Expect: 100-continue的请求时触发upgrade:当客户端要求升级协议时触发,与WebSocket有关
clientError
HTTP客户端
ClientRequest
ClientResponse
1 | var http = require('http'); |
http模块包含一个默认的客户端代码对象http.globalAgent,对连接进行管理,底层是线程池,对同一个服务端的请求最多创建5个连接(同浏览器限制相同)
HTTP客户端事件
response:得到服务端响应
socket:当底层连接分配给当前请求时
connect:当服务端响应了CONNECT请求时
upgrade:当服务端响应了
101 Switching Protocols状态时continue:当服务端响应了
100 Continue状态时
构建WebSocket服务
Node没有内置WebSocket库,社区的ws模块封装了WebSocket底层实现。
WebSocket相对HTTP的好处:
客户端与服务端只建立一个TCP连接
服务端可以推送数据到客户端,双向通信
协议头更轻量
WebSocket客户端
1 | var socket = new WebSocket('ws://127.0.0.1:12100/updates'); |
WebSocket协议分为:握手和数据传输
通过HTTP发送升级协议请求,特有协议头:
1 | Upgrade: websocket, |
重点:Sec-WebSocket-Key的值用于校验。
(1)客户端随机生成一个Base64编码的字符串key。
(2)服务端拿到该字符串后,与一串特定字符串拼接,计算SHA1散列值,再进行Base64编码,放在响应的Sec-WebSocket-Accept中。
1 | Base64(sha1(key+'xxx')) |
(3)客户端通过响应拿到返回值,进行校验
1 | Base64(sha1(key+'xxx')) == accept |
WeBSocket数据帧协议
客户端需要对发送的数据帧进行掩码处理,服务端发送给客户端的则不能做掩码处理。
每8位(1个字节)为一列。
每一位的意义:
opcode:4位操作码,用来描述当前帧
masked:1位,是否进行掩码处理,客户端为1需要掩码,服务端为0不需要掩码
payload length:7或7+16或7+64位,标识数据长度
masking key:32位,掩码
payload data:位数为8的倍数,数据
发送数据时,需要构造一个或多个数据帧协议报文。
客户端发送报文时,需要使用掩码对二进制进行加密,服务端收到后,需要进行解密。
服务端发送报文时,无需掩码。
网络服务与安全
SSL(Secure Sockets Layer,安全套接协议)很早就提出了,是一种安全协议,在传输层对网络连接进行加密和解密,应用层是透明的,后来标准化为 TLS(Transport Layer Security)安全传输层协议。
Node提供了3个安全方面的模块:
crypto:各种加密算法
tls:功能与net模块类似,但建立在 TLS/SSL 加密的 TCP 连接上
https:功能和http模块类似,只是建立在安全连接上
TLS/SSL
基于非对称加密
客户端和服务端都有自己的公钥/私钥。公钥加密要发送的数据,私钥解密接收到的数据。
在建立安全传输之前,客户端和服务端需要互换公钥。给谁发送消息就用谁的公钥进行加密,对方接收到使用自己的私钥就可以解密。
Node的底层采用openssl来实现TLS/SSL。
生成私钥
1 | openssl genrsa |
生成公钥
1 | openssl rsa |
中间人攻击:在客户端和服务器交换公钥时,攻击者插入其中,同时扮演客户端和服务端,获得双方的公钥,这样就可以解密拿到双方的真实数据。
为了解决中间人攻击,TLS/SSL引入了“数字证书”。
数字证书
主要包含:
服务器基本信息
服务器公钥
认证机构信息
认证机构的签名
引入了一个第三方——CA(Certificate Authority,证书认证机构),CA的作用是为站点颁发证书。
通过正规的证书机构颁发证书需要付出一定的精力和费用,大部分小公司采用“自签名证书”,即自己扮演CA,给自己的服务器颁发证书。
服务器端:
通过私钥生成CSR(Certificate Signing Request,证书签名请求)
把CSR交给CA
CA端颁发证书:
生成自己的私钥key
生成自己的csr
生成自己的证书crt
用自己的私钥key和证书crt给服务器的csr生成服务器的crt
把服务器crt交给服务器
客户端连接前会获取服务器证书,并通过CA证书验证服务端证书的真伪。
知名CA机构的证书一般预装在浏览器中,自签名证书客户端需要获取。
TLS服务
创建服务器端
1 | var tls = require('tls') |
创建客户端
1 | var tls = require('tls') |
HTTPS服务
HTTPS服务是工作在TLS/SSL上的HTTP。
服务端需要准备私钥和签名证书。
HTTPS服务端
1 | var https = require('https') |
HTTPS客户端
1 | var https = require('https') |

