client向网段所有主机广播一个请求,server接受到请求并返回一个Quote(字符串)给客户端
QuoteOfTheMomentClient.java
package org.jboss.netty.example.qotm;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.socket.DatagramChannel;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.util.CharsetUtil;
/**
* A UDP broadcast client that asks for a quote of the moment (QOTM) to
* {@link QuoteOfTheMomentServer}.
*
*/
public class QuoteOfTheMomentClient {
private final int port;
public QuoteOfTheMomentClient(int port) {
this.port = port;
}
public void run() {
//UDP用的是DatagramChannelFactory
DatagramChannelFactory f =
new NioDatagramChannelFactory(Executors.newCachedThreadPool());
//UDP用的是ConnectionlessBootstrap
ConnectionlessBootstrap b = new ConnectionlessBootstrap(f);
// Configure the pipeline factory.
b.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new StringEncoder(CharsetUtil.ISO_8859_1),
new StringDecoder(CharsetUtil.ISO_8859_1),
new QuoteOfTheMomentClientHandler());
}
});
// Enable broadcast 设置UDP广播,发送给同一网段的所有主机
b.setOption("broadcast", "true");
//UDP传输对字节有限制,设置传输字节大小
// Allow packets as large as up to 1024 bytes (default is 768).
// You could increase or decrease this value to avoid truncated packets
// or to improve memory footprint respectively.
//
// Please also note that a large UDP packet might be truncated or
// dropped by your router no matter how you configured this option.
// In UDP, a packet is truncated or dropped if it is larger than a
// certain size, depending on router configuration. IPv4 routers
// truncate and IPv6 routers drop a large packet. That's why it is
// safe to send small packets in UDP.
b.setOption(
"receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(1024));
//DatagramChannel
DatagramChannel c = (DatagramChannel) b.bind(new InetSocketAddress(0));
// Broadcast the QOTM request to port . 广播地址
c.write("I want a QOTM", new InetSocketAddress("255.255.255.255", port));
// QuoteOfTheMomentClientHandler will close the DatagramChannel when a
// response is received. If the channel is not closed within 5 seconds,
// print an error message and quit.
if (!c.getCloseFuture().awaitUninterruptibly(5000)) {
System.err.println("QOTM request timed out.");
c.close().awaitUninterruptibly();
}
f.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
// int port;
// if (args.length > 0) {
// port = Integer.parseInt(args[0]);
// } else {
// port = 8080;
// }
int port = 3333;
new QuoteOfTheMomentClient(port).run();
}
}
QuoteOfTheMomentClientHandler.java
package org.jboss.netty.example.qotm;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
String msg = (String) e.getMessage();
if (msg.startsWith("QOTM: ")) {
System.out.println("Quote of the Moment: " + msg.substring(6) + " from " + e.getRemoteAddress());
e.getChannel().close();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
e.getCause().printStackTrace();
e.getChannel().close();
}
}
QuoteOfTheMomentServer.java
package org.jboss.netty.example.qotm;
import java.net.InetSocketAddress;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.util.CharsetUtil;
/**
* A UDP server that responds to the QOTM (quote of the moment) request to a
* {@link QuoteOfTheMomentClient}.
*
*/
public class QuoteOfTheMomentServer {
private final int port;
public QuoteOfTheMomentServer(int port) {
this.port = port;
}
public void run() {
DatagramChannelFactory f = new NioDatagramChannelFactory();
ConnectionlessBootstrap b = new ConnectionlessBootstrap(f);
// Configure the pipeline factory.
b.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new StringEncoder(CharsetUtil.ISO_8859_1),
new StringDecoder(CharsetUtil.ISO_8859_1),
new QuoteOfTheMomentServerHandler());
}
});
// Enable broadcast
b.setOption("broadcast", "false");
// Allow packets as large as up to 1024 bytes (default is 768).
// You could increase or decrease this value to avoid truncated packets
// or to improve memory footprint respectively.
//
// Please also note that a large UDP packet might be truncated or
// dropped by your router no matter how you configured this option.
// In UDP, a packet is truncated or dropped if it is larger than a
// certain size, depending on router configuration. IPv4 routers
// truncate and IPv6 routers drop a large packet. That's why it is
// safe to send small packets in UDP.
b.setOption(
"receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(1024));
// Bind to the port and start the service.
b.bind(new InetSocketAddress(port));
}
public static void main(String[] args) throws Exception {
// int port;
// if (args.length > 0) {
// port = Integer.parseInt(args[0]);
// } else {
// port = 8080;
// }
int port = 3333;
new QuoteOfTheMomentServer(port).run();
}
}
QuoteOfTheMomentServerHandler.java
package org.jboss.netty.example.qotm;
import java.util.Random;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler {
private static final Random random = new Random();
// Quotes from Mohandas K. Gandhi:
private static final String[] quotes = {
"Where there is love there is life.",
"First they ignore you, then they laugh at you, then they fight you, then you win.",
"Be the change you want to see in the world.",
"The weak can never forgive. Forgiveness is the attribute of the strong.",
};
private static String nextQuote() {
int quoteId;
synchronized (random) {
quoteId = random.nextInt(quotes.length);
}
return quotes[quoteId];
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
String msg = (String) e.getMessage();
System.out.println(e.getRemoteAddress() + " request: " + msg);
if ("I want a QOTM".equals(msg)) {
e.getChannel().write("QOTM: " + nextQuote(), e.getRemoteAddress());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
e.getCause().printStackTrace();
// We don't close the channel because we can keep serving requests.
}
}
测试结果:
client
Quote of the Moment: The weak can never forgive. Forgiveness is the attribute of the strong. from /192.168.30.13:3333
server
/192.168.30.13:63738 request: I want a QOTM
如果网段还有其他主机绑定端口3333,也可以收到client的请求,上述例子中client只能接受一个server的响应