We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
计算机通信模型分为OSI七层网络模型和TCP/IP四层模型,实质只是分类程度不同,它们的对应关系如下:
TCP/IP分层模型的四个协议层分别完成以下的功能:
用于协作IP数据在已有网络介质上传输的协议。提供TCP/IP协议的数据结构和实际物理硬件之间的接口。
包含IP协议、RIP协议(Routing Information Protocol,路由信息协议),负责数据的包装、寻址和路由。同时还包含网间控制报文协议(Internet Control Message Protocol,ICMP)用来提供网络诊断信息。
提供两种端到端的通信服务。
因特网的应用层协议包括Finger、Whois、FTP(文件传输协议)、Gopher、HTTP(超文本传输协议)、Telent(远程终端协议)、SMTP(简单邮件传送协议)、IRC(因特网中继会话)、NNTP(网络新闻传输协议)等.
TCP(Transmission Control Protocol)网络传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议,数据传输前建立连接的工作要经过三次握手,数据传输后断开连接的工作要经过四次挥手。
上图中有几个字段需要重点介绍下: (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。 (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。 (3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下: (A)URG:紧急指针(urgent pointer)有效。 (B)ACK:确认序号有效。 (C)PSH:接收方应该尽快将这个报文交给应用层。 (D)RST:重置连接。 (E)SYN:发起一个新连接。 (F)FIN:释放一个连接。
连接三次握手过程:
第一次握手:客户端要和服务端进行通信,首先要告知服务端一声,遂发出一个SYN=1的连接请求信号,”服务端哥哥,我想给你说说话”。
第二次握手:当服务端接收到客户端的连接请求,此时要给客户端一个确认信息,”我知道了(ACK),我这边已经准备好了,你现在能连吗(SYN)”。
第三次握手:当客户端收到了服务端的确认连接信息后,要礼貌的告知一下服务端,“好的,咱们开始联通吧(ACK)”。
到此整个建立连接的过程已经结束,接下来就是双方你一句我一句甚至同时交流传递信息的过程了。
结束四次挥手过程:
第一次挥手:双方交流的差不多了,此时客户端也已经结尾了,接下来要断开通信连接,所以告诉服务端“我说完了(FIN)”,此时自身形成等待结束连接的状态。
第二次挥手:服务端知道客户端已经没话说了,服务端此时还有两句心里话要给客户端说,“我知道你说完了(ACK),我再给你说两句,&*……%¥”。
第三次挥手:此时客户端洗耳恭听继续处于等待结束的状态,服务器端也说完了,自身此时处于等待关闭连接的状态,并对告诉客户端,“我说完了,咱们断了吧(FIN)”。
第四次挥手:客户端收知道服务端也说完了,也要告诉服务端一声(ACK),因为连接和断开要双方都按下关闭操作才能断开,客户端同时又为自己定义一个定时器,因为不知道刚才说的这句话能不能准确到达服务端(网络不稳定或者其他因素引起的网络原因),默认时间定为两个通信的最大时间之和,超出这个时间就默认服务器端已经接收到了自己的确认信息,此时客户端就关闭自身连接,服务器端一旦接收到客户端发来的确定通知就立刻关闭服务器端的连接。
到此为止双方整个通信过程就此终结。这里要声明一下:断开链接不一定就是客户端,谁都可以先发起断开指令,另外客户端和服务端是没有固定标准的,谁先发起请求谁就是客户端。
网络编程的概念是"使用套接字来达到进程间通信的目的"。通常情况下,我们要使用网络提供的功能,可以有以下几种方式:
网络编程涉及到一个套接字(socket)的概念,所谓套接字,实际上是两个不同进 程间进行通信的端口(这里的端口有别于IP地址中常用的端口),它是对网络层次模型中网络层及其下面各层操作的一个封装,为了让开发者能够使用各种语言调用操作系统提供的网络服务,在不同服务端语言中都使用了套接字这个概念,开发者只要获得一个套接字(socket),就可以使用套接字(socket)中各种方法来创建不同进程之间的连接进而达到通信目的。
Node.js也提供了对socket的支持,它提供了一个net模块用来处理和TCP相关的操作,提供了dgram模块用来处理UDP相关操作。除此之外,还有v8底层相关的网络模块有tcp_wrap.cc、udp_wrap.cc、pipe_wrap.cc、stream_wrap.cc等等,在Javascript层以及C++层之间通过process.binding进行桥接相互通信。
创建一个TCP服务器,可以通过使用构造函数new net.Server或者使用工厂方法net.createServer,这两个方法都会返回一个net.Server类,可接收两个可选参数。
var net=require('net'); var server=net.createServer(function(socket){ console.log('客户端和服务端建立连接'); server.getConnections(function(err,count){ console.log("当前连接数为%d",count); }); server.maxConnections=2; console.log('tcp最大连接数为%d',server.maxConnections); }); server.on('error',function(e){ if(e.code=='EADDRINUSE'){ console.log('地址和端口被占用'); } }); server.listen(3000,'localhost',function(){ //console.log('服务器端开始监听...'); var address=server.address(); console.log(address); });
在终端使用tenlent 0.0.0.0 3000 即可与之通信。
net.createServer() 创建的服务器是一个 EventEmitter 实例,它的自定义事件有如下几种:
创建一个TCP客户端链接可以使用构造函数new net.Socket或者其工厂方法net.createConnection,创建成功后都会返回一个net.Socket实例。
var net = require('net'); var client = net.createConnection({port:3000, host:'localhost'}); client.on('connect',function(){ console.log('client connect'); client.write('hello world!'); setTimeout(function(){ client.end('bye bye'); },10000); }); client.on('data',function(data){ console.log('client data',toString()); }); client.on('error',function(error){ throw error; client.destroy(); }); client.on('close',function(){ console.log('client close'); });
服务器可以与多个客户端保存连接,每个连接都是典型的可读可写的 Stream 对象。它的自定义事件有如下几种:
从上面可以看出基于TCP连接的通信具有的特点:
相对于TCP,UDP是一种非连接不可靠但高效的传输协议。即传输便捷、效率非常高。
var dgram=require('dgram'); var server=dgram.createSocket('udp4'); server.on("message",(msg,rinfo) => { console.log('已接收到客户端发送的数据为' + msg); console.log("客户端地址新信息为%j", rinfo); var buff=new Buffer("确认信息"+msg); server.send(buff,0,buff.length,rinfo.port,rinfo.address); setTimeout(() => { server.unref(); },10000); }); server.on("listening", () => { var address = server.address(); console.log("服务器开始监听,地址信息为%j",address); }); server.bind(3000,'localhost');
var dgram=require('dgram'); var message= Buffer.from('hello world'); var client=dgram.createSocket('udp4'); client.send(message,0,message.length, 3000,"localhost", (err,bytes) => { if(err) console.log('数据发送失败'); else console.log("已发送%d字节数据",bytes); }); client.on("message", (msg,rinfo) => { console.log("已接收到服务端发送的数据%s",msg); console.log("服务器地址信息为%j",rinfo); client.close(); }); client.on("close", () => { console.log("socket端口被关闭"); });
UDP 相对于 TCP 更简单,它只是一个 EventEmitter 的实例,而非 Stream 的实例。它自定义事件如下:
socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。 UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。
更详细的定义参见UNIX Domain Socket IPC
const net = require("net"); const server = net.createServer(c => { c.on("end", () => { console.log("client disconnected"); }); c.write("hello\r\n"); c.pipe(c); }); server.on("error", err => { throw err; }); // server.listen(path[, backlog][, callback]) for IPC servers server.listen("/tmp/echo.sock", () => { console.log("server bound"); });
nc -U /tmp/echo.sock # -U — Use UNIX domain socket
nc(netcat)可以用于涉及 TCP 或 UDP 的相关内容,比如通过它我们可以打开 TCP 连接,发送 UDP 数据包,监听任意的 TCP 和 UDP 端口,执行端口扫描和处理 IPv4 和 IPv6 等。
网络编程 深入学习 Node.js Net
The text was updated successfully, but these errors were encountered:
No branches or pull requests
通信模型
计算机通信模型分为OSI七层网络模型和TCP/IP四层模型,实质只是分类程度不同,它们的对应关系如下:
TCP/IP分层模型的四个协议层分别完成以下的功能:
网络接口层
用于协作IP数据在已有网络介质上传输的协议。提供TCP/IP协议的数据结构和实际物理硬件之间的接口。
网间层
包含IP协议、RIP协议(Routing Information Protocol,路由信息协议),负责数据的包装、寻址和路由。同时还包含网间控制报文协议(Internet Control Message Protocol,ICMP)用来提供网络诊断信息。
传输层
提供两种端到端的通信服务。
应用层
因特网的应用层协议包括Finger、Whois、FTP(文件传输协议)、Gopher、HTTP(超文本传输协议)、Telent(远程终端协议)、SMTP(简单邮件传送协议)、IRC(因特网中继会话)、NNTP(网络新闻传输协议)等.
TCP握手
TCP(Transmission Control Protocol)网络传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议,数据传输前建立连接的工作要经过三次握手,数据传输后断开连接的工作要经过四次挥手。
TCP报文格式
上图中有几个字段需要重点介绍下:
(1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
(A)URG:紧急指针(urgent pointer)有效。
(B)ACK:确认序号有效。
(C)PSH:接收方应该尽快将这个报文交给应用层。
(D)RST:重置连接。
(E)SYN:发起一个新连接。
(F)FIN:释放一个连接。
连接三次握手过程:
第一次握手:客户端要和服务端进行通信,首先要告知服务端一声,遂发出一个SYN=1的连接请求信号,”服务端哥哥,我想给你说说话”。
第二次握手:当服务端接收到客户端的连接请求,此时要给客户端一个确认信息,”我知道了(ACK),我这边已经准备好了,你现在能连吗(SYN)”。
第三次握手:当客户端收到了服务端的确认连接信息后,要礼貌的告知一下服务端,“好的,咱们开始联通吧(ACK)”。
到此整个建立连接的过程已经结束,接下来就是双方你一句我一句甚至同时交流传递信息的过程了。
结束四次挥手过程:
第一次挥手:双方交流的差不多了,此时客户端也已经结尾了,接下来要断开通信连接,所以告诉服务端“我说完了(FIN)”,此时自身形成等待结束连接的状态。
第二次挥手:服务端知道客户端已经没话说了,服务端此时还有两句心里话要给客户端说,“我知道你说完了(ACK),我再给你说两句,&*……%¥”。
第三次挥手:此时客户端洗耳恭听继续处于等待结束的状态,服务器端也说完了,自身此时处于等待关闭连接的状态,并对告诉客户端,“我说完了,咱们断了吧(FIN)”。
第四次挥手:客户端收知道服务端也说完了,也要告诉服务端一声(ACK),因为连接和断开要双方都按下关闭操作才能断开,客户端同时又为自己定义一个定时器,因为不知道刚才说的这句话能不能准确到达服务端(网络不稳定或者其他因素引起的网络原因),默认时间定为两个通信的最大时间之和,超出这个时间就默认服务器端已经接收到了自己的确认信息,此时客户端就关闭自身连接,服务器端一旦接收到客户端发来的确定通知就立刻关闭服务器端的连接。
到此为止双方整个通信过程就此终结。这里要声明一下:断开链接不一定就是客户端,谁都可以先发起断开指令,另外客户端和服务端是没有固定标准的,谁先发起请求谁就是客户端。
网络编程
网络编程的概念是"使用套接字来达到进程间通信的目的"。通常情况下,我们要使用网络提供的功能,可以有以下几种方式:
网络编程涉及到一个套接字(socket)的概念,所谓套接字,实际上是两个不同进 程间进行通信的端口(这里的端口有别于IP地址中常用的端口),它是对网络层次模型中网络层及其下面各层操作的一个封装,为了让开发者能够使用各种语言调用操作系统提供的网络服务,在不同服务端语言中都使用了套接字这个概念,开发者只要获得一个套接字(socket),就可以使用套接字(socket)中各种方法来创建不同进程之间的连接进而达到通信目的。
Node.js也提供了对socket的支持,它提供了一个net模块用来处理和TCP相关的操作,提供了dgram模块用来处理UDP相关操作。除此之外,还有v8底层相关的网络模块有tcp_wrap.cc、udp_wrap.cc、pipe_wrap.cc、stream_wrap.cc等等,在Javascript层以及C++层之间通过process.binding进行桥接相互通信。
创建TCP服务端
创建一个TCP服务器,可以通过使用构造函数new net.Server或者使用工厂方法net.createServer,这两个方法都会返回一个net.Server类,可接收两个可选参数。
在终端使用tenlent 0.0.0.0 3000 即可与之通信。
net.createServer() 创建的服务器是一个 EventEmitter 实例,它的自定义事件有如下几种:
创建TCP客户端
创建一个TCP客户端链接可以使用构造函数new net.Socket或者其工厂方法net.createConnection,创建成功后都会返回一个net.Socket实例。
服务器可以与多个客户端保存连接,每个连接都是典型的可读可写的 Stream 对象。它的自定义事件有如下几种:
从上面可以看出基于TCP连接的通信具有的特点:
创建UDP的客户端和服务端
相对于TCP,UDP是一种非连接不可靠但高效的传输协议。即传输便捷、效率非常高。
创建UDP服务端
创建UDP客户端
UDP 相对于 TCP 更简单,它只是一个 EventEmitter 的实例,而非 Stream 的实例。它自定义事件如下:
UNIX Domain Socket IPC
socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。
创建一个 UNIX 域套接字服务器
连接UNIX 域套接字服务器
参考
网络编程
深入学习 Node.js Net
The text was updated successfully, but these errors were encountered: