Node.js dgram模块实现UDP通信示例代码


Posted in Javascript onSeptember 26, 2017

1、什么是UDP?

这里简单介绍下,UDP,即用户数据报协议,一种面向无连接的传输层协议,提供不可靠的消息传送服务。UDP协议使用端口号为不同的应用保留其各自的数据传输通道,这一点非常重要。与TCP相比,占用资源更少,传输速度更快。

2、了解UDP单播、广播和组播

单播:向一个单播地址发送UDP数据报时,数据报只能被指定的IP主机接收,同一子网下的其它主机都不会接收该数据报。单播过程(假设子网地址:192.168.10,该子网下有两台主机:192.168.10.2,192.168.10.3,向192.168.10.2发送数据报)

1.向主机192.168.10.2的8060端口发送数据报,该IP数据报目标IP在以太网中被ARP解析成MAC地址,然后将此MAC地址设置为目标地址发出去。

2.该子网下的主机以太网接口看到该数据帧时,对比自己的MAC地址,如果不一样,则忽略该数据帧。

3.直到192.168.10.2主机看到该数据帧时,发现MAC一致,则读入该数据帧,然后在IP层对比目标IP和本机IP,在UDP层对比端口号是否一致,最后接收该数据帧。

广播:向一个广播地址发送UDP数据报,该广播网络下的所有主机都会受到影响,主机根据端口号来判断是否丢弃该数据。广播过程(假设子网地址:192.168.10,则该网络的广播地址为:192.168.10.255,该子网下有两台主机:192.168.10.2,192.168.10.3,向192.168.10.255发送数据报):

1.向192.168.10.255主机端口为8060发送数据报,,该IP数据报目标IP在以太网中被ARP解析成MAC地址,然后将此MAC地址设置为目标地址发出去。

2.192.168.10.2和192.168.10.3的主机接口都会和此广播地址匹配成功,直到该数据报进入传输层时根据端口是否匹配判断是否丢弃该数据,端口为8060的会保留该数据,否则将数据丢弃。

:向一个组播地址发送UDP数据报,该组网络下的所有主机都会受到影响,主机根据端口号来判断是否丢弃该数据。组播过程原理与广播类似。

3、dgram模块API介绍

该模块用来创建UDP数据报socket,继承了EventEmitter,该模块的API如下所示:

Node.js dgram模块实现UDP通信示例代码

3、UDP单播实现

单播的原理上面已经说了,这里便不再叙述。

服务端:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('close',()=>{
  console.log('socket已关闭');
});

server.on('error',(err)=>{
  console.log(err);
});

server.on('listening',()=>{
  console.log('socket正在监听中...');
});

server.on('message',(msg,rinfo)=>{
  console.log(`receive message from ${rinfo.address}:${rinfo.port}`);
  server.send('exit',rinfo.port,rinfo.address)
});

server.bind('8060');

客户端:

const dgram = require('dgram');
const client = dgram.createSocket('udp4');

client.on('close',()=>{
  console.log('socket已关闭');
});

client.on('error',(err)=>{
  console.log(err);
});
client.on('message',(msg,rinfo)=>{
  if(msg=='exit') client.close();
  console.log(`receive message from ${rinfo.address}:${rinfo.port}`);
});
client.send(`hello`,8060,'1.1.1.69');

3、UDP广播实现

要实现UDP广播,就必须知道广播地址,广播地址如何计算呢?可以利用ipconfig(windows)或ifconfig(*unix)得到ip地址和mask掩码地址,然后利用ip地址与mask子网掩码做与操作得到网络地址,网络地址中主机位都为1就是广播地址,举个例子:

IP:149.88.160.58
mask:11111111.11111111.11000000.00000000
IP&MASK得到网络地址:149.88.128.0/18
网络号就是主机位全为0,即149.88.10000000.00000000 即149.88.128.0
广播地址就是主机位全为1,即149.88.10111111.11111111即149.88.191.255

接着实现UDP广播,我机子的IP为1.1.1.69,掩码为255.255.255.0,因此广播地址为1.1.1.255,服务端向广播地址的8061端口发送数据报,客户端绑定本机的8061端口,如下所示:

服务端:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('close',()=>{
  console.log('socket已关闭');
});

server.on('error',(err)=>{
  console.log(err);
});

server.on('listening',()=>{
  console.log('socket正在监听中...');
  server.setBroadcast(!0);//开启广播
  server.setTTL(128);
  server.send('大家好啊,我是服务端.',8061,'1.1.1.255');
});

server.on('message',(msg,rinfo)=>{
  console.log(`receive message from ${rinfo.address}:${rinfo.port}`);
});

server.bind('8060','1.1.1.69');

客户端:

const dgram = require('dgram');
const client = dgram.createSocket('udp4');

client.on('close',()=>{
  console.log('socket已关闭');
});

client.on('error',(err)=>{
  console.log(err);
});
client.on('listening',()=>{
  console.log('socket正在监听中...');
});
client.on('message',(msg,rinfo)=>{
  console.log(`receive message from ${rinfo.address}:${rinfo.port}:${msg}`);
});
client.bind(8061,'1.1.1.69');

3、UDP组播实现

组播地址是实现UDP组播的关键,因此了解组播地址是重点。什么是组播地址?IANA将D类地址(224.0.0.0-239.255.255.255)分配给IP组播,用来标识一个IP组播组,由IGMP(组管理协议)协议维护组成员关系,其中:

224.0.0.0~224.0.0.255为永久组地址,地址224.0.0.0保留不做分配,其它地址供路由协议使用;

224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;

224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;

239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

向组播地址发送数据报,只有该组成员才会接收此数据报。

dgram模块的addMembership()方法将socket加入组播组中,dropMembership()方法退出组播组。下面以组播地址224.100.100.100来实现UDP组播,如下所示:

服务端:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const multicastAddr = '224.100.100.100';

server.on('close',()=>{
  console.log('socket已关闭');
});

server.on('error',(err)=>{
  console.log(err);
});

server.on('listening',()=>{
  console.log('socket正在监听中...');
  server.addMembership(multicastAddr);
  server.setMulticastTTL(128);
  setInterval(()=>{
    sendMsg();
  },1500);
});

server.on('message',(msg,rinfo)=>{
  console.log(`receive message from ${rinfo.address}:${rinfo.port}`);
});

function sendMsg(){
  server.send('大家好啊,我是服务端.',8061,multicastAddr);
}

server.bind('8060','1.1.1.69');

客户端:

const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const multicastAddr = '224.100.100.100';

client.on('close',()=>{
  console.log('socket已关闭');
});

client.on('error',(err)=>{
  console.log(err);
});
client.on('listening',()=>{
  console.log('socket正在监听中...');
  client.addMembership(multicastAddr);
});
client.on('message',(msg,rinfo)=>{
  console.log(`receive message from ${rinfo.address}:${rinfo.port}:${msg}`);
});
client.bind(8061,'1.1.1.69');

另外UDP内网穿透相关的内容,大家也可自行了解一下。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
超级简单的图片防盗(HTML),好用
Apr 08 Javascript
javascript 对象定义方法 简单易学
Mar 22 Javascript
jQuery效果 slideToggle() 方法(在隐藏和显示之间切换)
Jun 28 Javascript
jquery实现excel导出的方法
Apr 04 Javascript
JavaScript学习总结之JS、AJAX应用
Jan 29 Javascript
JS正则替换去空格的方法
Mar 24 Javascript
jQuery中map函数的两种方式
Apr 07 jQuery
jQuery实现的简单在线计算器功能
May 11 jQuery
react-native动态切换tab组件的方法
Jul 07 Javascript
React中this丢失的四种解决方法
Mar 12 Javascript
微信小程序下拉框搜索功能的实现方法
Jul 31 Javascript
浅谈Vue使用Elementui修改默认的最快方法
Dec 05 Vue.js
深入理解ES6 Promise 扩展always方法
Sep 26 #Javascript
微信小程序开发之IOS和Android兼容的问题
Sep 26 #Javascript
Thinkphp5微信小程序获取用户信息接口的实例详解
Sep 26 #Javascript
微信小程序url与token设置详解
Sep 26 #Javascript
微信小程序之滚动视图容器的实现方法
Sep 26 #Javascript
微信小程序开发之好友列表字母列表跳转对应位置
Sep 26 #Javascript
深入理解Vuex 模块化(module)
Sep 26 #Javascript
You might like
推荐5款跨平台的PHP编辑器
2014/12/25 PHP
PHP中使用正则表达式提取中文实现笔记
2015/01/20 PHP
PHP登录验证码的实现与使用方法
2016/07/07 PHP
Ucren Virtual Desktop V2.0
2006/11/07 Javascript
ajax无刷新动态调用股票信息(改良版)
2008/11/01 Javascript
利用JavaScript实现新闻滚动效果(实例代码)
2013/11/27 Javascript
jquery ajax应用中iframe自适应高度问题解决方法
2014/04/12 Javascript
模拟一个类似百度google的模糊搜索下拉列表
2014/04/15 Javascript
简单介绍jsonp 使用小结
2016/01/27 Javascript
深入解析AngularJS框架中$scope的作用与生命周期
2016/03/05 Javascript
vue2.0实战之基础入门(1)
2017/03/27 Javascript
jQuery实现div跟随鼠标移动
2020/08/20 jQuery
JS实现的图片选择顺序切换和循环切换功能示例【测试可用】
2018/12/28 Javascript
vue中的计算属性和侦听属性
2020/11/06 Javascript
[02:36]DOTA2亚洲邀请赛小组赛精彩集锦:EE凭借法力虚空拿下4杀
2017/03/30 DOTA
python3使用tkinter实现ui界面简单实例
2014/01/10 Python
用Python实现一个简单的多线程TCP服务器的教程
2015/05/05 Python
Python实现快速排序和插入排序算法及自定义排序的示例
2016/02/16 Python
Python元组操作实例分析【创建、赋值、更新、删除等】
2017/07/24 Python
Python模拟自动存取款机的查询、存取款、修改密码等操作
2018/09/02 Python
Python对ElasticSearch获取数据及操作
2019/04/24 Python
Python微信操控itchat的方法
2019/05/31 Python
python将logging模块封装成单独模块并实现动态切换Level方式
2020/05/12 Python
css3使网页、图片变成灰色兼容大多数浏览器
2014/07/02 HTML / CSS
html5 Canvas实现图片旋转的示例
2018/01/15 HTML / CSS
英国领先的亚洲旅游专家:Wendy Wu Tours
2018/01/21 全球购物
美国棒球装备和用品商店:Baseball Savings
2018/06/09 全球购物
通信工程专业毕业生推荐信
2013/12/25 职场文书
五一家具促销方案
2014/01/10 职场文书
我与祖国共奋进演讲稿
2014/09/13 职场文书
保研专家推荐信范文
2015/03/25 职场文书
公司捐书倡议书
2015/04/27 职场文书
社区法制宣传月活动总结
2015/05/07 职场文书
CocosCreator ScrollView优化系列之分帧加载
2021/04/14 Python
nginx内存池源码解析
2021/11/20 Servers
【海涛教你打dota】体验一超神发条:咱是抢盾专业户
2022/04/01 DOTA