【Netty】UDP广播事件
一、前言
前面学习了WebSocket协议,并且通过示例讲解了WebSocket的具体使用,接着学习如何使用无连接的UDP来广播事件。
二、UDP广播事件
2.1 UDP基础
面向连接的TCP协议管理端到端的连接,在连接生命周期中,发送的消息会有序并且可靠地进行传输,最后连接有序地终止。然而,在无连接协议(如UDP)中,没有持久连接的概念,每个消息(UDP数据报)都是独立的传输,此外,UDP没有TCP的纠错机制(即每个对等体会确认其接收到的分组,并且发送者会重传未确认的分组)。
UDP的限制比TCP多,但是比TCP快很多,这是因为消除了握手和消息管理的所有开销,UDP非常适合处理或容忍消息丢失的应用。
2.2 UDP广播
迄今为止所有的示例都使用了单播的传输模式,其被定义为将消息发送到由唯一地址标识的单个网络目的地,有连接和无连接的协议都支持这种模式,UDP为多个收件人发送消息提供了额外的传输模式:
· 组播--传输到定义的主机组。
· 广播--传输到网络(或子网)上的所有主机。
本章中的示例将通过发送在同一网络上的所有主机接收的消息来使用UDP广播。
2.3 UDP简单示例
示例将打开一个文件,并通过UDP将每一行广播为指定端口。下图展示了应用的结构图。

