Nodejs UDP实现
前言
UDP是User Datagram Potocol 的简称,它与熟知的TCP协议一样,UDP协议直接位于IP协议的顶层。
UDP适用于一次传输量小,对可靠性要求不高的环境;UDP协议为非连接的协议,没有建立连接的过程,所以它的通信效率极高,但也因此它的可靠性不如TCP。
dgram
dgram 模块提供了UDP数据包socket的实现;
PS:nodejs V10版本内置模块,所以不再需要通过npm下载。
快速开始
const dgram = require('dgram'); const server = dgram.createSocket('udp4'); server.on('error', (err) => { console.log(`服务器异常:\n${err.stack}`); server.close(); }); server.on('message', (msg, rinfo) => { console.log(`服务器收到:${msg} 来自 ${rinfo.address}:${rinfo.port}`); }); server.on('listening', () => { const address = server.address(); console.log(`服务器监听 ${address.address}:${address.port}`); }); server.bind(41234);
dgram.createSocket()创建dgram.Socket实例,此实例为包含函数的EventEmitter。
‘close’ 时间将使用close(),关闭socket并且不会在触发新的“message”事件。
‘error‘ 当发生错误时便会触发。
‘message‘ 当接收到新数据时触发,msg和rinfo会被当作参数,传到函数中处理。
msg:消息 buffer
rinfo:远程地址信息 (address 发送方地址;family地址类型 IPv4 /IPv6;port发送方端口;size消息大小)
发送信息
socket.send(msg,[offset,length],port,[addr],callback)
msg:《buffer,string,array》要发送得消息
offset:指消息开头在buffer中得偏移
length:消息得字节数
port:端口号
addr:接收方得地址
//例 const dgram = require('dgram'); const message = Buffer.from('Some bytes'); const client = dgram.createSocket('udp4'); client.send(message, 41234, 'localhost', (err) => { client.close(); });
PS:关于UDP包得大小
IPv4/IPv6 数据包得最大尺寸取决于MTU(maximum transmission unit 最大传输单元)与payload length字段大小。
Payload Length字段有16 位宽,指一个超过 64K 的_包含_ IP 头部和数据的负载 (65,507 字节 = 65,535 − 8 字节 UDP 头 − 20 字节 IP 头部);通常对于环回地址来说是这样,但这个长度的数据包对于大多数的主机和网络来说不切实际。
.MTU指的是数据链路层为数据包提供的最大大小。对于任意链路,IPv4所托管的MTU最小为68个字节,推荐为576(典型地,作为拨号上网应用的推荐值),无论它们是完整地还是分块地抵达。
.对于IPv6,MTU的最小值是1280个字节,然而,受托管的最小的碎片重组缓冲大小为1500个字节。现今大多数的数据链路层技术(如以太网),都有1500的MTU最小值,因而68个字节显得非常小。
要提前知道数据包可能经过的每个链路的 MTU 是不可能的。发送大于接受者MTU大小的数据包将不会起作用,因为数据包会被静默地丢失,而不会通知发送者该包未抵达目的地。
进阶函数
socket.getRecvBufferSize()
return number 返回socket接收到得字节大小
socket.getSendBufferSize()
return number 返回socket发送出得字节大小
IPv4/IPv6
//IPv6 //linux 系统 const socket = dgram.createSocket('udp6'); socket.bind(1234, () => { socket.setMulticastInterface('::%eth1'); }); //windows 系统 const socket = dgram.createSocket('udp6'); socket.bind(1234, () => { socket.setMulticastInterface('::%2'); }); //IPv4 const socket = dgram.createSocket('udp4'); socket.bind(1234, () => { socket.setMulticastInterface('10.0.0.2'); });
socket.setMulticastTTL(ttl)/socket.setTTL(ttl)
设置 IP_Multicast_TTL/IP_TTL 套接字选项。一般来说,TTL表示”生存时间”,这里特指一个IP数据包传输时允许的最大跳步数。当IP数据包每向前经过一个路由或网关时,TTL值减1,若经过某个路由时,TTL值被减至0,便不再继续向前传输。比较有代表性的是,为了进行网络情况嗅探或者多播而修改TTL值。
传给 socket.setTTL() 的参数是一个范围为0-255的跳步数。大多数系统的默认值是 1 ,但是可以变化。
socket.setRecvBufferSize(size)
设置最大的套接字接收缓冲字节。
socket.setSendBufferSize(size)
设置最大的套接字发送缓冲字节。
贴士 IPv4与IPv6
为何要从IPV4升级到iPV6协议?
IPV4协议支持的物理IP地址已经即将用光,那么不升级协议的话,后面越来越多的联网设备将无法获取到足量的IP地址,也就是连不上网,这个与我们飞速发展的物联网相矛盾的。
IPv4地址长度是32,支持的物理地址是2^32-1个地址;
IPv6地址的长度是128,支持的物理地址是2^128-1个地址。
IPV6相比较IPV4有什么优势?
1、更大的地址空间,IPV6地址容量巨大。
2、iPV6地址分配遵循Aggregation原则,路由器的路由表长度减少,提高转发数据包的速度。
我的系统支持IPV6吗?
以我们目前用的win7或win10系统而言,两种协议是同时支持的
ipv4怎么升级过度到IPV6?
目前有三种主流方案,分别是双栈技术(所有的设备上ipv4 ipv6共存)、隧道技术、GRE隧道and手动隧道ipv6 over ipv4,对于普通用户我们完全不用担心,按时更新系统就可以了。