详细分析Node.js中的UDP模块

问题1:UDP模块的socket的内部签名是什么?

Socket {
  domain: null,
  _events: { message: [Function], listening: [Function] },
  _eventsCount: 2,
  _maxListeners: undefined,
  _handle:
   UDP {
     fd: undefined,
     lookup: [Function: lookup4],
     owner: [Circular],
     onmessage: [Function: onMessage] },
  _receiving: true,
  _bindState: 2,
  type: 'udp4',
  fd: -42,
  _reuseAddr: undefined }
注意:这个socket是一个EventEmitter实例而不是一个stream,相对于TCP来说其socket既是Stream实例也是EventEmitter实例。
server.on('message',function(msg,rinfo){
	//第二个参数签名为
	console.log(rinfo);
	console.log('server got:'+msg+" from "+rinfo.address+":"+rinfo.port);
})
server.on('listening',function(){
	//server对象的签名为
	var address=server.address();
	console.log('server listening '+address.address+":"+address.port);
});
//下面让UDP套接字接受网络消息,这个套接字接受所有网卡上6666端口号的消息,在绑定完成之后触发listening事件
server.bind(6666);
这时候我们服务器绑定了6666端口号,在listening中可以获取到当前服务器绑定的URL和端口号。通过 server.address方法就可以获取到服务器运行的地址。而message中事件中,其通过第二个参数rinfo可以获取来源的地址。我们看看message事件中获取到的来源的信息:

{ address: '127.0.0.1', family: 'IPv4', port: 55168, size: 12 }
注意:也就是说这个服务器运行以后监听了网卡上的一个端口号,不管UDP客户端从那台主机发送消息都是可以接收到的,只要他是发送到UDP服务器监听的端口号就可以

问题2:Class: dgram.Socket有哪些事件和方法?
通过dgram.createSocket来创建,而且不需要通过new操作符
Event: 'close'
当socket通过close方法关闭的时候触发,如果触发了,那么就不会在这个socket上触发任何"message"事件。
Event: 'error'
当抛出异常的时候触发
Event: 'listening'
当socket对象开始监听数据包文的信息触发,当UDP socket被创建的时候就会触发
Event: 'message'
第一个参数为Buffer对象,第二个参数为远程地址信息。

	socket.on('message', (msg, rinfo) => {
	  console.log('Received %d bytes from %s:%d\n',
	              msg.length, rinfo.address, rinfo.port);
	});
socket.addMembership(multicastAddress[, multicastInterface])
通知内核在一个固定的multicastAddress上使用IP_ADD_MEMBERSHIP套接字合并多路广播组,如果multicastInterface没有指定,那么操作系统会尝试把这些membership添加到所有的有效的网卡中
socket.address()
获取一个socket的所有的信息,通常包含address,family,port属性
socket.bind([port][, address][, callback])
让dgram.Socket在指定的port/address监听数据包。如果没有指定port那么操作系统就会指定一个<随机的端口>,如果address没有指定那么操作系统就会<监听所有的地址>。回调函数是一个'listening'事件的函数。一个绑定的报文socket会让Node.js进程运行并接受数据报文信息。
	const dgram = require('dgram');
	const server = dgram.createSocket('udp4');
	server.on('error', (err) => {
	  console.log(`server error:\n${err.stack}`);
	  server.close();
	});
	server.on('message', (msg, rinfo) => {
	  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
	});
	server.on('listening', () => {
	  var address = server.address();
	  console.log(`server listening ${address.address}:${address.port}`);
	});
	server.bind(41234);
	// server listening 0.0.0.0:41234
上面这个例子使用UDP监听41234端口号
socket.bind(options[, callback])
其中第一个选项是必须的,支持如下的属性。port必须,address是可选的,exclusive也是可选的。让dgram.Socket在指定的端口号和地址监听数据报文。如果port没有指定,操作系统会绑定随机的端口号。如果address没有指定就会监听所有的地址。最后一个回调函数是'listening'事件句柄。如果在使用dgram.Socket对象的时候使用了[cluster]模块,这时候就可以使用一个exclusive属性,如果设置为false那么所有的子线程就会共享一个端口号(默认值),如果设置为true,这时候如果想要端口共享就会报错。
	socket.bind({
	  address: 'localhost',
	  port: 8000,
	  exclusive: true
	});