2.4 LogEvent POJO
在消息应用中,消息经常以POJO形式展现,LogEvent的POJO如下。
public final class LogEvent {
public static final byte SEPARATOR = (byte) ':';
private final InetSocketAddress source;
private final String logfile;
private final String msg;
private final long received;
public LogEvent(String logfile, String msg) {
this(null, -1, logfile, msg);
}
public LogEvent(InetSocketAddress source, long received,
String logfile, String msg) {
this.source = source;
this.logfile = logfile;
this.msg = msg;
this.received = received;
}
public InetSocketAddress getSource() {
return source;
}
public String getLogfile() {
return logfile;
}
public String getMsg() {
return msg;
}
public long getReceivedTimestamp() {
return received;
}
}
2.5 编写broadcaster
Netty提供了许多类来支持UDP应用程序,如Netty的DatagramPacket是DatagramChannel实现与远程对等体进行通信的简单消息容器,我们需要一个编码器将EventLog消息转换为DatagramPackets,可以扩展Netty的MessageToMessageEncoder,LogEventEncoder的代码如下。
public class LogEventEncoder extends MessageToMessageEncoder<LogEvent> {
private final InetSocketAddress remoteAddress;
public LogEventEncoder(InetSocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
@Override
protected void encode(ChannelHandlerContext channelHandlerContext,
LogEvent logEvent, List<Object> out) throws Exception {
byte[] file = logEvent.getLogfile().getBytes(CharsetUtil.UTF_8);
byte[] msg = logEvent.getMsg().getBytes(CharsetUtil.UTF_8);
ByteBuf buf = channelHandlerContext.alloc()
.buffer(file.length + msg.length + 1);
buf.writeBytes(file);
buf.writeByte(LogEvent.SEPARATOR);
buf.writeBytes(msg);
out.add(new DatagramPacket(buf, remoteAddress));
}
}
完成编码器后,即可以开始启动服务端,其中服务端LogEventBroadcaster的代码如下。
public class LogEventBroadcaster {
private final Bootstrap bootstrap;
private final File file;
private final EventLoopGroup group;
public LogEventBroadcaster(InetSocketAddress address, File file) {
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new LogEventEncoder(address));
this.file = file;
}
public void run() throws IOException {
Channel ch = bootstrap.bind(0).syncUninterruptibly().channel();
System.out.println("LogEventBroadcaster running");
long pointer = 0;
for (;;) {
long len = file.length();
if (len < pointer) {
// file was reset
pointer = len;
} else if (len > pointer) {
// Content was added
RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(pointer);
String line;
while ((line = raf.readLine()) != null) {
ch.writeAndFlush(new LogEvent(null, -1, file.getAbsolutePath(), line));
}
pointer = raf.getFilePointer();
raf.close();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
}
}
public void stop() {
group.shutdownGracefully();
}
public static void main(String[] args) throws Exception {
if (args.length != 2) {
throw new IllegalArgumentException();
}
LogEventBroadcaster broadcaster = new LogEventBroadcaster(new InetSocketAddress("255.255.255.255",
Integer.parseInt(args[0])), new File(args[1]));
try {
broadcaster.run();
} finally {
broadcaster.stop();
}
}
}
2.6 编写monitor
在应用中
· 接收由LogEventBroadcaster广播的UDP DatagramPackets。
· 将其解码为LogEvent。
· 将LogEvent写入输出流System.out。
下图展示LogEvent的流动。

LogEventDecoder负责将传入的DatagramPackets解码为LogEvent消息,其代码如下。
public class LogEventDecoder extends MessageToMessageDecoder<DatagramPacket> {
@Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket datagramPacket, List<Object> out) throws Exception {
ByteBuf data = datagramPacket.content();
int i = data.indexOf(0, data.readableBytes(), LogEvent.SEPARATOR);
String filename = data.slice(0, i).toString(CharsetUtil.UTF_8);
String logMsg = data.slice(i + 1, data.readableBytes()).toString(CharsetUtil.UTF_8);
LogEvent event = new LogEvent(datagramPacket.recipient(), System.currentTimeMillis(),
filename,logMsg);
out.add(event);
}
}
而LogEventHandler用于处理LogEvent,其代码如下。
public class LogEventHandler extends SimpleChannelInboundHandler<LogEvent> {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelRead0(ChannelHandlerContext channelHandlerContext, LogEvent event) throws Exception {
StringBuilder builder = new StringBuilder();
builder.append(event.getReceivedTimestamp());
builder.append(" [");
builder.append(event.getSource().toString());
builder.append("] [");
builder.append(event.getLogfile());
builder.append("] : ");
builder.append(event.getMsg());
System.out.println(builder.toString());
}
}
LogEventMonitor用于将处理器添加至管道中,其代码如下。
public class LogEventMonitor {
private final Bootstrap bootstrap;
private final EventLoopGroup group;
public LogEventMonitor(InetSocketAddress address) {
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LogEventDecoder());
pipeline.addLast(new LogEventHandler());
}
}).localAddress(address);
}
public Channel bind() {
return bootstrap.bind().syncUninterruptibly().channel();
}
public void stop() {
group.shutdownGracefully();
}
public static void main(String[] args) throws Exception {
if (args.length != 1) {
throw new IllegalArgumentException("Usage: LogEventMonitor <port>");
}
LogEventMonitor monitor = new LogEventMonitor(new InetSocketAddress(Integer.parseInt(args[0])));
try {
Channel channel = monitor.bind();
System.out.println("LogEventMonitor running");
channel.closeFuture().await();
} finally {
monitor.stop();
}
}
}
运行LogEventBroadcaster和LogEventMonitor
三、总结
本篇博文讲解了UDP协议,以及其示例,在实际应用中需要根据不同的应用场景选择不同的协议,谢谢各位园友的观看~
【Netty】UDP广播事件的更多相关文章
- Netty学习摘记 —— UDP广播事件
本文参考 本篇文章是对<Netty In Action>一书第十三章"使用UDP广播事件"的学习摘记,主要内容为广播应用程序的开发 消息POJO 我们将日志信息封装成名 ...
- Netty实战十三之使用UDP广播事件
1.UDP的基础知识 我们将会把重点放在一个无连接协议即用户数据报协议(UDP)上,它通常用在性能至关重要并且能够容忍一定的数据报丢失的情况下. 面向连接的传输(如TCP)管理了两个网络端点之间的连接 ...
- Netty 框架学习 —— UDP 广播
UDP 广播 面向连接的传输(如 TCP)管理两个网络端点之间的连接的建立,在连接的生命周期的有序和可靠的消息传输,以及最后,连接的有序终止.相比之下,类似 UDP 的无连接协议中则没有持久化连接的概 ...
- 利用Docker技术实现UDP广播效果(网络编程python版)
docker的安装见官方文档 我使用的系统为Ubuntu16.04 Ubuntu系统安装docker文档地址:https://docs.docker.com/engine/installation/l ...
- 给Hi3518e的Uboot添加UDP广播收发功能
基于个人兴趣,决定实现一个和方案公司提供的uboot收发广播的功能.记录笔记如下. SDK版本:Hi3518E_V100R001C01SPC081 1. 由于我手头的板子的Phy是RMII模式,因此先 ...
- [蓝牙] 2、蓝牙BLE协议及架构浅析&&基于广播超时待机说广播事件
第一章 BLE基本概念了解 一.蓝牙4.0和BLE区别 蓝牙4.0是一种应用非常广泛.基于2.4G射频的低功耗无线通讯技术.蓝牙低功耗(Bluetooth Low Energy ),人们又常称之为 ...
- NetworkComms V3 之发送UDP广播消息
NetworkComms网络通信框架序言 NetworkComms通信框架,是一款来自英国的c#语言编写的通信框架,历时6年研发,成熟稳定,性能可靠. NetworkComms v3目前只支持基本的U ...
- Android杂谈--HTC等手机接收不到UDP广播报文的解决方案
最近遇到个问题,在android手机上发送UDP报文的时候,HTC等机型(测试用HTC new one)接收不到广播报文,而其他的samsung, huawei, xiaomi, nexus等等均没有 ...
- [C# 网络编程系列]专题七:UDP编程补充——UDP广播程序的实现
转自:http://www.cnblogs.com/zhili/archive/2012/09/03/2666974.html 上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享 ...
随机推荐
- Python isinstance
语法:isinstance(object,type) 作用:来判断一个对象是否是一个已知的类型. 其第一个参数(object)为对象,第二个参数(type)为类型名(int...)或类型名的一个列表( ...
- CSS 预处理器中的循环
本文由 nzbin 翻译,黄利民 校稿.未经许可,禁止转载! 英文出处:css-tricks.com 发表地址:http://web.jobbole.com/91016/ 如果你看过老的科幻电影,你一 ...
- 《Python自然语言处理》第二章-习题解答-练习6
问题描述:在比较词表的讨论中,创建一个对象叫做translate,通过它你可以使用德语和意大利语词汇查找对应的英语词汇.这种方法可能会出现什么问题,你能提出一个办法来避免这个问题吗? 虽然这是一道初级 ...
- shell初步了解
shell的类型 查看用户所用的shell程序,在/etc/passwd 文件中的第七个字段(好像就是最后一个,主要是bash shell) 还有一个默认shell是/bin/sh,它作为默认的系统s ...
- iOS原生地图与高德地图的使用
原生地图 1.什么是LBS LBS: 基于位置的服务 Location Based Service 实际应用:大众点评,陌陌,微信,美团等需要用到地图或定位的App 2.定位方式 1.GPS定位 2. ...
- 从JDBC到hibernate再到mybatis之路
一.传统的JDBC编程 在java开发中,以前都是通过JDBC(Java Data Base Connectivity)与数据库打交道的,至少在ORM(Object Relational Mappin ...
- iOS开发 - 适配Https的野路子
大致写下适配Https时遇到的坑,做完服务器迁移一直通宵到现在,表示无力再多做详解,只放一些常见问题的解决方案吧 问题一.Https请求失败 1. NetManager初始化时可参考如下设置(因为我没 ...
- Unity UI 基础【译】
https://unity3d.com/cn/learn/tutorials/topics/best-practices/fundamentals-unity-ui?playlist=30089 理解 ...
- 使用Asp.Net MVC开发兼职文章系统
我已经开发好了,你拿去用就是了. 以下是README的内容,包含功能要求和开发过程的一些思考: 一.功能 1.学生兼职人员文章(任务.自由编写),审核(通过,退回修改,无效),并按每15天结算一次费用 ...
- extjs4 前台导出grid数据 生成excel,数据量大后台无法接收到数据
最近做的一个web项目使用的是extsj4 框架,需要一个导出excel功能,通过extjs4 自带的导出方法实现.在前台生成excel的代码,form提交传递到后台输出.前台grid数据超过1000 ...