* More comments on examples
* Added JavaDoc for ChannelPipelineCoverage which is somewhat difficult to understand.
This commit is contained in:
parent
5e99787df6
commit
93f76ce594
@ -30,6 +30,31 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Specifies if the same instance of the annotated {@link ChannelHandler} type
|
||||||
|
* can be added to more than one {@link ChannelPipeline}.
|
||||||
|
* <p>
|
||||||
|
* All handler types are expected to specify this annotation. Otherwise you
|
||||||
|
* will be warned in runtime. Only two values are allowed for this annotation:
|
||||||
|
* {@code "all"} and {@code "one"}.
|
||||||
|
* <p>
|
||||||
|
* Please note that this annotation doesn't prevent a handler annotated with
|
||||||
|
* the value {@code "one"} from being added to more than one pipeline. This
|
||||||
|
* annotation is used for documentation purpose only.
|
||||||
|
*
|
||||||
|
* <h3>{@code ChannelPipelineCoverage("all")}</h3>
|
||||||
|
*
|
||||||
|
* {@code "all"} means you can add the same instance of the annotated handler
|
||||||
|
* type to more than one {@link ChannelPipeline}. It means the member
|
||||||
|
* variables of the handler instance is shared among multiple channels and it
|
||||||
|
* is OK to do so.
|
||||||
|
*
|
||||||
|
* <h3>{@code ChannelPipelineCoverage("one")}</h3>
|
||||||
|
*
|
||||||
|
* {@code "one"} means you must create a new instance of the annotated handler
|
||||||
|
* type for each new channel. It means the member variables of the handler
|
||||||
|
* instance can not be shared at all, and violating this contract will lead
|
||||||
|
* the handler to a race condition.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
@ -42,8 +67,19 @@ import java.lang.annotation.Target;
|
|||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface ChannelPipelineCoverage {
|
public @interface ChannelPipelineCoverage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code "all"}
|
||||||
|
*/
|
||||||
public static final String ALL = "all";
|
public static final String ALL = "all";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code "one"}
|
||||||
|
*/
|
||||||
public static final String ONE = "one";
|
public static final String ONE = "one";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of this annotation
|
||||||
|
*/
|
||||||
String value();
|
String value();
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public class DiscardClient {
|
|||||||
firstMessageSize = 256;
|
firstMessageSize = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start client.
|
// Configure the client.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioClientSocketChannelFactory(
|
new NioClientSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -72,6 +72,7 @@ public class DiscardClient {
|
|||||||
bootstrap.setOption("tcpNoDelay", true);
|
bootstrap.setOption("tcpNoDelay", true);
|
||||||
bootstrap.setOption("keepAlive", true);
|
bootstrap.setOption("keepAlive", true);
|
||||||
|
|
||||||
|
// Start the connection attempt.
|
||||||
bootstrap.connect(new InetSocketAddress(host, port));
|
bootstrap.connect(new InetSocketAddress(host, port));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import org.jboss.netty.channel.MessageEvent;
|
|||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Handles a client-side channel.
|
||||||
*
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
@ -106,6 +107,10 @@ public class DiscardClientHandler extends SimpleChannelHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateTraffic(ChannelStateEvent e) {
|
private void generateTraffic(ChannelStateEvent e) {
|
||||||
|
// Keep generating traffic until the channel is unwritable.
|
||||||
|
// A channel becomes unwritable when its internal buffer is full.
|
||||||
|
// If you keep writing messages ignoring this property,
|
||||||
|
// you will end up with an OutOfMemoryError.
|
||||||
Channel channel = e.getChannel();
|
Channel channel = e.getChannel();
|
||||||
while (channel.isWritable()) {
|
while (channel.isWritable()) {
|
||||||
ChannelBuffer m = nextMessage();
|
ChannelBuffer m = nextMessage();
|
||||||
|
@ -40,7 +40,7 @@ import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
|||||||
public class DiscardServer {
|
public class DiscardServer {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// Start server.
|
// Configure the server.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioServerSocketChannelFactory(
|
new NioServerSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -53,6 +53,7 @@ public class DiscardServer {
|
|||||||
bootstrap.setOption("child.tcpNoDelay", true);
|
bootstrap.setOption("child.tcpNoDelay", true);
|
||||||
bootstrap.setOption("child.keepAlive", true);
|
bootstrap.setOption("child.keepAlive", true);
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
bootstrap.bind(new InetSocketAddress(8080));
|
bootstrap.bind(new InetSocketAddress(8080));
|
||||||
|
|
||||||
// Start performance monitor.
|
// Start performance monitor.
|
||||||
|
@ -36,6 +36,7 @@ import org.jboss.netty.channel.MessageEvent;
|
|||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Handles a server-side channel.
|
||||||
*
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
@ -22,12 +22,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.jboss.netty.example.discard;
|
package org.jboss.netty.example.discard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures and prints the current throughput every 3 seconds.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class ThroughputMonitor extends Thread {
|
public class ThroughputMonitor extends Thread {
|
||||||
|
|
||||||
private final DiscardServerHandler handler;
|
private final DiscardServerHandler handler;
|
||||||
|
|
||||||
public ThroughputMonitor(DiscardServerHandler echoHandler) {
|
public ThroughputMonitor(DiscardServerHandler handler) {
|
||||||
this.handler = echoHandler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,6 +29,16 @@ import org.jboss.netty.bootstrap.ClientBootstrap;
|
|||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends one message when a connection is open and echoes back any received
|
||||||
|
* data to the server.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class EchoClient {
|
public class EchoClient {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@ -51,7 +61,7 @@ public class EchoClient {
|
|||||||
firstMessageSize = 256;
|
firstMessageSize = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start client.
|
// Configure the client.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioClientSocketChannelFactory(
|
new NioClientSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -64,6 +74,7 @@ public class EchoClient {
|
|||||||
bootstrap.setOption("tcpNoDelay", true);
|
bootstrap.setOption("tcpNoDelay", true);
|
||||||
bootstrap.setOption("keepAlive", true);
|
bootstrap.setOption("keepAlive", true);
|
||||||
|
|
||||||
|
// Start the connection attempt.
|
||||||
bootstrap.connect(new InetSocketAddress(host, port));
|
bootstrap.connect(new InetSocketAddress(host, port));
|
||||||
|
|
||||||
// Start performance monitor.
|
// Start performance monitor.
|
||||||
|
@ -36,6 +36,15 @@ import org.jboss.netty.channel.ExceptionEvent;
|
|||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles both client-side and server-side handler depending on which
|
||||||
|
* constructor was called.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
@ChannelPipelineCoverage("all")
|
@ChannelPipelineCoverage("all")
|
||||||
public class EchoHandler extends SimpleChannelHandler {
|
public class EchoHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
@ -45,12 +54,18 @@ public class EchoHandler extends SimpleChannelHandler {
|
|||||||
private final ChannelBuffer firstMessage;
|
private final ChannelBuffer firstMessage;
|
||||||
private final AtomicLong transferredBytes = new AtomicLong();
|
private final AtomicLong transferredBytes = new AtomicLong();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a server-side handler.
|
||||||
|
*/
|
||||||
public EchoHandler() {
|
public EchoHandler() {
|
||||||
this(0);
|
firstMessage = ChannelBuffer.EMPTY_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a client-side handler.
|
||||||
|
*/
|
||||||
public EchoHandler(int firstMessageSize) {
|
public EchoHandler(int firstMessageSize) {
|
||||||
if (firstMessageSize < 0) {
|
if (firstMessageSize <= 0) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"firstMessageSize: " + firstMessageSize);
|
"firstMessageSize: " + firstMessageSize);
|
||||||
}
|
}
|
||||||
@ -70,18 +85,23 @@ public class EchoHandler extends SimpleChannelHandler {
|
|||||||
if (e instanceof ChannelStateEvent) {
|
if (e instanceof ChannelStateEvent) {
|
||||||
logger.info(e.toString());
|
logger.info(e.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let SimpleChannelHandler call actual event handler methods below.
|
||||||
super.handleUpstream(ctx, e);
|
super.handleUpstream(ctx, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelConnected(
|
public void channelConnected(
|
||||||
ChannelHandlerContext ctx, ChannelStateEvent e) {
|
ChannelHandlerContext ctx, ChannelStateEvent e) {
|
||||||
|
// Send the first message. Server will not send anything here
|
||||||
|
// because the firstMessage's capacity is 0.
|
||||||
e.getChannel().write(firstMessage);
|
e.getChannel().write(firstMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void messageReceived(
|
public void messageReceived(
|
||||||
ChannelHandlerContext ctx, MessageEvent e) {
|
ChannelHandlerContext ctx, MessageEvent e) {
|
||||||
|
// Send back the received message to the remote peer.
|
||||||
transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
|
transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
|
||||||
e.getChannel().write(e.getMessage());
|
e.getChannel().write(e.getMessage());
|
||||||
}
|
}
|
||||||
@ -89,6 +109,7 @@ public class EchoHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(
|
public void exceptionCaught(
|
||||||
ChannelHandlerContext ctx, ExceptionEvent e) {
|
ChannelHandlerContext ctx, ExceptionEvent e) {
|
||||||
|
// Close the connection when an exception is raised.
|
||||||
logger.log(
|
logger.log(
|
||||||
Level.WARNING,
|
Level.WARNING,
|
||||||
"Unexpected exception from downstream.",
|
"Unexpected exception from downstream.",
|
||||||
|
@ -29,10 +29,19 @@ import org.jboss.netty.bootstrap.ServerBootstrap;
|
|||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Echoes back any received data from a client.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class EchoServer {
|
public class EchoServer {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// Start server.
|
// Configure the server.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioServerSocketChannelFactory(
|
new NioServerSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -45,6 +54,7 @@ public class EchoServer {
|
|||||||
bootstrap.setOption("child.tcpNoDelay", true);
|
bootstrap.setOption("child.tcpNoDelay", true);
|
||||||
bootstrap.setOption("child.keepAlive", true);
|
bootstrap.setOption("child.keepAlive", true);
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
bootstrap.bind(new InetSocketAddress(8080));
|
bootstrap.bind(new InetSocketAddress(8080));
|
||||||
|
|
||||||
// Start performance monitor.
|
// Start performance monitor.
|
||||||
|
@ -22,17 +22,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.jboss.netty.example.echo;
|
package org.jboss.netty.example.echo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures and prints the current throughput every 3 seconds.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class ThroughputMonitor extends Thread {
|
public class ThroughputMonitor extends Thread {
|
||||||
|
|
||||||
private final EchoHandler echoHandler;
|
private final EchoHandler handler;
|
||||||
|
|
||||||
public ThroughputMonitor(EchoHandler echoHandler) {
|
public ThroughputMonitor(EchoHandler handler) {
|
||||||
this.echoHandler = echoHandler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long oldCounter = echoHandler.getTransferredBytes();
|
long oldCounter = handler.getTransferredBytes();
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
@ -42,7 +50,7 @@ public class ThroughputMonitor extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long endTime = System.currentTimeMillis();
|
long endTime = System.currentTimeMillis();
|
||||||
long newCounter = echoHandler.getTransferredBytes();
|
long newCounter = handler.getTransferredBytes();
|
||||||
System.err.format(
|
System.err.format(
|
||||||
"%4.3f MiB/s%n",
|
"%4.3f MiB/s%n",
|
||||||
(newCounter - oldCounter) * 1000 / (endTime - startTime) /
|
(newCounter - oldCounter) * 1000 / (endTime - startTime) /
|
||||||
|
@ -30,28 +30,35 @@ import org.jboss.netty.channel.ChannelHandlerContext;
|
|||||||
import org.jboss.netty.handler.codec.frame.FrameDecoder;
|
import org.jboss.netty.handler.codec.frame.FrameDecoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Decodes the binary representation of a {@link BigInteger} with 32-bit
|
||||||
|
* integer length prefix into a Java {@link BigInteger} instance. For example,
|
||||||
|
* { 0, 0, 0, 1, 42 } will be decoded into new BigInteger("42").
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class BigIntegerDecoder extends FrameDecoder {
|
public class BigIntegerDecoder extends FrameDecoder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object decode(
|
protected Object decode(
|
||||||
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
|
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
|
||||||
|
// Wait until the length prefix is available.
|
||||||
if (buffer.readableBytes() < 4) {
|
if (buffer.readableBytes() < 4) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int dataLength = buffer.getInt(buffer.readerIndex());
|
int dataLength = buffer.getInt(buffer.readerIndex());
|
||||||
|
|
||||||
|
// Wait until the whole data is available.
|
||||||
if (buffer.readableBytes() < dataLength + 4) {
|
if (buffer.readableBytes() < dataLength + 4) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip the length field because we know it already.
|
||||||
buffer.skipBytes(4);
|
buffer.skipBytes(4);
|
||||||
|
|
||||||
|
// Convert the received data into a new BigInteger.
|
||||||
byte[] decoded = new byte[dataLength];
|
byte[] decoded = new byte[dataLength];
|
||||||
buffer.readBytes(decoded);
|
buffer.readBytes(decoded);
|
||||||
|
|
||||||
|
@ -30,6 +30,15 @@ import org.jboss.netty.channel.ChannelFactory;
|
|||||||
import org.jboss.netty.channel.ChannelFuture;
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a sequence of integers to a {@link FactorialServer} to calculate
|
||||||
|
* the factorial of the specified integer.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class FactorialClient {
|
public class FactorialClient {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
@ -39,12 +39,27 @@ import org.jboss.netty.channel.ExceptionEvent;
|
|||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
@ChannelPipelineCoverage("one")
|
/**
|
||||||
|
* Handler for a client-side channel. Please note that this handler's
|
||||||
|
* {@link ChannelPipelineCoverage} annotation value is "one". It means
|
||||||
|
* this handler maintains some stateful information which is specific to
|
||||||
|
* a certain channel. Therefore, an instance of this handler can
|
||||||
|
* cover only one ChannelPipeline and Channel pair. You have to create
|
||||||
|
* a new handler instance whenever you create a new channel and insert
|
||||||
|
* this handler to avoid a race condition.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
@ChannelPipelineCoverage("one") // <-- HERE
|
||||||
public class FactorialClientHandler extends SimpleChannelHandler {
|
public class FactorialClientHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(
|
private static final Logger logger = Logger.getLogger(
|
||||||
FactorialClientHandler.class.getName());
|
FactorialClientHandler.class.getName());
|
||||||
|
|
||||||
|
// Stateful properties
|
||||||
private int i = 1;
|
private int i = 1;
|
||||||
private int receivedMessages = 0;
|
private int receivedMessages = 0;
|
||||||
private final int count;
|
private final int count;
|
||||||
|
@ -28,11 +28,12 @@ import org.jboss.netty.channel.ChannelPipeline;
|
|||||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creates a newly configured {@link ChannelPipeline} for a client-side channel.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class FactorialClientPipelineFactory implements
|
public class FactorialClientPipelineFactory implements
|
||||||
ChannelPipelineFactory {
|
ChannelPipelineFactory {
|
||||||
|
@ -23,11 +23,12 @@
|
|||||||
package org.jboss.netty.example.factorial;
|
package org.jboss.netty.example.factorial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Thrown when there was a protocol violation during communication.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class FactorialProtocolException extends Exception {
|
public class FactorialProtocolException extends Exception {
|
||||||
|
|
||||||
|
@ -29,10 +29,19 @@ import org.jboss.netty.bootstrap.ServerBootstrap;
|
|||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a sequence of integers from a {@link FactorialClient} to calculate
|
||||||
|
* the factorial of the specified integer.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class FactorialServer {
|
public class FactorialServer {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// Start server.
|
// Configure the server.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioServerSocketChannelFactory(
|
new NioServerSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -44,6 +53,7 @@ public class FactorialServer {
|
|||||||
bootstrap.setOption("child.tcpNoDelay", true);
|
bootstrap.setOption("child.tcpNoDelay", true);
|
||||||
bootstrap.setOption("child.keepAlive", true);
|
bootstrap.setOption("child.keepAlive", true);
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
bootstrap.bind(new InetSocketAddress(8080));
|
bootstrap.bind(new InetSocketAddress(8080));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,12 +35,27 @@ import org.jboss.netty.channel.ExceptionEvent;
|
|||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
@ChannelPipelineCoverage("one")
|
/**
|
||||||
|
* Handler for a server-side channel. Please note that this handler's
|
||||||
|
* {@link ChannelPipelineCoverage} annotation value is "one". It means
|
||||||
|
* this handler maintains some stateful information which is specific to
|
||||||
|
* a certain channel. Therefore, an instance of this handler can
|
||||||
|
* cover only one ChannelPipeline and Channel pair. You have to create
|
||||||
|
* a new handler instance whenever you create a new channel and insert
|
||||||
|
* this handler to avoid a race condition.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
|
@ChannelPipelineCoverage("one") // <-- HERE
|
||||||
public class FactorialServerHandler extends SimpleChannelHandler {
|
public class FactorialServerHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(
|
private static final Logger logger = Logger.getLogger(
|
||||||
FactorialServerHandler.class.getName());
|
FactorialServerHandler.class.getName());
|
||||||
|
|
||||||
|
// Stateful properties.
|
||||||
private int lastMultiplier = 1;
|
private int lastMultiplier = 1;
|
||||||
private BigInteger factorial = new BigInteger(new byte[] { 1 });
|
private BigInteger factorial = new BigInteger(new byte[] { 1 });
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ import org.jboss.netty.channel.ChannelPipeline;
|
|||||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creates a newly configured {@link ChannelPipeline} for a server-side channel.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
@ -45,6 +47,8 @@ public class FactorialServerPipelineFactory implements
|
|||||||
pipeline.addLast("encoder", new NumberEncoder());
|
pipeline.addLast("encoder", new NumberEncoder());
|
||||||
|
|
||||||
// and then business logic.
|
// and then business logic.
|
||||||
|
// Please note we create a handler for every new channel
|
||||||
|
// because it has stateful properties.
|
||||||
pipeline.addLast("handler", new FactorialServerHandler());
|
pipeline.addLast("handler", new FactorialServerHandler());
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
|
@ -35,6 +35,9 @@ import org.jboss.netty.channel.ChannelPipelineCoverage;
|
|||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Encodes a {@link Number} into the binary representation with a 32-bit length
|
||||||
|
* prefix. For example, 42 will be encoded to { 0, 0, 0, 1, 42 }.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
|
@ -28,7 +28,16 @@ import java.util.concurrent.Executors;
|
|||||||
import org.jboss.netty.bootstrap.ClientBootstrap;
|
import org.jboss.netty.bootstrap.ClientBootstrap;
|
||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
||||||
|
import org.jboss.netty.example.echo.EchoClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modification of {@link EchoClient} which utilizes Java object serialization.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class ObjectEchoClient {
|
public class ObjectEchoClient {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@ -51,7 +60,7 @@ public class ObjectEchoClient {
|
|||||||
firstMessageSize = 256;
|
firstMessageSize = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start client.
|
// Configure the client.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioClientSocketChannelFactory(
|
new NioClientSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -64,6 +73,7 @@ public class ObjectEchoClient {
|
|||||||
bootstrap.setOption("tcpNoDelay", true);
|
bootstrap.setOption("tcpNoDelay", true);
|
||||||
bootstrap.setOption("keepAlive", true);
|
bootstrap.setOption("keepAlive", true);
|
||||||
|
|
||||||
|
// Start the connection attempt.
|
||||||
bootstrap.connect(new InetSocketAddress(host, port));
|
bootstrap.connect(new InetSocketAddress(host, port));
|
||||||
|
|
||||||
// Start performance monitor.
|
// Start performance monitor.
|
||||||
|
@ -39,6 +39,15 @@ import org.jboss.netty.channel.SimpleChannelHandler;
|
|||||||
import org.jboss.netty.handler.codec.serialization.ObjectDecoder;
|
import org.jboss.netty.handler.codec.serialization.ObjectDecoder;
|
||||||
import org.jboss.netty.handler.codec.serialization.ObjectEncoder;
|
import org.jboss.netty.handler.codec.serialization.ObjectEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles both client-side and server-side handler depending on which
|
||||||
|
* constructor was called.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
@ChannelPipelineCoverage("all")
|
@ChannelPipelineCoverage("all")
|
||||||
public class ObjectEchoHandler extends SimpleChannelHandler {
|
public class ObjectEchoHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
@ -48,12 +57,18 @@ public class ObjectEchoHandler extends SimpleChannelHandler {
|
|||||||
private final List<Integer> firstMessage;
|
private final List<Integer> firstMessage;
|
||||||
private final AtomicLong transferredMessages = new AtomicLong();
|
private final AtomicLong transferredMessages = new AtomicLong();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a server-side handler.
|
||||||
|
*/
|
||||||
public ObjectEchoHandler() {
|
public ObjectEchoHandler() {
|
||||||
this(0);
|
firstMessage = new ArrayList<Integer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a client-side handler.
|
||||||
|
*/
|
||||||
public ObjectEchoHandler(int firstMessageSize) {
|
public ObjectEchoHandler(int firstMessageSize) {
|
||||||
if (firstMessageSize < 0) {
|
if (firstMessageSize <= 0) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"firstMessageSize: " + firstMessageSize);
|
"firstMessageSize: " + firstMessageSize);
|
||||||
}
|
}
|
||||||
@ -80,6 +95,8 @@ public class ObjectEchoHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void channelOpen(ChannelHandlerContext ctx,
|
public void channelOpen(ChannelHandlerContext ctx,
|
||||||
ChannelStateEvent e) throws Exception {
|
ChannelStateEvent e) throws Exception {
|
||||||
|
// Add encoder and decoder as soon as a new channel is created so that
|
||||||
|
// a Java object is serialized and deserialized.
|
||||||
e.getChannel().getPipeline().addFirst("encoder", new ObjectEncoder());
|
e.getChannel().getPipeline().addFirst("encoder", new ObjectEncoder());
|
||||||
e.getChannel().getPipeline().addFirst("decoder", new ObjectDecoder());
|
e.getChannel().getPipeline().addFirst("decoder", new ObjectDecoder());
|
||||||
}
|
}
|
||||||
@ -87,6 +104,7 @@ public class ObjectEchoHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void channelConnected(
|
public void channelConnected(
|
||||||
ChannelHandlerContext ctx, ChannelStateEvent e) {
|
ChannelHandlerContext ctx, ChannelStateEvent e) {
|
||||||
|
// Send the first message if this handler is a client-side handler.
|
||||||
if (!firstMessage.isEmpty()) {
|
if (!firstMessage.isEmpty()) {
|
||||||
e.getChannel().write(firstMessage);
|
e.getChannel().write(firstMessage);
|
||||||
}
|
}
|
||||||
@ -95,6 +113,7 @@ public class ObjectEchoHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void messageReceived(
|
public void messageReceived(
|
||||||
ChannelHandlerContext ctx, MessageEvent e) {
|
ChannelHandlerContext ctx, MessageEvent e) {
|
||||||
|
// Echo back the received object to the client.
|
||||||
transferredMessages.incrementAndGet();
|
transferredMessages.incrementAndGet();
|
||||||
e.getChannel().write(e.getMessage());
|
e.getChannel().write(e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,20 @@ import java.util.concurrent.Executors;
|
|||||||
import org.jboss.netty.bootstrap.ServerBootstrap;
|
import org.jboss.netty.bootstrap.ServerBootstrap;
|
||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||||
|
import org.jboss.netty.example.echo.EchoServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modification of {@link EchoServer} which utilizes Java object serialization.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class ObjectEchoServer {
|
public class ObjectEchoServer {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// Start server.
|
// Configure the server.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioServerSocketChannelFactory(
|
new NioServerSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -45,6 +54,7 @@ public class ObjectEchoServer {
|
|||||||
bootstrap.setOption("child.tcpNoDelay", true);
|
bootstrap.setOption("child.tcpNoDelay", true);
|
||||||
bootstrap.setOption("child.keepAlive", true);
|
bootstrap.setOption("child.keepAlive", true);
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
bootstrap.bind(new InetSocketAddress(8080));
|
bootstrap.bind(new InetSocketAddress(8080));
|
||||||
|
|
||||||
// Start performance monitor.
|
// Start performance monitor.
|
||||||
|
@ -22,17 +22,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.jboss.netty.example.objectecho;
|
package org.jboss.netty.example.objectecho;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures and prints the current throughput every 3 seconds.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class ThroughputMonitor extends Thread {
|
public class ThroughputMonitor extends Thread {
|
||||||
|
|
||||||
private final ObjectEchoHandler echoHandler;
|
private final ObjectEchoHandler handler;
|
||||||
|
|
||||||
public ThroughputMonitor(ObjectEchoHandler echoHandler) {
|
public ThroughputMonitor(ObjectEchoHandler handler) {
|
||||||
this.echoHandler = echoHandler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long oldCounter = echoHandler.getTransferredMessages();
|
long oldCounter = handler.getTransferredMessages();
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
@ -42,7 +50,7 @@ public class ThroughputMonitor extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long endTime = System.currentTimeMillis();
|
long endTime = System.currentTimeMillis();
|
||||||
long newCounter = echoHandler.getTransferredMessages();
|
long newCounter = handler.getTransferredMessages();
|
||||||
System.err.format(
|
System.err.format(
|
||||||
"%4.3f msgs/s%n",
|
"%4.3f msgs/s%n",
|
||||||
(newCounter - oldCounter) * 1000 / (double) (endTime - startTime));
|
(newCounter - oldCounter) * 1000 / (double) (endTime - startTime));
|
||||||
|
@ -32,7 +32,17 @@ import org.jboss.netty.channel.Channel;
|
|||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.ChannelFuture;
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
||||||
|
import org.jboss.netty.example.telnet.TelnetClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple SSL chat client modified from {@link TelnetClient}.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class SecureChatClient {
|
public class SecureChatClient {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@ -48,7 +58,7 @@ public class SecureChatClient {
|
|||||||
String host = args[0];
|
String host = args[0];
|
||||||
int port = Integer.parseInt(args[1]);
|
int port = Integer.parseInt(args[1]);
|
||||||
|
|
||||||
// Start client.
|
// Configure the client.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioClientSocketChannelFactory(
|
new NioClientSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -61,6 +71,7 @@ public class SecureChatClient {
|
|||||||
bootstrap.setOption("tcpNoDelay", true);
|
bootstrap.setOption("tcpNoDelay", true);
|
||||||
bootstrap.setOption("keepAlive", true);
|
bootstrap.setOption("keepAlive", true);
|
||||||
|
|
||||||
|
// Start the connection attempt.
|
||||||
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
|
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
|
||||||
|
|
||||||
// Wait until the connection attempt succeeds or fails.
|
// Wait until the connection attempt succeeds or fails.
|
||||||
@ -86,6 +97,8 @@ public class SecureChatClient {
|
|||||||
lastWriteFuture.awaitUninterruptibly();
|
lastWriteFuture.awaitUninterruptibly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close the connection. Make sure the close operation ends because
|
||||||
|
// all I/O operations are asynchronous in Netty.
|
||||||
channel.close().awaitUninterruptibly();
|
channel.close().awaitUninterruptibly();
|
||||||
|
|
||||||
// We should shut down all thread pools here to exit normally.
|
// We should shut down all thread pools here to exit normally.
|
||||||
|
@ -34,6 +34,14 @@ import org.jboss.netty.channel.MessageEvent;
|
|||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
import org.jboss.netty.handler.ssl.SslHandler;
|
import org.jboss.netty.handler.ssl.SslHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a client-side channel.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
@ChannelPipelineCoverage("all")
|
@ChannelPipelineCoverage("all")
|
||||||
public class SecureChatClientHandler extends SimpleChannelHandler {
|
public class SecureChatClientHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
@ -52,9 +60,11 @@ public class SecureChatClientHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void channelConnected(
|
public void channelConnected(
|
||||||
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
||||||
|
// Get the SslHandler from the pipeline
|
||||||
// Get the SslHandler and begin handshake ASAP.
|
// which were added in SecureChatPipelineFactory.
|
||||||
SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
|
SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
|
||||||
|
|
||||||
|
// Begin handshake.
|
||||||
sslHandler.handshake(e.getChannel());
|
sslHandler.handshake(e.getChannel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,11 +26,13 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A bogus key store which provides all the required information to
|
||||||
|
* create an example SSL connection.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class SecureChatKeyStore {
|
public class SecureChatKeyStore {
|
||||||
private static final short[] DATA = new short[] {
|
private static final short[] DATA = new short[] {
|
||||||
|
@ -36,6 +36,8 @@ import org.jboss.netty.handler.codec.string.StringEncoder;
|
|||||||
import org.jboss.netty.handler.ssl.SslHandler;
|
import org.jboss.netty.handler.ssl.SslHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creates a newly configured {@link ChannelPipeline} for a new channel.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
@ -55,8 +57,11 @@ public class SecureChatPipelineFactory implements
|
|||||||
ChannelPipeline pipeline = pipeline();
|
ChannelPipeline pipeline = pipeline();
|
||||||
|
|
||||||
// Add SSL handler first to encrypt and decrypt everything.
|
// Add SSL handler first to encrypt and decrypt everything.
|
||||||
|
// In this example, we use a bogus certificate in the server side
|
||||||
|
// and accept any invalid certificates in the client side.
|
||||||
// You will need something more complicated to identify both
|
// You will need something more complicated to identify both
|
||||||
// and server in the real world.
|
// and server in the real world.
|
||||||
|
|
||||||
SSLEngine engine;
|
SSLEngine engine;
|
||||||
if (handler instanceof SecureChatClientHandler) {
|
if (handler instanceof SecureChatClientHandler) {
|
||||||
engine = SecureChatSslContextFactory.getClientContext().createSSLEngine();
|
engine = SecureChatSslContextFactory.getClientContext().createSSLEngine();
|
||||||
|
@ -28,11 +28,20 @@ import java.util.concurrent.Executors;
|
|||||||
import org.jboss.netty.bootstrap.ServerBootstrap;
|
import org.jboss.netty.bootstrap.ServerBootstrap;
|
||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||||
|
import org.jboss.netty.example.telnet.TelnetServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple SSL chat server modified from {@link TelnetServer}.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class SecureChatServer {
|
public class SecureChatServer {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// Start server.
|
// Configure the server.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioServerSocketChannelFactory(
|
new NioServerSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -45,6 +54,7 @@ public class SecureChatServer {
|
|||||||
bootstrap.setOption("child.tcpNoDelay", true);
|
bootstrap.setOption("child.tcpNoDelay", true);
|
||||||
bootstrap.setOption("child.keepAlive", true);
|
bootstrap.setOption("child.keepAlive", true);
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
bootstrap.bind(new InetSocketAddress(8080));
|
bootstrap.bind(new InetSocketAddress(8080));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,14 @@ import org.jboss.netty.channel.SimpleChannelHandler;
|
|||||||
import org.jboss.netty.handler.ssl.SslHandler;
|
import org.jboss.netty.handler.ssl.SslHandler;
|
||||||
import org.jboss.netty.util.MapBackedSet;
|
import org.jboss.netty.util.MapBackedSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a server-side channel.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
@ChannelPipelineCoverage("all")
|
@ChannelPipelineCoverage("all")
|
||||||
public class SecureChatServerHandler extends SimpleChannelHandler {
|
public class SecureChatServerHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
@ -64,6 +72,7 @@ public class SecureChatServerHandler extends SimpleChannelHandler {
|
|||||||
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
||||||
|
|
||||||
// Get the SslHandler in the current pipeline.
|
// Get the SslHandler in the current pipeline.
|
||||||
|
// We added it in SecureChatPipelineFactory.
|
||||||
final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
|
final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
|
||||||
|
|
||||||
// Get notified when SSL handshake is done.
|
// Get notified when SSL handshake is done.
|
||||||
@ -113,7 +122,7 @@ public class SecureChatServerHandler extends SimpleChannelHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the connection if the client sent 'bye'.
|
// Close the connection if the client has sent 'bye'.
|
||||||
if (request.toLowerCase().equals("bye")) {
|
if (request.toLowerCase().equals("bye")) {
|
||||||
e.getChannel().close();
|
e.getChannel().close();
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,16 @@ import javax.net.ssl.KeyManagerFactory;
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creates a bogus {@link SSLContext}. A client-side context created by this
|
||||||
|
* factory accepts any certificate even if it's invalid. A server-side context
|
||||||
|
* created by this factory sends a bogus certificate defined in {@link SecureChatKeyStore}.
|
||||||
|
*
|
||||||
|
* You will have to create your context differently in a real world application.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class SecureChatSslContextFactory {
|
public class SecureChatSslContextFactory {
|
||||||
|
|
||||||
|
@ -34,11 +34,13 @@ import javax.net.ssl.TrustManagerFactorySpi;
|
|||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Bogus {@link TrustManagerFactorySpi} which accepts any certificate
|
||||||
|
* even if it's invalid.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class SecureChatTrustManagerFactory extends TrustManagerFactorySpi {
|
public class SecureChatTrustManagerFactory extends TrustManagerFactorySpi {
|
||||||
|
|
||||||
|
@ -33,6 +33,14 @@ import org.jboss.netty.channel.ChannelFactory;
|
|||||||
import org.jboss.netty.channel.ChannelFuture;
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplistic telnet client.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class TelnetClient {
|
public class TelnetClient {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@ -48,7 +56,7 @@ public class TelnetClient {
|
|||||||
String host = args[0];
|
String host = args[0];
|
||||||
int port = Integer.parseInt(args[1]);
|
int port = Integer.parseInt(args[1]);
|
||||||
|
|
||||||
// Start client.
|
// Configure the client.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioClientSocketChannelFactory(
|
new NioClientSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -61,6 +69,7 @@ public class TelnetClient {
|
|||||||
bootstrap.setOption("tcpNoDelay", true);
|
bootstrap.setOption("tcpNoDelay", true);
|
||||||
bootstrap.setOption("keepAlive", true);
|
bootstrap.setOption("keepAlive", true);
|
||||||
|
|
||||||
|
// Start the connection attempt.
|
||||||
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
|
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
|
||||||
|
|
||||||
// Wait until the connection attempt succeeds or fails.
|
// Wait until the connection attempt succeeds or fails.
|
||||||
@ -78,6 +87,8 @@ public class TelnetClient {
|
|||||||
if (line == null) {
|
if (line == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sends the received line to the server.
|
||||||
lastWriteFuture = channel.write(line + '\n');
|
lastWriteFuture = channel.write(line + '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +97,8 @@ public class TelnetClient {
|
|||||||
lastWriteFuture.awaitUninterruptibly();
|
lastWriteFuture.awaitUninterruptibly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close the connection. Make sure the close operation ends because
|
||||||
|
// all I/O operations are asynchronous in Netty.
|
||||||
channel.close().awaitUninterruptibly();
|
channel.close().awaitUninterruptibly();
|
||||||
|
|
||||||
// We should shut down all thread pools here to exit normally.
|
// We should shut down all thread pools here to exit normally.
|
||||||
|
@ -33,6 +33,14 @@ import org.jboss.netty.channel.ExceptionEvent;
|
|||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a client-side channel.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
@ChannelPipelineCoverage("all")
|
@ChannelPipelineCoverage("all")
|
||||||
public class TelnetClientHandler extends SimpleChannelHandler {
|
public class TelnetClientHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
@ -51,6 +59,7 @@ public class TelnetClientHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void messageReceived(
|
public void messageReceived(
|
||||||
ChannelHandlerContext ctx, MessageEvent e) {
|
ChannelHandlerContext ctx, MessageEvent e) {
|
||||||
|
// Print out the line received from the server.
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@ import org.jboss.netty.handler.codec.string.StringDecoder;
|
|||||||
import org.jboss.netty.handler.codec.string.StringEncoder;
|
import org.jboss.netty.handler.codec.string.StringEncoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creates a newly configured {@link ChannelPipeline} for a new channel.
|
||||||
|
*
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Trustin Lee (tlee@redhat.com)
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
*
|
*
|
||||||
@ -49,9 +51,10 @@ public class TelnetPipelineFactory implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ChannelPipeline getPipeline() throws Exception {
|
public ChannelPipeline getPipeline() throws Exception {
|
||||||
|
// Create a default pipeline implementation.
|
||||||
ChannelPipeline pipeline = pipeline();
|
ChannelPipeline pipeline = pipeline();
|
||||||
|
|
||||||
// Add the text line codec first,
|
// Add the text line codec combination first,
|
||||||
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
|
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
|
||||||
8192, Delimiters.lineDelimiter()));
|
8192, Delimiters.lineDelimiter()));
|
||||||
pipeline.addLast("decoder", new StringDecoder());
|
pipeline.addLast("decoder", new StringDecoder());
|
||||||
|
@ -29,10 +29,18 @@ import org.jboss.netty.bootstrap.ServerBootstrap;
|
|||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplistic telnet server.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
public class TelnetServer {
|
public class TelnetServer {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// Start server.
|
// Configure the server.
|
||||||
ChannelFactory factory =
|
ChannelFactory factory =
|
||||||
new NioServerSocketChannelFactory(
|
new NioServerSocketChannelFactory(
|
||||||
Executors.newCachedThreadPool(),
|
Executors.newCachedThreadPool(),
|
||||||
@ -45,6 +53,7 @@ public class TelnetServer {
|
|||||||
bootstrap.setOption("child.tcpNoDelay", true);
|
bootstrap.setOption("child.tcpNoDelay", true);
|
||||||
bootstrap.setOption("child.keepAlive", true);
|
bootstrap.setOption("child.keepAlive", true);
|
||||||
|
|
||||||
|
// Bind and start to accept incoming connections.
|
||||||
bootstrap.bind(new InetSocketAddress(8080));
|
bootstrap.bind(new InetSocketAddress(8080));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,14 @@ import org.jboss.netty.channel.ExceptionEvent;
|
|||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a server-side channel.
|
||||||
|
*
|
||||||
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
|
* @author Trustin Lee (tlee@redhat.com)
|
||||||
|
*
|
||||||
|
* @version $Rev$, $Date$
|
||||||
|
*/
|
||||||
@ChannelPipelineCoverage("all")
|
@ChannelPipelineCoverage("all")
|
||||||
public class TelnetServerHandler extends SimpleChannelHandler {
|
public class TelnetServerHandler extends SimpleChannelHandler {
|
||||||
|
|
||||||
@ -55,7 +63,7 @@ public class TelnetServerHandler extends SimpleChannelHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void channelConnected(
|
public void channelConnected(
|
||||||
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
||||||
// Send greeting.
|
// Send greeting for a new connection.
|
||||||
e.getChannel().write(
|
e.getChannel().write(
|
||||||
"Welcome to " + InetAddress.getLocalHost().getHostName() + "!\n");
|
"Welcome to " + InetAddress.getLocalHost().getHostName() + "!\n");
|
||||||
e.getChannel().write("It's " + new Date() + " now.\n");
|
e.getChannel().write("It's " + new Date() + " now.\n");
|
||||||
@ -65,7 +73,8 @@ public class TelnetServerHandler extends SimpleChannelHandler {
|
|||||||
public void messageReceived(
|
public void messageReceived(
|
||||||
ChannelHandlerContext ctx, MessageEvent e) {
|
ChannelHandlerContext ctx, MessageEvent e) {
|
||||||
|
|
||||||
// Convert to a String first.
|
// Cast to a String first.
|
||||||
|
// We know it's a String because we put some codec in TelnetPipelineFactory.
|
||||||
String request = (String) e.getMessage();
|
String request = (String) e.getMessage();
|
||||||
|
|
||||||
// Generate and write a response.
|
// Generate and write a response.
|
||||||
@ -80,9 +89,12 @@ public class TelnetServerHandler extends SimpleChannelHandler {
|
|||||||
response = "Did you say '" + request + "'?\n";
|
response = "Did you say '" + request + "'?\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't need to write a ChannelBuffer here.
|
||||||
|
// We know the encoder inserted at TelnetPipelineFactory will do the conversion.
|
||||||
ChannelFuture future = e.getChannel().write(response);
|
ChannelFuture future = e.getChannel().write(response);
|
||||||
|
|
||||||
// Close the connection after sending 'Have a good day!'
|
// Close the connection after sending 'Have a good day!'
|
||||||
|
// if the client has sent 'bye'.
|
||||||
if (close) {
|
if (close) {
|
||||||
future.addListener(ChannelFutureListener.CLOSE);
|
future.addListener(ChannelFutureListener.CLOSE);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user