socket.close([callback])
关闭socket,停止监听socket上面的数据,如果指定了回调就是作为'close'事件的监听器。
socket.dropMembership(multicastAddress[, multicastInterface])
让内核使用IP_DROP_MEMBERSHIP去去除multicastAddress上的多播组。当socket关闭了或者进程停止了,内核会自动调用方法,因此大多数应用不需要手动调用它。如果multicastInterface没有指定,那么操作系统会丢掉所有有效interface的memebership
socket.send(buf, offset, length, port, address[, callback])
如果没有指定address那么其值就是'0.0.0.0' or '::0',要确定数据包是否发送的最好的方式是指定一个回调函数,如果有错误抛出同时给定了回调函数,回调函数第一个参数就是错误对象, 如果没有指定回调那么错误就是在socket的'error'事件上面触发。
const dgram = require('dgram');
	const message = new Buffer('Some bytes');
	const client = dgram.createSocket('udp4');
	client.send(message, 0, message.length, 41234, 'localhost', (err) => {
	  client.close();
	});
UDP报文的大小:

IPV4/IPV6最大的报文大小取决于MTU (Maximum Transmission Unit)和Payload Length字段大小。Payload Length字段是16比特的长度,也就是正常载荷超过64KB(包含报文头和数据)(65,507 bytes = 65,535 − 8 bytes UDP header − 20 bytes IP header)。对于环回接口这个值都是正确的,但是这么大的数据报文信息对于大多数主机和网络来说都是不适用的。MUT指的是指定的链路层基础能够支持的最大的数据报文信息。对于IPV4指定的MTU最小为68字节,但是对于IPV4建议的大小为576。

对于IPV6来说,其最小的MTU是1280字节,强制最小片段的缓存大小为1500字节。68个字节太小了,因为大多数链路技术,如以太网,都有最小的MTU为1500字节。发送一个超过接受者能够接受的MTU将不会起作用,因为报文就会悄悄的丢掉,而不会告诉发送者数据没有发送成功。
socket.setBroadcast(flag)
设置或者清除SO_BROADCAST这个socket选项,当设置为true的时候,那么UDP报文就会发送到一个本地网卡的广播地址。
socket.setMulticastLoopback(flag)
设置或者清除socket连接的IP_MULTICAST_LOOP(也就是IP多播回环)。如果设置为true的时候多播报文也会被本地网卡接受
socket.setMulticastTTL(ttl)
设置socket的IP_MULTICAST_TTL选项,TTL代表'Live to Live',在这里用于一个报文允许经过的最大的跳数,当然是对于多播来说的。每经过一个路由和网关那么TTL就会减少1,如果减少为0那么不会传输。参数的范围为0~255,大多数系统默认为1.
socket.setTTL(ttl)
设置socket对象的IP_TTL选项,在这种情况下代表能经过的跳数的数量。常用于网络寻址或者多播。ttl在0~255之间,大多数系统都是64
socket.ref()
默认情况下,绑定一个socket就会阻塞Node.js进程,只要这个socket打开那么就会一直阻塞。socket.unref()就会把当前socket排除在引用计数外。socket.ref相反会把当前socket重新添加到引用计数之中,同时重新加载这个socket的默认行为。因为这个方法可以返回一个socket,因此可以接受链式调用
socket.unref()
这个方法允许把当前socket排除在引用计数之外,我们知道这些引用会导致Node.js进程一直保持活动。这个方法允许在当前socket处于活动态的时候自己退出
<dgram.Socket>类:
dgram.createSocket(options[, callback])
这个方法会产生一个<dgram.Socket>对象,其中第一个参数必须是'udp4'或者'udp6',同时也可以指定一个'reuseAddr'字段。当'reuseAddr'设置为true,那么socket.bind就会重用地址,即使已经有一个进程绑定了当前socket。'reuseAddr'默认为false,回调函数会作为'message'事件回调。一旦socket被创建,调用socket.bind()方法就会让socket去监听报文信息,如果没有为bind方法指定address和port,那么这个方法就会监听所有网卡,但是这个端口号确实是随机的。这个绑定的端口号可以使用socket.address方法返回一个对象。这个对象有address和port属性表示绑定的地址和端口号

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值