Node.js 网络通信(二)02-构建UDP服务——UDP简介 & UDP三种传播方式-单播、广播、组播 & UDP一对多通信场景 & dgram模块用于构建UDP服务之Socket方法和事件
User Datagram Protocol,简称 UDP ,又称用户数据报协议和 TCP 一样,位于网络传输层用于处理数据包UDP 最大的特点是无连接UDP 传输速度快UDP 数据传输不可靠不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的可靠性由应用层负责支持一对一通信,也支持一对多通信许多关键的互联网应用程序使用 UDP如 DNS 域
Node.js 网络通信(二)02-构建UDP服务——UDP简介 & UDP三种传播方式-单播、广播、组播 & UDP一对多通信场景 & dgram模块用于构建UDP服务之Socket方法和事件
第3章 构建 UDP 服务
内容安排:
- UDP 介绍
- Node 中的核心模块 dgram
- 使用 Node 实现 UDP 单播
- 使用 Node 实现 UDP 广播
- 使用 Node 实现 UDP 组播
UDP 简介
- User Datagram Protocol,简称 UDP ,又称用户数据报协议
- 和 TCP 一样,位于网络传输层用于处理数据包
- UDP 最大的特点是无连接
- UDP 传输速度快
- UDP 数据传输不可靠
- 不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的
- 可靠性由应用层负责
- 支持一对一通信,也支持一对多通信
- 许多关键的互联网应用程序使用 UDP
- 如 DNS 域名系统服务、TFTP 简单文件传输协议、DHCP 动态主机设置协议 等
- UDP 适用于对速度要求比较高,对数据质量要求不严谨的应用
- 例如流媒体、实时多人游戏、实时音视频
TCP 和 UDP
TCP和UDP: 都是数据传输方式的协议.比如说我要给你钱, 我是以手把手的方式拿给你呢还是以快递的方式寄给你呢.
UDP | TCP | |
---|---|---|
连接 | 无连接 | 面向连接 |
速度 | 无需建立连接,速度较快 | 需要建立连接,速度较慢 |
目的主机 | 一对一,一对多 | 仅能一对一 |
带宽 | UDP 报头较短,消耗带宽更少 | 消耗更多的带宽 |
消息边界 | 有 | 无 |
可靠性 | 低 | 高 |
顺序 | 无序 | 有序 |
注:事实上,UDP协议的这种乱序性基本上很少出现,通常只会在网络非常拥挤的情况下才有可能发生。
什么时候用 TCP,什么时候用 UDP?
- 对速度要求比较高的时候使用UDP,例如视频聊天, QQ聊天
- 对数据安全要求比较高的时候使用TCP,例如数据传输,文件下载
- 假如对于视频聊天来说,如果画质优先那就选用TCP, 如果流畅度优先那就选用UDP
UDP 的三种传播方式
1、UDP 单播
- 单播是目的地址为单一目标的一种传播方式
- 地址范围:
0.0.0.0 ~ 223.255.255.255
2、UDP 广播
- 目的地址为网络中的所有设备
- 地址范围分为两种
- 受限广播:它不被路由转发,IP 地址的网络字段和主机字段全为1就是地址
255.255.255.255
- 直接广播:会被路由转发,IP地址的网络字段定义这个网络,主机字段通常全为1,如
192.168.10.255
- 受限广播:它不被路由转发,IP 地址的网络字段和主机字段全为1就是地址
3、UDP 组播
- 多播(Multicast)也叫组播,把信息传递给一组目的地地址
- 地址范围:
224.0.0.0 ~ 239.255.255.255
224.0.0.0 ~ 224.0.0.255
为永久组地址,224.0.0.0.0
保留不分配,其它供路由协议使用224.0.1.0 ~ 224.0.1.255
为公用组播地址,可以用于 Internet224.0.2.0 ~ 238.255.255.255
为用户可用的组播地址(临时组),全网范围有效,使用需要申请239.0.0.0 ~ 239.255.255.255
为本地管理组播地址,仅在特定本地范围有效
UDP 一对多通信场景
单播传输(Unicast):在发送者和每一接收者之间实现点对点网络连接。如果一台发送者同时给多个的接收者传输相同的数据,也必须相应的复制多份的相同数据包。如果有大量主机希望获得数据包的同一份拷贝时,将导致发送者负担沉重、延迟长、网络拥塞;为保证一定的服务质量需增加硬件和带宽。
广播(Broadcast):是指在IP子网内广播数据包,所有在子网内部的主机都将收到这些数据包。广播意味着网络向子网每一个主机都投递一份数据包,不论这些主机是否乐于接收该数据包。所以广播的使用范围非常小,只在本地子网内有效,通过路由器和网络设备控制广播传输。在网络中的应用较多,如客户机通过DHCP自动获得IP地址的过程就是通过广播来实现的。但是与单播和多播相比,广播几乎占用了子网内网络的所有带宽
组播:组播解决了单播和广播方式效率低的问题。当网络中的某些用户需求特定信息时,组播源(即组播信息发送者)仅发送一次信息,组播路由器借助组播路由协议为组播数据包建立树型路由,被传递的信息在尽可能远的分叉路口才开始复制和分发。网上视频会议、网上视频点播特别适合采用多播方式。
1、单播面对 “一对多”
- 在单播通信中每一个数据包都有确切的目的IP地址
- 对于同一份数据,如果存在多个接收者,Server 需发送与接收者数目相同的单播数据包
- 当接收者成百上千时,将极大的加重 Server 的负担
2、广播面对 “一对多”
- 广播数据包被限制在局域网中
- 一旦有设备发送广播数据则广播域内所有设备都收到这个数据包,并且不得不消耗资源去处理,大量的广播数据包将消耗网络的带宽及设备资源
- 在 IPv6 中,广播的报文传输方式被取消
3、组播面对 “一对多”
- 组播非常适合一对多的模型,只有加入到特定组播组的成员,才会接收到组播数据。当存在多个组播组成员时,源无需发送多个数据拷贝,仅需发送一份即可,组播网络设备会根据实际需要转发或拷贝组播数据
- 数据流只发送给加入该组播组的接收者(组成员),而不需要该数据的设备不会收到该组播流量
- 相同的组播报文,在一段链路上仅有一份数据,大大提高了网络资源的利用率
Node 中的 dgram 模块
Node 为我们提供了 dgram 模块用于构建 UDP 服务。
使用该模块创建 UDP 套接字非常简单,UDP 套接字一旦创建,既可以作为客户端发送数据,也可以作为服务器接收数据。
const dgram = require('dgram')
const socket = dgram.createSocket('udp4')
Socket 方法
API | 说明 |
---|---|
bind() | 绑定端口和主机 |
address() | 返回 Socket 地址对象 |
close() | 关闭 Socket 并停止监听 |
send() | 发送消息 |
addMembership() | 添加组播成员 |
dropMembership() | 删除组播成员 |
setBroadcast() | 设置是否启动广播 |
setTTL() | 设置数据报生存时间 |
setMulticastTTL() | 设置组播数据报生存时间 |
Socket 事件
API | 说明 |
---|---|
listening | 监听成功时触发,仅触发一次 |
message | 收到消息时触发 |
error | 发生错误时触发 |
close | 关闭 Socket 时触发 |
使用 Node 实现 UDP 单播
服务端
const dgram = require('dgram')
const server = dgram.createSocket('udp4')
server.on('listening', () => {
const address = server.address()
console.log(`server running ${address.address}:${address.port}`)
})
server.on('message', (msg, remoteInfo) => {
console.log(`server got ${msg} from ${remoteInfo.address}:${remoteInfo.port}`)
server.send('world', remoteInfo.port, remoteInfo.address)
})
server.on('error', err => {
console.log('server error', err)
})
server.bind(3000)
客户端
const dgram = require('dgram')
const client = dgram.createSocket('udp4')
// client.send('hello', 3000, 'localhost')
client.on('listening', () => {
const address = client.address()
console.log(`client running ${address.address}:${address.port}`)
client.send('hello', 3000, 'localhost')
})
client.on('message', (msg, remoteInfo) => {
console.log(`client got ${msg} from ${remoteInfo.address}:${remoteInfo.port}`)
})
client.on('error', err => {
console.log('client error', err)
})
client.bind(8000)
使用 Node 实现 UDP 广播
服务端
const dgram = require('dgram')
const server = dgram.createSocket('udp4')
server.on('listening', () => {
const address = server.address()
console.log(`server running ${address.address}:${address.port}`)
server.setBroadcast(true) // 开启广播模式
server.send('hello', 8000, '255.255.255.255')
// 每隔2秒发送一条广播消息
setInterval(function () {
// 直接地址 192.168.10.255
// 受限地址 255.255.255.255
server.send('hello', 8000, '192.168.10.255')
// server.send('hello', 8000, '255.255.255.255')
}, 2000)
})
server.on('message', (msg, remoteInfo) => {
console.log(`server got ${msg} from ${remoteInfo.address}:${remoteInfo.port}`)
server.send('world', remoteInfo.port, remoteInfo.address)
})
server.on('error', err => {
console.log('server error', err)
})
server.bind(3000)
客户端
const dgram = require('dgram')
const client = dgram.createSocket('udp4')
client.on('message', (msg, remoteInfo) => {
console.log(`client got ${msg} from ${remoteInfo.address}:${remoteInfo.port}`)
})
client.on('error', err => {
console.log('client error', err)
})
client.bind(8000)
使用 Node 实现 UDP 组播
服务端
const dgram = require('dgram')
const server = dgram.createSocket('udp4')
server.on('listening', () => {
const address = server.address()
setInterval(function () {
server.send('hello', 8000, '224.0.1.100')
}, 2000)
})
server.on('message', (msg, remoteInfo) => {
console.log(`server got ${msg} from ${remoteInfo.address}:${remoteInfo.port}`)
server.send('world', remoteInfo.port, remoteInfo.address)
})
server.on('error', err => {
console.log('server error', err)
})
server.bind(3000)
客户端
const dgram = require('dgram')
const client = dgram.createSocket('udp4')
client.on('listening', () => {
const address = client.address()
console.log(`client running ${address.address}:${address.port}`)
client.addMembership('224.0.1.100')
})
client.on('message', (msg, remoteInfo) => {
console.log(`client got ${msg} from ${remoteInfo.address}:${remoteInfo.port}`)
})
client.on('error', err => {
console.log('client error', err)
})
client.bind(8000)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)