当前位置: 首页 > 后端技术 > Node.js

知乎node的核心模块--网络编程

时间:2023-04-03 23:35:32 Node.js

原文在我的博客,转载请注明出处,谢谢在构建网络通信服务方面,相对于其他老牌后端语言,Node.js也能胜任(也许更好)Onechip),并且有自己独特的处理方式。Node是一个面向网络的平台。其事件驱动、非阻塞、单线程的特性使得节点应用具有低内存、高并发、扩展性强的优良特性,适用于分布式网络。Node底层实现了传输层TCP/UDP和应用层HTTP/HTTPS的功能,并封装成适合网络的API,无需依赖第三方服务即可创建自己的服务器。使用起来非常方便、简单、灵活。对于网络编程,node提供了net、dgram、http、https四个模块,分别用于处理TCP、UDP、HTTP、HTTPS。本文将介绍这些模块,并使用这些模块提供的API来构建简单的Web服务。事实上,无论是什么语言,什么平台,网络编程的实现都需要遵循网络标准规范,只是具体实现或者提供的API不同而已。因此,在讨论节点网络编程之前,我们需要了解网络通信所使用的网络协议(推荐阅读《图解HTTP》)。了解了网络通信的规范和机制后,熟悉API就足够了。TCP/UDPTCP(TransmissionControlProtocol)传输控制协议是一种面向连接的协议,即必须建立连接才能发送数据。在传输之前,TCP需要和服务器进行3次握手才能形成一个会话(SYN是同步信号,ACK是确认信号):TCP传输数据比较可靠,如果丢失数据会重传,并对传输的数据进行排序。适用于重要的、有序的数据传输。UDP(UserDatagramProtocol)是一种无连接的协议,不是面向连接的,而是面向事务的。创建过程比较简单,占用内存底部,处理快速灵活。发送数据不需要和另一端建立连接,不区分客户端和服务器端,一端既可以发送数据也可以接收数据。数据传输无序,网络中断会导致丢包。UDP简单、不可靠的特性适用于一些数据丢失不会造成太大影响的场景,比如音视频数据传输。套接字网络上的两个程序通过双向通信连接实现数据交换。这种连接的一端称为套接字(socket),因此至少需要一对端口号(套接字)才能建立网络通信连接。socket的本质是对TCP/IP协议栈的封装,为TCP或UDP编程提供接口,而不是另外一种协议。通过socket,可以使用TCP/IP协议。Socket的英文原意是“孔”或“插座”。作为BSDUNIX的进程通信机制,取后一种意思。通常也称为“套接字”,用于描述IP地址和端口,是一个通信链的句柄,可用于实现不同虚拟机或不同计算机之间的通信。互联网上的主机一般运行多种服务软件,同时提供多种服务。每个服务打开一个Socket并绑定一个端口,不同的端口对应不同的服务。Socket正如它的英文原意一样,就像一个多孔的插座。一台主机就像一个布满各种插座的房间,每个插座都有一个编号,有的插座提供220伏的交流电,有的提供110伏的交流电,有的提供有线电视节目。客户端软件可以通过将插头插入不同编号的插座得到不同的服务。——百度百科创建TCP、UDP客户端和服务器节点中,net模块提供了创建基于TCP协议的网络通信的API,net.Socket类提供了TCP或UNIXSocket的抽象,net.createServer用于创建服务器端,net.Socket和net.connect用于创建客户端。dgram模块用于创建基于UDP协议的网络服务。创建不区分客户端和服务器。在一端使用dgram.createSocket发送数据或接收数据。http/httpshttp是应用层协议,建立在TCP/IP之上,https建立在TLS和SSL加密层协议之上。现代网络基本上是http/https应用程序。TCP在建立连接时发送消息,HTTP也是如此。HTTP消息分为请求消息和响应消息。消息格式如下:HTTP/1.0200OK//起始行Content-type:text/plain//HeaderPartContent-length:19//HeaderHiI'mamessage!//body中最重要的部分是headermessage,它定义了请求或响应的行为,是客户端和服务端通信的重要信息。http报文的头部有几十个属性,而且越来越多,保证客户端和服务端的充分通信。现代浏览器集成了HTTP代理功能。当用户点击一个链接时,浏览器会生成一个HTTP请求报文并发送给服务器。收到响应后,它会解析消息并渲染消息的主要内容。node中的http模块提供了一个接口,用于创建基于http协议的网络通信应用程序。它继承于net模块,采用事件驱动机制。它可以与多个客户端保持连接,并且不会为每个连接打开一个新的进程或线程,低内存,高并发,性能优异。》http模块将用于连接的套接字(socket)的读写抽象为ServerRequest和ServerResponse对象,分别对应请求和响应操作。在请求产生的过程中,http模块从connection并调用binary模块http_parser解析,解析出请求报文的header后,触发请求事件,调用用户的业务逻辑。”——蒲灵《深入浅出Node.js》从上图可以看出,什么node中的http模块做的是继承net模块使用TCP协议,封装http请求,产生http事件,响应事件绑定handlers。httpagent节点中的http模块提供了一个类http.Agent,这个类叫做httpagent,其作用是复用TCP连接,减少资源浪费。那么http代理是如何复用TCP连接的呢?http代理维护了一个连接池,客户端发起的http请求通过代理进行管理:它维护给定主机和端口的等待请求队列,并为每个请求重用单个套接字(TCP)连接,直到队列为空,此时套接字(TCP连接)将被销毁或放入连接池中,等待由连接池中具有相同主机和端口的请求再次使用。是销毁还是放入连接池取决于keepAlive选项——Node.js8.9.0中文文档连接池如何管理连接取决于服务器:即使连接中连接的TCPKeep-Alive连接池打开后,服务器可能仍会关闭空闲连接,在这种情况下,这些连接将从连接池中移除,并在发出新的HTTP请求时为指定的主机和端口创建一个新连接。服务器也可能拒绝在同一个连接上允许多个请求,在这种情况下,为每个请求重新创建连接并且不能合并。代理仍然会向服务器发出请求,但每个请求都会出现在一个新的连接上。但是当客户端或服务器关闭连接时,它会从连接池中删除。释放连接池中任何未使用的套接字,以便在没有请求时Node.js进程不必继续运行。——Node.js8.9.0中文文档http模块除了提供代理类外,还提供:http.ClientRequest类——表示一个正在处理的请求,这个请求还可以设置请求头http.Server类——继承net.Server,并添加了一些事件http.ServerResponse类-表示对http.createServer方法的响应-创建服务器,返回http.Server实例http.request方法-对各种请求显式发送请求,并响应相应的事件创建httpServer//node创建服务器非常简单,不需要任何第三方代理varhttp=require('http');http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'text/plain'})res.end('HelloWorld\n');}).listen(8880,'127.0.0.1');console.log('服务器运行于http://127.0.0.1:8880/')创建http请求并使用http.request发送请求。WebSocket问答是HTTP协议的一个特性,但是服务端主动向客户端推送数据的场景也是常见且需要的。在WebSocket出现之前,客户端与服务端的双工通信一般只能通过开启多个HTTP连接并进行轮询来实现。由于HTTP的一问一答特性不适合这种场景,即使是HTTP1.1新的Keep-Alive也不能很好的解决这个问题,所以出现了WebSocket协议。WebSocket协议实现了客户端和服务端的双向通信,服务端可以主动向客户端发送数据。当建立WebSocket协议连接时,客户端会发送一个HTTP请求请求服务器端将协议切换为WebSocket。如果服务端支持WebSocket协议,会返回一个HTTP响应,表示正在切换WebSocket协议,切换。然后就可以互相发送数据了。使用WebSocket协议构建应用有以下优点:客户端可以实现与服务端的双向通信,服务端可以通过第一次请求建立TCP连接后主动向客户端发送数据,后续的数据交换不不需要发送HTTP标头。可以交换数据目前大部分浏览器都实现了WebSocket,可以直接使用:varsocket=newWebSocket('ws://localhost:3000/')//路径中的协议改为ws(WebSocket)socket.onopen=function(){//连接打开时做什么};socket.onmessage=function(event){//从服务器接收信息(event.data)};调用WebSocket后,浏览器会发送HTTP请求,请求消息如下:GET/chatHTTP/1.1Host:server.example.comUpgrade:websocket//请求协议升级为websocketConnection:UpgradeSec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==//校验值Sec-WebSocket-Protocol:chat,superchatSec-WebSocket-Version:13Node原生模块中没有支持WebSocket协议连接功能的模块,但是Node有很多第三方模块可以帮助实现这一点。常用的ws模块方法如下://引入WebSocket模块:constWebSocket=require('ws');//引用Server类:constWebSocketServer=WebSocket.Server;//实例化:constwss=newWebSocketServer({//在本地3000端口上打开一个WebSocketServerport:3000});wss.on('connection',function(ws){console.log(`[SERVER]connection()`);ws.on('message',function(message){console.log(`[SERVER]收到:${message}`);ws.send(`ECHO:${message}`,(err)=>{if(err){console.log(`[SERVER]error:${err}`);}});})});服务器返回的响应信息如下:HTTP/1.1101SwitchingProtocolsUpgrade:websocketConnection:UpgradeSec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=//返回计算出的校验值Sec-WebSocket-Protocol:chat使用框架进行网络编程.Node网络模块中提供的API相对底层。有时在构建网络应用程序时,您不需要关心底层实现。这时候就可以使用三方框架来打包了。API来帮助我们,常用的框架有express、koa、connect等。