Is the string based server, below, functionally equivalent to its datagram server brethren?
The only notable difference I see, and the only difference I'm trying to achieve, is to go from NioDatagramChannel to nioServerSocketChannel. There are some minor differences between the handlers, but do both handlers respond to "QOTM" with nextQuote()?
For brevity, and sanity, I cannot include the client. I'm unfamiliar with netty, and there's simply not much 4.x documentation on this topic I can find. Netty in Action does say:
7.2.4 MessageToMessageDecoder – Decode POJO’s on the fly If you want to decode a message to another type of message MessageToMessageDecoder is the way to go. It allows an easy way to do so. The semantic is quite the same as for all the other decoders we explained before.
But for simplicity I'm just trying to utilize String en/de-coders for the time being. Am I using them correctly in the server?
see also:
http://seeallhearall.blogspot.ca/2012/05/netty-tutorial-part-1-introduction-to.html
datagram server:
package net.bounceme.dur.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.util.logging.Logger;
import net.bounceme.dur.netty.datagram.DatagramServerInitializer;
public final class DatagramServer {
private static final Logger log = Logger.getLogger(DatagramServer.class.getName());
public void start() throws InterruptedException {
MyProps p = new MyProps();
int port = p.getServerPort();
pingPong(port);
}
private void pingPong(int port) throws InterruptedException {
log.fine("which handler?");
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new DatagramServerInitializer());
b.bind(port).sync().channel().closeFuture().await();
} finally {
group.shutdownGracefully();
}
}
}
string server:
package net.bounceme.dur.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import java.util.logging.Logger;
import net.bounceme.dur.netty.string.StringServerInitializer;
public final class StringServer {
private static final Logger log = Logger.getLogger(StringServer.class.getName());
public void start() throws InterruptedException {
MyProps p = new MyProps();
int port = p.getServerPort();
pingPong(port);
}
private void pingPong(int port) throws InterruptedException {
log.fine("which handler?");
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new StringServerInitializer());
b.bind(port).sync().channel().closeFuture().await();
} finally {
group.shutdownGracefully();
}
}
}
datagram server handler:
package net.bounceme.dur.netty.datagram;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import java.util.Random;
import java.util.logging.Logger;
public class DatagramServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private static final Logger log = Logger.getLogger(DatagramServerHandler.class.getName());
private static final Random random = new Random();
public DatagramServerHandler() {
log.info("..started..");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
ctx.writeAndFlush(nextQuote());
}
// 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 channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
log.info(packet.toString());
if ("QOTM?".equals(packet.content().toString(CharsetUtil.UTF_8))) {
ctx.write(new DatagramPacket(
Unpooled.copiedBuffer("QOTM: " + nextQuote(), CharsetUtil.UTF_8), packet.sender()));
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.severe(cause.toString());
}
}
datagram server initializer:
package net.bounceme.dur.netty.datagram;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import java.util.logging.Logger;
public class DatagramServerInitializer extends ChannelInitializer<NioDatagramChannel> {
private static final Logger log = Logger.getLogger(DatagramServerInitializer.class.getName());
public DatagramServerInitializer() {
log.info("..initializing..");
}
@Override
protected void initChannel(NioDatagramChannel c) throws Exception {
log.info("..adding to pipeline..");
ChannelPipeline pipeline = c.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new DatagramServerHandler());
}
}
string server handler:
package net.bounceme.dur.netty.string;
import net.bounceme.dur.netty.datagram.DatagramServerHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.Random;
import java.util.logging.Logger;
public class StringServerHandler extends SimpleChannelInboundHandler<String> {
private static final Logger log = Logger.getLogger(DatagramServerHandler.class.getName());
private static final Random random = new Random();
public StringServerHandler() {
log.info("..started..");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
ctx.writeAndFlush(nextQuote());
}
// 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 channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.severe(cause.toString());
}
@Override
protected void channelRead0(ChannelHandlerContext chc, String msg) throws Exception {
System.err.println(msg);
if ("QOTM?".equals(msg)) {
chc.writeAndFlush(nextQuote());
} else {
log.warning(msg); //never executes
}
}
}
string server initializer:
package net.bounceme.dur.netty.string;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.util.logging.Logger;
public class StringServerInitializer extends ChannelInitializer<ServerSocketChannel> {
private static final Logger log = Logger.getLogger(StringServerInitializer.class.getName());
public StringServerInitializer() {
log.info("..initializing..");
}
@Override
protected void initChannel(ServerSocketChannel c) throws Exception {
log.info("..adding to pipeline..");
ChannelPipeline pipeline = c.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringServerHandler());
}
}