Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f9a9abf

Browse files
committed
completed 写一个广播器
1 parent 2e656c3 commit f9a9abf

File tree

4 files changed

+183
-1
lines changed

4 files changed

+183
-1
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
写一个广播器
2+
====
3+
4+
本节,我们将写一个广播器。下图展示了广播一个 DatagramPacket 在每个日志实体里面的方法
5+
6+
![](../images/Figure 13.2 Log entries sent with DatagramPackets.jpg)
7+
8+
1. 日志文件
9+
2. 日志文件中的日志实体
10+
3. 一个 DatagramPacket 保持一个单独的日志实体
11+
12+
Figure 13.2 Log entries sent with DatagramPackets
13+
14+
图13.3表示一个 LogEventBroadcaster 的 ChannelPipeline 的高级视图,说明了 LogEvent 是如何流转的。
15+
16+
![](../images/Figure 13.3 LogEventBroadcaster-ChannelPipeline and LogEvent flow.jpg)
17+
18+
Figure 13.3 LogEventBroadcaster: ChannelPipeline and LogEvent flow
19+
20+
正如我们所看到的,所有的数据传输都封装在 LogEvent 消息里。LogEventBroadcaster 写这些通过在本地端的管道,发送它们通过ChannelPipeline 转换(编码)为一个定制的 ChannelHandler 的DatagramPacket 信息。最后,他们通过 UDP 广播并被远程接收。
21+
22+
*编码器和解码器*
23+
24+
*编码器和解码器将消息从一种格式转换为另一种,深度探讨在第7章中进行。我们探索 Netty 提供的基础类来简化和实现自定义 ChannelHandler 如 LogEventEncoder 在这个应用程序中。*
25+
26+
下面展示了 编码器的实现
27+
28+
Listing 13.2 LogEventEncoder
29+
30+
public class LogEventEncoder extends MessageToMessageEncoder<LogEvent> {
31+
private final InetSocketAddress remoteAddress;
32+
33+
public LogEventEncoder(InetSocketAddress remoteAddress) { //1
34+
this.remoteAddress = remoteAddress;
35+
}
36+
37+
@Override
38+
protected void encode(ChannelHandlerContext channelHandlerContext, LogEvent logEvent, List<Object> out) throws Exception {
39+
byte[] file = logEvent.getLogfile().getBytes(CharsetUtil.UTF_8); //2
40+
byte[] msg = logEvent.getMsg().getBytes(CharsetUtil.UTF_8);
41+
ByteBuf buf = channelHandlerContext.alloc().buffer(file.length + msg.length + 1);
42+
buf.writeBytes(file);
43+
buf.writeByte(LogEvent.SEPARATOR); //3
44+
buf.writeBytes(msg); //4
45+
out.add(new DatagramPacket(buf, remoteAddress)); //5
46+
}
47+
}
48+
49+
1. LogEventEncoder 创建了 DatagramPacket 消息类发送到指定的
50+
InetSocketAddress
51+
2. 写文件名到 ByteBuf
52+
3. 添加一个 SEPARATOR
53+
4. 写一个日志消息到 ByteBuf
54+
5. 添加新的 DatagramPacket 到出站消息
55+
56+
*为什么使用 MessageToMessageEncoder?*
57+
58+
*当然我们可以编写自己的自定义 ChannelOutboundHandler 来转换 LogEvent 对象到 DatagramPackets。但是继承自MessageToMessageEncoder 为我们简化和做了大部分的工作。*
59+
60+
为了实现 LogEventEncoder,我们只需要定义服务器的运行时配置,我们称之为"bootstrapping(引导)"。这包括设置各种 ChannelOption 并安装需要的 ChannelHandler 到 ChannelPipeline 中。完成的
61+
LogEventBroadcaster 类,如清单13.3所示。
62+
63+
Listing 13.3 LogEventBroadcaster
64+
65+
public class LogEventBroadcaster {
66+
private final Bootstrap bootstrap;
67+
private final File file;
68+
private final EventLoopGroup group;
69+
70+
public LogEventBroadcaster(InetSocketAddress address, File file) {
71+
group = new NioEventLoopGroup();
72+
bootstrap = new Bootstrap();
73+
bootstrap.group(group)
74+
.channel(NioDatagramChannel.class)
75+
.option(ChannelOption.SO_BROADCAST, true)
76+
.handler(new LogEventEncoder(address)); //1
77+
78+
this.file = file;
79+
}
80+
81+
public void run() throws IOException {
82+
Channel ch = bootstrap.bind(0).syncUninterruptibly().channel(); //2
83+
System.out.println("LogEventBroadcaster running");
84+
long pointer = 0;
85+
for (;;) {
86+
long len = file.length();
87+
if (len < pointer) {
88+
// file was reset
89+
pointer = len; //3
90+
} else if (len > pointer) {
91+
// Content was added
92+
RandomAccessFile raf = new RandomAccessFile(file, "r");
93+
raf.seek(pointer); //4
94+
String line;
95+
while ((line = raf.readLine()) != null) {
96+
ch.writeAndFlush(new LogEvent(null, -1, file.getAbsolutePath(), line)); //5
97+
}
98+
pointer = raf.getFilePointer(); //6
99+
raf.close();
100+
}
101+
try {
102+
Thread.sleep(1000); //7
103+
} catch (InterruptedException e) {
104+
Thread.interrupted();
105+
break;
106+
}
107+
}
108+
}
109+
110+
public void stop() {
111+
group.shutdownGracefully();
112+
}
113+
114+
public static void main(String[] args) throws Exception {
115+
if (args.length != 2) {
116+
throw new IllegalArgumentException();
117+
}
118+
119+
LogEventBroadcaster broadcaster = new LogEventBroadcaster(new InetSocketAddress("255.255.255.255",
120+
Integer.parseInt(args[0])), new File(args[1])); //8
121+
try {
122+
broadcaster.run();
123+
} finally {
124+
broadcaster.stop();
125+
}
126+
}
127+
}
128+
129+
1. 引导 NioDatagramChannel 。为了使用广播,我们设置 SO_BROADCAST 的 socket 选项
130+
2. 绑定管道。注意当使用 Datagram Channel 时,是没有连接的
131+
3. 如果需要,可以设置文件的指针指向文件的最后字节
132+
4. 设置当前文件的指针,这样不会把旧的发出去
133+
5. 写一个 LogEvent 到管道用于保存文件名和文件实体。(我们期望每个日志实体是一行长度)
134+
6. 存储当前文件的位置,这样,我们可以稍后继续
135+
7. 睡 1 秒。如果其他中断退出循环就重新启动它。
136+
8. 构造一个新的实例 LogEventBroadcaster 并启动它
137+
138+
这就是程序的完整的第一部分。可以使用 "netcat" 程序查看程序的结果。在 UNIX/Linux 系统,可以使用 "nc", 在 Windows 环境下,可以在 <http://nmap.org/ncat>找到
139+
140+
Netcat 是完美的第一个测试我们的应用程序;它只是监听指定的端口上接收并打印所有数据到标准输出。将其设置为在端口 9999 上监听 UDP 数据如下:
141+
142+
$ nc -l -u 9999
143+
144+
现在我们需要启动 LogEventBroadcaster。清单13.4显示了如何使用 mvn 编译和运行广播器。pom的配置。pom.xml 配置指向一个文件`/var/log/syslog`(假设是UNIX / Linux环境)和端口设置为 9999。文件中的条目将通过 UDP 广播到端口,在你开始 netcat 后打印到控制台。
145+
146+
Listing 13.4 Compile and start the LogEventBroadcaster
147+
148+
$ mvn clean package exec:exec -Pchapter13-LogEventBroadcaster
149+
[INFO] Scanning for projects...
150+
[INFO]
151+
[INFO] --------------------------------------------------------------------
152+
[INFO] Building netty-in-action 0.1-SNAPSHOT
153+
[INFO] --------------------------------------------------------------------
154+
...
155+
...
156+
[INFO]
157+
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ netty-in-action ---
158+
[INFO] Building jar: /Users/norman/Documents/workspace-intellij/netty-in-actionprivate/
159+
target/netty-in-action-0.1-SNAPSHOT.jar
160+
[INFO]
161+
[INFO] --- exec-maven-plugin:1.2.1:exec (default-cli) @ netty-in-action -
162+
LogEventBroadcaster running
163+
164+
当调用 mvn 时,在系统属性中改变文件和端口值,指定你想要的。清单13.5 设置日志文件 到 `/var/log/mail.log` 和端口 8888。
165+
166+
Listing 13.5 Compile and start the LogEventBroadcaster
167+
168+
$ mvn clean package exec:exec -Pchapter13-LogEventBroadcaster /
169+
-Dlogfile=/var/log/mail.log -Dport=8888 -....
170+
....
171+
[INFO]
172+
[INFO] --- exec-maven-plugin:1.2.1:exec (default-cli) @ netty-in-action -
173+
LogEventBroadcaster running
174+
175+
当看到 "LogEventBroadcaster running" 说明程序运行成功了。
176+
177+
netcat 只用于测试,但不适合生产环境中使用。
178+
179+
180+
181+

‎SUMMARY.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ This is the summary of my book.
8585
* [UDP 基础](NETTY BY EXAMPLE/UDP Basics.md)
8686
* [UDP 广播](NETTY BY EXAMPLE/UDP Broadcast.md)
8787
* [UDP 示例](NETTY BY EXAMPLE/The UDP Sample Application.md)
88-
* [EventLog 的 POJO](NETTY BY EXAMPLE/EventLog POJOs.md)
88+
* [EventLog 的 POJO](NETTY BY EXAMPLE/EventLog POJOs.md)
89+
* [写一个广播器](NETTY BY EXAMPLE/Writing the broadcaster.md)
8990
* 高级主题
9091
* [实现自定义编解码器](ADVANCED TOPICS/Implement a custom codec.md)
9192
* [EventLoop 和线程模型](ADVANCED TOPICS/EventLoop and thread model.md)
43.3 KB
Loading[フレーム]
21 KB
Loading[フレーム]

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /