Clean up the examples

Motivation:

The examples have not been updated since long time ago, showing various
issues fixed in this commit.

Modifications:

- Overall simplification to reduce LoC
  - Use system properties to get options instead of parsing args.
  - Minimize option validation
  - Just use System.out/err instead of Logger
  - Do not pass config as parameters - just access it directly
  - Move the main logic to main(String[]) instead of creating a new
    instance meaninglessly
    - Update netty-build-21 to make checkstyle not complain
  - Remove 'throws Exception' clause if possible
- Line wrap at 120 (previously at 80)
- Add an option to enable SSL for most examples
- Use ChannelFuture.sync() instead of await()
- Use System.out for the actual result. Use System.err otherwise.
- Delete examples that are not very useful:
  - applet
  - websocket/html5
  - websocketx/sslserver
  - localecho/multithreaded
- Add run-example.sh which simplifies launching an example from command
  line
- Rewrite FileServer example

Result:

Shorter and simpler examples.  A user can focus more on what it actually
does than miscellaneous stuff.  A user can launch an example very
easily.
This commit is contained in:
Trustin Lee 2014-05-23 16:46:31 +09:00
parent 47f961b6b9
commit 3f8194557b
158 changed files with 2160 additions and 4470 deletions

View File

@ -27,11 +27,6 @@ import java.util.List;
* Before returning SocksRequest decoder removes itself from pipeline. * Before returning SocksRequest decoder removes itself from pipeline.
*/ */
public class SocksAuthRequestDecoder extends ReplayingDecoder<SocksAuthRequestDecoder.State> { public class SocksAuthRequestDecoder extends ReplayingDecoder<SocksAuthRequestDecoder.State> {
private static final String name = "SOCKS_AUTH_REQUEST_DECODER";
public static String getName() {
return name;
}
private SocksSubnegotiationVersion version; private SocksSubnegotiationVersion version;
private int fieldLength; private int fieldLength;

View File

@ -26,11 +26,6 @@ import java.util.List;
* Before returning SocksResponse decoder removes itself from pipeline. * Before returning SocksResponse decoder removes itself from pipeline.
*/ */
public class SocksAuthResponseDecoder extends ReplayingDecoder<SocksAuthResponseDecoder.State> { public class SocksAuthResponseDecoder extends ReplayingDecoder<SocksAuthResponseDecoder.State> {
private static final String name = "SOCKS_AUTH_RESPONSE_DECODER";
public static String getName() {
return name;
}
private SocksSubnegotiationVersion version; private SocksSubnegotiationVersion version;
private SocksAuthStatus authStatus; private SocksAuthStatus authStatus;

View File

@ -27,11 +27,6 @@ import java.util.List;
* Before returning SocksRequest decoder removes itself from pipeline. * Before returning SocksRequest decoder removes itself from pipeline.
*/ */
public class SocksCmdRequestDecoder extends ReplayingDecoder<SocksCmdRequestDecoder.State> { public class SocksCmdRequestDecoder extends ReplayingDecoder<SocksCmdRequestDecoder.State> {
private static final String name = "SOCKS_CMD_REQUEST_DECODER";
public static String getName() {
return name;
}
private SocksProtocolVersion version; private SocksProtocolVersion version;
private int fieldLength; private int fieldLength;

View File

@ -27,11 +27,6 @@ import java.util.List;
* Before returning SocksResponse decoder removes itself from pipeline. * Before returning SocksResponse decoder removes itself from pipeline.
*/ */
public class SocksCmdResponseDecoder extends ReplayingDecoder<SocksCmdResponseDecoder.State> { public class SocksCmdResponseDecoder extends ReplayingDecoder<SocksCmdResponseDecoder.State> {
private static final String name = "SOCKS_CMD_RESPONSE_DECODER";
public static String getName() {
return name;
}
private SocksProtocolVersion version; private SocksProtocolVersion version;
private int fieldLength; private int fieldLength;

View File

@ -27,11 +27,6 @@ import java.util.List;
* Before returning SocksRequest decoder removes itself from pipeline. * Before returning SocksRequest decoder removes itself from pipeline.
*/ */
public class SocksInitRequestDecoder extends ReplayingDecoder<SocksInitRequestDecoder.State> { public class SocksInitRequestDecoder extends ReplayingDecoder<SocksInitRequestDecoder.State> {
private static final String name = "SOCKS_INIT_REQUEST_DECODER";
public static String getName() {
return name;
}
private final List<SocksAuthScheme> authSchemes = new ArrayList<SocksAuthScheme>(); private final List<SocksAuthScheme> authSchemes = new ArrayList<SocksAuthScheme>();
private SocksProtocolVersion version; private SocksProtocolVersion version;

View File

@ -26,11 +26,6 @@ import java.util.List;
* Before returning SocksResponse decoder removes itself from pipeline. * Before returning SocksResponse decoder removes itself from pipeline.
*/ */
public class SocksInitResponseDecoder extends ReplayingDecoder<SocksInitResponseDecoder.State> { public class SocksInitResponseDecoder extends ReplayingDecoder<SocksInitResponseDecoder.State> {
private static final String name = "SOCKS_INIT_RESPONSE_DECODER";
public static String getName() {
return name;
}
private SocksProtocolVersion version; private SocksProtocolVersion version;
private SocksAuthScheme authScheme; private SocksAuthScheme authScheme;

View File

@ -28,12 +28,6 @@ import io.netty.handler.codec.MessageToByteEncoder;
*/ */
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class SocksMessageEncoder extends MessageToByteEncoder<SocksMessage> { public class SocksMessageEncoder extends MessageToByteEncoder<SocksMessage> {
private static final String name = "SOCKS_MESSAGE_ENCODER";
public static String getName() {
return name;
}
@Override @Override
protected void encode(ChannelHandlerContext ctx, SocksMessage msg, ByteBuf out) throws Exception { protected void encode(ChannelHandlerContext ctx, SocksMessage msg, ByteBuf out) throws Exception {
msg.encodeAsByteBuf(out); msg.encodeAsByteBuf(out);

View File

@ -1,88 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.applet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;
import javax.swing.JApplet;
/**
* {@link JApplet} which starts up a Server that receive data and discard it.
*/
public class AppletDiscardServer extends JApplet {
private static final long serialVersionUID = -7824894101960583175L;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
@Override
public void init() {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new DiscardServerHandler());
}
});
ChannelFuture f = bootstrap.bind(9999).sync();
f.channel().closeFuture().sync();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
@Override
public void destroy() {
super.destroy();
if (bossGroup != null) {
bossGroup.shutdownGracefully();
}
if (workerGroup != null) {
workerGroup.shutdownGracefully();
}
}
private static final class DiscardServerHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("Received: " + msg.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}

View File

@ -17,35 +17,52 @@ package io.netty.example.discard;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/** /**
* Keeps sending random data to the specified address. * Keeps sending random data to the specified address.
*/ */
public class DiscardClient { public final class DiscardClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int firstMessageSize; static final int PORT = Integer.parseInt(System.getProperty("port", "8009"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public DiscardClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.firstMessageSize = firstMessageSize; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
b.group(group) b.group(group)
.channel(NioSocketChannel.class) .channel(NioSocketChannel.class)
.handler(new DiscardClientHandler(firstMessageSize)); .handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
p.addLast(new DiscardClientHandler());
}
});
// Make the connection attempt. // Make the connection attempt.
ChannelFuture f = b.connect(host, port).sync(); ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed. // Wait until the connection is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
@ -53,26 +70,4 @@ public class DiscardClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + DiscardClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
}
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new DiscardClient(host, port, firstMessageSize).run();
}
} }

View File

@ -21,59 +21,39 @@ import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handles a client-side channel. * Handles a client-side channel.
*/ */
public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> { public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(
DiscardClientHandler.class.getName());
private final int messageSize;
private ByteBuf content; private ByteBuf content;
private ChannelHandlerContext ctx; private ChannelHandlerContext ctx;
public DiscardClientHandler(int messageSize) {
if (messageSize <= 0) {
throw new IllegalArgumentException(
"messageSize: " + messageSize);
}
this.messageSize = messageSize;
}
@Override @Override
public void channelActive(ChannelHandlerContext ctx) public void channelActive(ChannelHandlerContext ctx) {
throws Exception {
this.ctx = ctx; this.ctx = ctx;
// Initialize the message. // Initialize the message.
content = ctx.alloc().directBuffer(messageSize).writeZero(messageSize); content = ctx.alloc().directBuffer(DiscardClient.SIZE).writeZero(DiscardClient.SIZE);
// Send the initial messages. // Send the initial messages.
generateTraffic(); generateTraffic();
} }
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) {
content.release(); content.release();
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, Object msg) {
// Server is supposed to send nothing, but if it sends something, discard it. // Server is supposed to send nothing, but if it sends something, discard it.
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
Throwable cause) throws Exception {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log( cause.printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.",
cause);
ctx.close(); ctx.close();
} }
@ -87,9 +67,12 @@ public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() { private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { if (future.isSuccess()) {
generateTraffic(); generateTraffic();
} else {
future.cause().printStackTrace();
future.channel().close();
} }
} }
}; };

View File

@ -18,38 +18,54 @@ package io.netty.example.discard;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* Discards any incoming data. * Discards any incoming data.
*/ */
public class DiscardServer { public final class DiscardServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8009"));
public DiscardServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new DiscardServerHandler()); ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new DiscardServerHandler());
} }
}); });
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync(); ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed. // Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully // In this example, this does not happen, but you can do that to gracefully
@ -60,14 +76,4 @@ public class DiscardServer {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new DiscardServer(port).run();
}
} }

View File

@ -18,30 +18,20 @@ package io.netty.example.discard;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handles a server-side channel. * Handles a server-side channel.
*/ */
public class DiscardServerHandler extends SimpleChannelInboundHandler<Object> { public class DiscardServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(
DiscardServerHandler.class.getName());
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, Object msg) {
// discard // discard
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
Throwable cause) throws Exception {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log( cause.printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.",
cause);
ctx.close(); ctx.close();
} }
} }

View File

@ -19,10 +19,15 @@ import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/** /**
* Sends one message when a connection is open and echoes back any received * Sends one message when a connection is open and echoes back any received
@ -30,19 +35,22 @@ import io.netty.channel.socket.nio.NioSocketChannel;
* traffic between the echo client and server by sending the first message to * traffic between the echo client and server by sending the first message to
* the server. * the server.
*/ */
public class EchoClient { public final class EchoClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int firstMessageSize; static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public EchoClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.git
this.port = port; final SslContext sslCtx;
this.firstMessageSize = firstMessageSize; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
// Configure the client. // Configure the client.
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
@ -53,14 +61,17 @@ public class EchoClient {
.handler(new ChannelInitializer<SocketChannel>() { .handler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast( ChannelPipeline p = ch.pipeline();
//new LoggingHandler(LogLevel.INFO), if (sslCtx != null) {
new EchoClientHandler(firstMessageSize)); p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoClientHandler());
} }
}); });
// Start the client. // Start the client.
ChannelFuture f = b.connect(host, port).sync(); ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed. // Wait until the connection is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
@ -69,26 +80,4 @@ public class EchoClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + EchoClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
}
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new EchoClient(host, port, firstMessageSize).run();
}
} }

View File

@ -20,9 +20,6 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler implementation for the echo client. It initiates the ping-pong * Handler implementation for the echo client. It initiates the ping-pong
* traffic between the echo client and server by sending the first message to * traffic between the echo client and server by sending the first message to
@ -30,19 +27,13 @@ import java.util.logging.Logger;
*/ */
public class EchoClientHandler extends ChannelHandlerAdapter { public class EchoClientHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(
EchoClientHandler.class.getName());
private final ByteBuf firstMessage; private final ByteBuf firstMessage;
/** /**
* Creates a client-side handler. * Creates a client-side handler.
*/ */
public EchoClientHandler(int firstMessageSize) { public EchoClientHandler() {
if (firstMessageSize <= 0) { firstMessage = Unpooled.buffer(EchoClient.SIZE);
throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);
}
firstMessage = Unpooled.buffer(firstMessageSize);
for (int i = 0; i < firstMessage.capacity(); i ++) { for (int i = 0; i < firstMessage.capacity(); i ++) {
firstMessage.writeByte((byte) i); firstMessage.writeByte((byte) i);
} }
@ -54,19 +45,19 @@ public class EchoClientHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); cause.printStackTrace();
ctx.close(); ctx.close();
} }
} }

View File

@ -19,25 +19,34 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* Echoes back any received data from a client. * Echoes back any received data from a client.
*/ */
public class EchoServer { public final class EchoServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public EchoServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
// Configure the server. // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -50,14 +59,17 @@ public class EchoServer {
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast( ChannelPipeline p = ch.pipeline();
//new LoggingHandler(LogLevel.INFO), if (sslCtx != null) {
new EchoServerHandler()); p.addLast(sslCtx.newHandler(ch.alloc()));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoServerHandler());
} }
}); });
// Start the server. // Start the server.
ChannelFuture f = b.bind(port).sync(); ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed. // Wait until the server socket is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
@ -67,14 +79,4 @@ public class EchoServer {
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new EchoServer(port).run();
}
} }

View File

@ -19,32 +19,26 @@ import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler implementation for the echo server. * Handler implementation for the echo server.
*/ */
@Sharable @Sharable
public class EchoServerHandler extends ChannelHandlerAdapter { public class EchoServerHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(
EchoServerHandler.class.getName());
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); cause.printStackTrace();
ctx.close(); ctx.close();
} }
} }

View File

@ -44,8 +44,7 @@ public class BigIntegerDecoder extends ByteToMessageDecoder {
int magicNumber = in.readUnsignedByte(); int magicNumber = in.readUnsignedByte();
if (magicNumber != 'F') { if (magicNumber != 'F') {
in.resetReaderIndex(); in.resetReaderIndex();
throw new CorruptedFrameException( throw new CorruptedFrameException("Invalid magic number: " + magicNumber);
"Invalid magic number: " + magicNumber);
} }
// Wait until the whole data is available. // Wait until the whole data is available.

View File

@ -20,63 +20,47 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/** /**
* Sends a sequence of integers to a {@link FactorialServer} to calculate * Sends a sequence of integers to a {@link FactorialServer} to calculate
* the factorial of the specified integer. * the factorial of the specified integer.
*/ */
public class FactorialClient { public final class FactorialClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int count; static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
static final int COUNT = Integer.parseInt(System.getProperty("count", "1000"));
public FactorialClient(String host, int port, int count) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.count = count; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
b.group(group) b.group(group)
.channel(NioSocketChannel.class) .channel(NioSocketChannel.class)
.handler(new FactorialClientInitializer(count)); .handler(new FactorialClientInitializer(sslCtx));
// Make a new connection. // Make a new connection.
ChannelFuture f = b.connect(host, port).sync(); ChannelFuture f = b.connect(HOST, PORT).sync();
// Get the handler instance to retrieve the answer. // Get the handler instance to retrieve the answer.
FactorialClientHandler handler = FactorialClientHandler handler =
(FactorialClientHandler) f.channel().pipeline().last(); (FactorialClientHandler) f.channel().pipeline().last();
// Print out the answer. // Print out the answer.
System.err.format( System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial());
"Factorial of %,d is: %,d", count, handler.getFactorial());
} finally { } finally {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length != 3) {
System.err.println(
"Usage: " + FactorialClient.class.getSimpleName() +
" <host> <port> <count>");
return;
}
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
int count = Integer.parseInt(args[2]);
if (count <= 0) {
throw new IllegalArgumentException("count must be a positive integer.");
}
new FactorialClient(host, port, count).run();
}
} }

View File

@ -23,8 +23,6 @@ import io.netty.channel.SimpleChannelInboundHandler;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler for a client-side channel. This handler maintains stateful * Handler for a client-side channel. This handler maintains stateful
@ -35,30 +33,24 @@ import java.util.logging.Logger;
*/ */
public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteger> { public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteger> {
private static final Logger logger = Logger.getLogger(
FactorialClientHandler.class.getName());
private ChannelHandlerContext ctx; private ChannelHandlerContext ctx;
private int receivedMessages; private int receivedMessages;
private int next = 1; private int next = 1;
private final int count;
final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>(); final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>();
public FactorialClientHandler(int count) {
this.count = count;
}
public BigInteger getFactorial() { public BigInteger getFactorial() {
boolean interrupted = false; boolean interrupted = false;
for (;;) { try {
try { for (;;) {
BigInteger factorial = answer.take(); try {
if (interrupted) { return answer.take();
Thread.currentThread().interrupt(); } catch (InterruptedException ignore) {
interrupted = true;
} }
return factorial; }
} catch (InterruptedException e) { } finally {
interrupted = true; if (interrupted) {
Thread.currentThread().interrupt();
} }
} }
} }
@ -72,7 +64,7 @@ public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteg
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, final BigInteger msg) { public void messageReceived(ChannelHandlerContext ctx, final BigInteger msg) {
receivedMessages ++; receivedMessages ++;
if (receivedMessages == count) { if (receivedMessages == FactorialClient.COUNT) {
// Offer the answer after closing the connection. // Offer the answer after closing the connection.
ctx.channel().close().addListener(new ChannelFutureListener() { ctx.channel().close().addListener(new ChannelFutureListener() {
@Override @Override
@ -85,22 +77,19 @@ public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteg
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close(); ctx.close();
} }
private void sendNumbers() { private void sendNumbers() {
// Do not send more than 4096 numbers. // Do not send more than 4096 numbers.
ChannelFuture future = null; ChannelFuture future = null;
for (int i = 0; i < 4096 && next <= count; i++) { for (int i = 0; i < 4096 && next <= FactorialClient.COUNT; i++) {
future = ctx.write(Integer.valueOf(next)); future = ctx.write(Integer.valueOf(next));
next++; next++;
} }
if (next <= count) { if (next <= FactorialClient.COUNT) {
assert future != null; assert future != null;
future.addListener(numberSender); future.addListener(numberSender);
} }
@ -112,6 +101,9 @@ public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteg
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
sendNumbers(); sendNumbers();
} else {
future.cause().printStackTrace();
future.channel().close();
} }
} }
}; };

View File

@ -20,31 +20,36 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.compression.ZlibCodecFactory; import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper; import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.ssl.SslContext;
/** /**
* Creates a newly configured {@link ChannelPipeline} for a client-side channel. * Creates a newly configured {@link ChannelPipeline} for a client-side channel.
*/ */
public class FactorialClientInitializer extends ChannelInitializer<SocketChannel> { public class FactorialClientInitializer extends ChannelInitializer<SocketChannel> {
private final int count; private final SslContext sslCtx;
public FactorialClientInitializer(int count) { public FactorialClientInitializer(SslContext sslCtx) {
this.count = count; this.sslCtx = sslCtx;
} }
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc(), FactorialClient.HOST, FactorialClient.PORT));
}
// Enable stream compression (you can remove these two if unnecessary) // Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast("deflater", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP)); pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast("inflater", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
// Add the number codec first, // Add the number codec first,
pipeline.addLast("decoder", new BigIntegerDecoder()); pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast("encoder", new NumberEncoder()); pipeline.addLast(new NumberEncoder());
// and then business logic. // and then business logic.
pipeline.addLast("handler", new FactorialClientHandler(count)); pipeline.addLast(new FactorialClientHandler());
} }
} }

View File

@ -19,42 +19,43 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* Receives a sequence of integers from a {@link FactorialClient} to calculate * Receives a sequence of integers from a {@link FactorialClient} to calculate
* the factorial of the specified integer. * the factorial of the specified integer.
*/ */
public class FactorialServer { public final class FactorialServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
public FactorialServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new FactorialServerInitializer()); .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new FactorialServerInitializer(sslCtx));
b.bind(port).sync().channel().closeFuture().sync(); b.bind(PORT).sync().channel().closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new FactorialServer(port).run();
}
} }

View File

@ -19,9 +19,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler for a server-side channel. This handler maintains stateful * Handler for a server-side channel. This handler maintains stateful
@ -32,14 +29,11 @@ import java.util.logging.Logger;
*/ */
public class FactorialServerHandler extends SimpleChannelInboundHandler<BigInteger> { public class FactorialServerHandler extends SimpleChannelInboundHandler<BigInteger> {
private static final Logger logger = Logger.getLogger(
FactorialServerHandler.class.getName());
private BigInteger lastMultiplier = new BigInteger("1"); private BigInteger lastMultiplier = new BigInteger("1");
private BigInteger factorial = new BigInteger("1"); private BigInteger factorial = new BigInteger("1");
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, BigInteger msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, BigInteger msg) {
// Calculate the cumulative factorial and send it to the client. // Calculate the cumulative factorial and send it to the client.
lastMultiplier = msg; lastMultiplier = msg;
factorial = factorial.multiply(msg); factorial = factorial.multiply(msg);
@ -48,17 +42,12 @@ public class FactorialServerHandler extends SimpleChannelInboundHandler<BigInteg
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Formatter fmt = new Formatter(); System.err.printf("Factorial of %,d is: %,d%n", lastMultiplier, factorial);
logger.info(fmt.format(
"Factorial of %,d is: %,d", lastMultiplier, factorial).toString());
fmt.close();
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log( cause.printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close(); ctx.close();
} }
} }

View File

@ -20,26 +20,38 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.compression.ZlibCodecFactory; import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper; import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.ssl.SslContext;
/** /**
* Creates a newly configured {@link ChannelPipeline} for a server-side channel. * Creates a newly configured {@link ChannelPipeline} for a server-side channel.
*/ */
public class FactorialServerInitializer extends ChannelInitializer<SocketChannel> { public class FactorialServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public FactorialServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
// Enable stream compression (you can remove these two if unnecessary) // Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast("deflater", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP)); pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast("inflater", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
// Add the number codec first, // Add the number codec first,
pipeline.addLast("decoder", new BigIntegerDecoder()); pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast("encoder", new NumberEncoder()); pipeline.addLast(new NumberEncoder());
// and then business logic. // and then business logic.
// Please note we create a handler for every new channel // Please note we create a handler for every new channel
// because it has stateful properties. // because it has stateful properties.
pipeline.addLast("handler", new FactorialServerHandler()); pipeline.addLast(new FactorialServerHandler());
} }
} }

View File

@ -29,7 +29,7 @@ import java.math.BigInteger;
public class NumberEncoder extends MessageToByteEncoder<Number> { public class NumberEncoder extends MessageToByteEncoder<Number> {
@Override @Override
protected void encode(ChannelHandlerContext ctx, Number msg, ByteBuf out) throws Exception { protected void encode(ChannelHandlerContext ctx, Number msg, ByteBuf out) {
// Convert to a BigInteger first for easier implementation. // Convert to a BigInteger first for easier implementation.
BigInteger v; BigInteger v;
if (msg instanceof BigInteger) { if (msg instanceof BigInteger) {

View File

@ -13,17 +13,14 @@
* License for the specific language governing permissions and limitations * License for the specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package io.netty.example.filetransfer; package io.netty.example.file;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultFileRegion; import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.FileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
@ -32,23 +29,30 @@ import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import java.io.File;
import java.io.FileInputStream;
/** /**
* Server that accept the path of a file an echo back its content. * Server that accept the path of a file an echo back its content.
*/ */
public class FileServer { public final class FileServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
// Use the same default port with the telnet example so that we can use the telnet client example to access it.
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8023"));
public FileServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
// Configure the server. // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -61,16 +65,21 @@ public class FileServer {
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast( ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(
new StringEncoder(CharsetUtil.UTF_8), new StringEncoder(CharsetUtil.UTF_8),
new LineBasedFrameDecoder(8192), new LineBasedFrameDecoder(8192),
new StringDecoder(CharsetUtil.UTF_8), new StringDecoder(CharsetUtil.UTF_8),
new FileHandler()); new ChunkedWriteHandler(),
new FileServerHandler());
} }
}); });
// Start the server. // Start the server.
ChannelFuture f = b.bind(port).sync(); ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed. // Wait until the server socket is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
@ -80,41 +89,4 @@ public class FileServer {
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new FileServer(port).run();
}
private static final class FileHandler extends SimpleChannelInboundHandler<String> {
@Override
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
File file = new File(msg);
if (file.exists()) {
if (!file.isFile()) {
ctx.writeAndFlush("Not a file: " + file + '\n');
return;
}
ctx.write(file + " " + file.length() + '\n');
FileInputStream fis = new FileInputStream(file);
FileRegion region = new DefaultFileRegion(fis.getChannel(), 0, file.length());
ctx.write(region);
ctx.writeAndFlush("\n");
fis.close();
} else {
ctx.writeAndFlush("File not found: " + file + '\n');
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
} }

View File

@ -0,0 +1,73 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.file;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedFile;
import java.io.RandomAccessFile;
public class FileServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush("HELO: Type the path of the file to retrieve.\n");
}
@Override
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
RandomAccessFile raf = null;
long length = -1;
try {
raf = new RandomAccessFile(msg, "r");
length = raf.length();
} catch (Exception e) {
ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n');
return;
} finally {
if (length < 0 && raf != null) {
raf.close();
}
}
ctx.write("OK: " + raf.length() + '\n');
if (ctx.pipeline().get(SslHandler.class) == null) {
// SSL not enabled - can use zero-copy file transfer.
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length));
} else {
// SSL enabled - cannot use zero-copy file transfer.
ctx.write(new ChunkedFile(raf));
}
ctx.writeAndFlush("\n");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
if (ctx.channel().isActive()) {
ctx.writeAndFlush("ERR: " +
cause.getClass().getSimpleName() + ": " +
cause.getMessage() + '\n').addListener(ChannelFutureListener.CLOSE);
}
}
}

View File

@ -19,6 +19,10 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* This example server aims to demonstrate * This example server aims to demonstrate
@ -27,7 +31,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
* a html page that is loaded to try out CORS support in a web brower. * a html page that is loaded to try out CORS support in a web brower.
* <p> * <p>
* *
* CORS is configured in {@link HttpServerInitializer} and by updating the config you can * CORS is configured in {@link HttpCorsServerInitializer} and by updating the config you can
* try out various combinations, like using a specific origin instead of a * try out various combinations, like using a specific origin instead of a
* wildcard origin ('*'). * wildcard origin ('*').
* <p> * <p>
@ -63,40 +67,37 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
* If you inspect the headers being sent using your browser you'll see that the 'Origin' * If you inspect the headers being sent using your browser you'll see that the 'Origin'
* request header is {@code 'null'}. This is expected and happens when you load a file from the * request header is {@code 'null'}. This is expected and happens when you load a file from the
* local file system. Netty can handle this by configuring the CorsHandler which is done * local file system. Netty can handle this by configuring the CorsHandler which is done
* in the {@link HttpServerInitializer}. * in the {@link HttpCorsServerInitializer}.
* *
*/ */
public class HttpServer { public final class HttpCorsServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new HttpServerInitializer()); .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpCorsServerInitializer(sslCtx));
b.bind(port).sync().channel().closeFuture().sync(); b.bind(PORT).sync().channel().closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new HttpServer(port).run();
}
} }

View File

@ -23,6 +23,7 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.cors.CorsConfig; import io.netty.handler.codec.http.cors.CorsConfig;
import io.netty.handler.codec.http.cors.CorsHandler; import io.netty.handler.codec.http.cors.CorsHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.stream.ChunkedWriteHandler;
/** /**
@ -68,19 +69,27 @@ import io.netty.handler.stream.ChunkedWriteHandler;
* corsConfig.exposedHeaders("custom-response-header"); * corsConfig.exposedHeaders("custom-response-header");
* </pre> * </pre>
*/ */
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> { public class HttpCorsServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpCorsServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
CorsConfig corsConfig = CorsConfig.withAnyOrigin().build(); CorsConfig corsConfig = CorsConfig.withAnyOrigin().build();
pipeline.addLast("encoder", new HttpResponseEncoder()); ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder()); if (sslCtx != null) {
pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); pipeline.addLast(sslCtx.newHandler(ch.alloc()));
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); }
pipeline.addLast("cors", new CorsHandler(corsConfig)); pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast("handler", new OkResponseHandler()); pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new CorsHandler(corsConfig));
pipeline.addLast(new OkResponseHandler());
} }
} }

View File

@ -29,7 +29,7 @@ import io.netty.handler.codec.http.HttpVersion;
public class OkResponseHandler extends ChannelHandlerAdapter { public class OkResponseHandler extends ChannelHandlerAdapter {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
final DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); final DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.headers().set("custom-response-header", "Some value"); response.headers().set("custom-response-header", "Some value");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);

View File

@ -16,41 +16,49 @@
package io.netty.example.http.file; package io.netty.example.http.file;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.SelfSignedCertificate;
public class HttpStaticFileServer { public class HttpStaticFileServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpStaticFileServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(SslProvider.JDK, ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new HttpStaticFileServerInitializer()); .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpStaticFileServerInitializer(sslCtx));
b.bind(port).sync().channel().closeFuture().sync(); Channel ch = b.bind(PORT).sync().channel();
System.err.println("Open your web browser and navigate to " +
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
ch.closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new HttpStaticFileServer(port).run();
}
} }

View File

@ -32,6 +32,7 @@ import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedFile; import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.SystemPropertyUtil;
@ -108,15 +109,8 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
public static final String HTTP_DATE_GMT_TIMEZONE = "GMT"; public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
public static final int HTTP_CACHE_SECONDS = 60; public static final int HTTP_CACHE_SECONDS = 60;
private final boolean useSendFile;
public HttpStaticFileServerHandler(boolean useSendFile) {
this.useSendFile = useSendFile;
}
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
if (!request.getDecoderResult().isSuccess()) { if (!request.getDecoderResult().isSuccess()) {
sendError(ctx, BAD_REQUEST); sendError(ctx, BAD_REQUEST);
return; return;
@ -173,7 +167,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
RandomAccessFile raf; RandomAccessFile raf;
try { try {
raf = new RandomAccessFile(file, "r"); raf = new RandomAccessFile(file, "r");
} catch (FileNotFoundException fnfe) { } catch (FileNotFoundException ignore) {
sendError(ctx, NOT_FOUND); sendError(ctx, NOT_FOUND);
return; return;
} }
@ -192,7 +186,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
// Write the content. // Write the content.
ChannelFuture sendFileFuture; ChannelFuture sendFileFuture;
if (useSendFile) { if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture = sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
} else { } else {
@ -204,15 +198,15 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
@Override @Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) { // total unknown if (total < 0) { // total unknown
System.err.println("Transfer progress: " + progress); System.err.println(future.channel() + " Transfer progress: " + progress);
} else { } else {
System.err.println("Transfer progress: " + progress + " / " + total); System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total);
} }
} }
@Override @Override
public void operationComplete(ChannelProgressiveFuture future) throws Exception { public void operationComplete(ChannelProgressiveFuture future) {
System.err.println("Transfer complete."); System.err.println(future.channel() + " Transfer complete.");
} }
}); });
@ -227,7 +221,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
if (ctx.channel().isActive()) { if (ctx.channel().isActive()) {
sendError(ctx, INTERNAL_SERVER_ERROR); sendError(ctx, INTERNAL_SERVER_ERROR);
@ -241,11 +235,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
try { try {
uri = URLDecoder.decode(uri, "UTF-8"); uri = URLDecoder.decode(uri, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
try { throw new Error(e);
uri = URLDecoder.decode(uri, "ISO-8859-1");
} catch (UnsupportedEncodingException e1) {
throw new Error();
}
} }
if (!uri.startsWith("/")) { if (!uri.startsWith("/")) {
@ -326,7 +316,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse( FullHttpResponse response = new DefaultFullHttpResponse(
HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8)); HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
// Close the connection as soon as the error message is sent. // Close the connection as soon as the error message is sent.
@ -397,5 +387,4 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath())); response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
} }
} }

View File

@ -19,26 +19,27 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.stream.ChunkedWriteHandler;
public class HttpStaticFileServerInitializer extends ChannelInitializer<SocketChannel> { public class HttpStaticFileServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpStaticFileServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
// Create a default pipeline implementation.
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
// Uncomment the following line if you want HTTPS pipeline.addLast(sslCtx.newHandler(ch.alloc()));
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); }
//engine.setUseClientMode(false); pipeline.addLast(new HttpServerCodec());
//pipeline.addLast("ssl", new SslHandler(engine)); pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast(new HttpStaticFileServerHandler());
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
pipeline.addLast("handler", new HttpStaticFileServerHandler(true)); // Specify false if SSL.
} }
} }

View File

@ -21,20 +21,30 @@ import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* An HTTP server that sends back the content of the received HTTP request * An HTTP server that sends back the content of the received HTTP request
* in a pretty plaintext form. * in a pretty plaintext form.
*/ */
public class HttpHelloWorldServer { public final class HttpHelloWorldServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpHelloWorldServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
// Configure the server. // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -43,23 +53,18 @@ public class HttpHelloWorldServer {
b.option(ChannelOption.SO_BACKLOG, 1024); b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new HttpHelloWorldServerInitializer()); .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpHelloWorldServerInitializer(sslCtx));
Channel ch = b.bind(PORT).sync().channel();
System.err.println("Open your web browser and navigate to " +
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync(); ch.closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new HttpHelloWorldServer(port).run();
}
} }

View File

@ -37,7 +37,7 @@ public class HttpHelloWorldServerHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) { if (msg instanceof HttpRequest) {
HttpRequest req = (HttpRequest) msg; HttpRequest req = (HttpRequest) msg;
@ -59,7 +59,7 @@ public class HttpHelloWorldServerHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.close(); ctx.close();
} }

View File

@ -19,18 +19,23 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;
public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> { public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpHelloWorldServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
// Uncomment the following line if you want HTTPS p.addLast(sslCtx.newHandler(ch.alloc()));
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); }
//engine.setUseClientMode(false); p.addLast(new HttpServerCodec());
//p.addLast("ssl", new SslHandler(engine)); p.addLast(new HttpHelloWorldServerHandler());
p.addLast("codec", new HttpServerCodec());
p.addLast("handler", new HttpHelloWorldServerHandler());
} }
} }

View File

@ -36,17 +36,14 @@ import java.net.URI;
* A simple HTTP client that prints out the content of the HTTP response to * A simple HTTP client that prints out the content of the HTTP response to
* {@link System#out} to test {@link HttpSnoopServer}. * {@link System#out} to test {@link HttpSnoopServer}.
*/ */
public class HttpSnoopClient { public final class HttpSnoopClient {
private final URI uri; static final String URL = System.getProperty("url", "http://127.0.0.1:8080/");
public HttpSnoopClient(URI uri) { public static void main(String[] args) throws Exception {
this.uri = uri; URI uri = new URI(URL);
}
public void run() throws Exception {
String scheme = uri.getScheme() == null? "http" : uri.getScheme(); String scheme = uri.getScheme() == null? "http" : uri.getScheme();
String host = uri.getHost() == null? "localhost" : uri.getHost(); String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
int port = uri.getPort(); int port = uri.getPort();
if (port == -1) { if (port == -1) {
if ("http".equalsIgnoreCase(scheme)) { if ("http".equalsIgnoreCase(scheme)) {
@ -61,8 +58,9 @@ public class HttpSnoopClient {
return; return;
} }
// Configure SSL context if necessary.
final boolean ssl = "https".equalsIgnoreCase(scheme);
final SslContext sslCtx; final SslContext sslCtx;
boolean ssl = "https".equalsIgnoreCase(scheme);
if (ssl) { if (ssl) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE); sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else { } else {
@ -104,16 +102,4 @@ public class HttpSnoopClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println(
"Usage: " + HttpSnoopClient.class.getSimpleName() +
" <URL>");
return;
}
URI uri = new URI(args[0]);
new HttpSnoopClient(uri).run();
}
} }

View File

@ -27,44 +27,44 @@ import io.netty.util.CharsetUtil;
public class HttpSnoopClientHandler extends SimpleChannelInboundHandler<HttpObject> { public class HttpSnoopClientHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) {
if (msg instanceof HttpResponse) { if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg; HttpResponse response = (HttpResponse) msg;
System.out.println("STATUS: " + response.getStatus()); System.err.println("STATUS: " + response.getStatus());
System.out.println("VERSION: " + response.getProtocolVersion()); System.err.println("VERSION: " + response.getProtocolVersion());
System.out.println(); System.err.println();
if (!response.headers().isEmpty()) { if (!response.headers().isEmpty()) {
for (String name: response.headers().names()) { for (String name: response.headers().names()) {
for (String value: response.headers().getAll(name)) { for (String value: response.headers().getAll(name)) {
System.out.println("HEADER: " + name + " = " + value); System.err.println("HEADER: " + name + " = " + value);
} }
} }
System.out.println(); System.err.println();
} }
if (HttpHeaders.isTransferEncodingChunked(response)) { if (HttpHeaders.isTransferEncodingChunked(response)) {
System.out.println("CHUNKED CONTENT {"); System.err.println("CHUNKED CONTENT {");
} else { } else {
System.out.println("CONTENT {"); System.err.println("CONTENT {");
} }
} }
if (msg instanceof HttpContent) { if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg; HttpContent content = (HttpContent) msg;
System.out.print(content.content().toString(CharsetUtil.UTF_8)); System.err.print(content.content().toString(CharsetUtil.UTF_8));
System.out.flush(); System.err.flush();
if (content instanceof LastHttpContent) { if (content instanceof LastHttpContent) {
System.out.println("} END OF CONTENT"); System.err.println("} END OF CONTENT");
ctx.close();
} }
} }
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace(); cause.printStackTrace();
ctx.close(); ctx.close();
} }

View File

@ -20,8 +20,6 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpContentDecompressor; import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
public class HttpSnoopClientInitializer extends ChannelInitializer<SocketChannel> { public class HttpSnoopClientInitializer extends ChannelInitializer<SocketChannel> {
@ -33,25 +31,22 @@ public class HttpSnoopClientInitializer extends ChannelInitializer<SocketChannel
} }
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
// Create a default pipeline implementation.
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
p.addLast("log", new LoggingHandler(LogLevel.INFO));
// Enable HTTPS if necessary. // Enable HTTPS if necessary.
if (sslCtx != null) { if (sslCtx != null) {
p.addLast("ssl", sslCtx.newHandler(ch.alloc())); p.addLast(sslCtx.newHandler(ch.alloc()));
} }
p.addLast("codec", new HttpClientCodec()); p.addLast(new HttpClientCodec());
// Remove the following line if you don't want automatic content decompression. // Remove the following line if you don't want automatic content decompression.
p.addLast("inflater", new HttpContentDecompressor()); p.addLast(new HttpContentDecompressor());
// Uncomment the following line if you don't want to handle HttpChunks. // Uncomment the following line if you don't want to handle HttpContents.
//p.addLast("aggregator", new HttpObjectAggregator(1048576)); //p.addLast(new HttpObjectAggregator(1048576));
p.addLast("handler", new HttpSnoopClientHandler()); p.addLast(new HttpSnoopClientHandler());
} }
} }

View File

@ -20,6 +20,10 @@ import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* An HTTP server that sends back the content of the received HTTP request * An HTTP server that sends back the content of the received HTTP request
@ -27,13 +31,19 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
*/ */
public class HttpSnoopServer { public class HttpSnoopServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpSnoopServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
// Configure the server. // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -41,23 +51,18 @@ public class HttpSnoopServer {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new HttpSnoopServerInitializer()); .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpSnoopServerInitializer(sslCtx));
Channel ch = b.bind(PORT).sync().channel();
System.err.println("Open your web browser and navigate to " +
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync(); ch.closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new HttpSnoopServer(port).run();
}
} }

View File

@ -17,6 +17,7 @@ package io.netty.example.http.snoop;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.DecoderResult;
@ -50,7 +51,7 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
private final StringBuilder buf = new StringBuilder(); private final StringBuilder buf = new StringBuilder();
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@ -123,7 +124,10 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
buf.append("\r\n"); buf.append("\r\n");
} }
writeResponse(trailer, ctx); if (!writeResponse(trailer, ctx)) {
// If keep-alive is off, close the connection once the content is fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
} }
} }
} }
@ -185,7 +189,7 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.close(); ctx.close();
} }

View File

@ -20,24 +20,28 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.ssl.SslContext;
public class HttpSnoopServerInitializer extends ChannelInitializer<SocketChannel> { public class HttpSnoopServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpSnoopServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
// Create a default pipeline implementation.
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
// Uncomment the following line if you want HTTPS p.addLast(sslCtx.newHandler(ch.alloc()));
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); }
//engine.setUseClientMode(false); p.addLast(new HttpRequestDecoder());
//p.addLast("ssl", new SslHandler(engine));
p.addLast("decoder", new HttpRequestDecoder());
// Uncomment the following line if you don't want to handle HttpChunks. // Uncomment the following line if you don't want to handle HttpChunks.
//p.addLast("aggregator", new HttpObjectAggregator(1048576)); //p.addLast(new HttpObjectAggregator(1048576));
p.addLast("encoder", new HttpResponseEncoder()); p.addLast(new HttpResponseEncoder());
// Remove the following line if you don't want automatic content compression. // Remove the following line if you don't want automatic content compression.
//p.addLast("deflater", new HttpContentCompressor()); //p.addLast(new HttpContentCompressor());
p.addLast("handler", new HttpSnoopServerHandler()); p.addLast(new HttpSnoopServerHandler());
} }
} }

View File

@ -24,59 +24,55 @@ import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.LastHttpContent;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import java.util.logging.Logger;
/** /**
* Handler that just dumps the contents of the response from the server * Handler that just dumps the contents of the response from the server
*/ */
public class HttpUploadClientHandler extends SimpleChannelInboundHandler<HttpObject> { public class HttpUploadClientHandler extends SimpleChannelInboundHandler<HttpObject> {
private static final Logger logger = Logger.getLogger(HttpUploadClientHandler.class.getName());
private boolean readingChunks; private boolean readingChunks;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) {
if (msg instanceof HttpResponse) { if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg; HttpResponse response = (HttpResponse) msg;
logger.info("STATUS: " + response.getStatus()); System.err.println("STATUS: " + response.getStatus());
logger.info("VERSION: " + response.getProtocolVersion()); System.err.println("VERSION: " + response.getProtocolVersion());
if (!response.headers().isEmpty()) { if (!response.headers().isEmpty()) {
for (String name : response.headers().names()) { for (String name : response.headers().names()) {
for (String value : response.headers().getAll(name)) { for (String value : response.headers().getAll(name)) {
logger.info("HEADER: " + name + " = " + value); System.err.println("HEADER: " + name + " = " + value);
} }
} }
} }
if (response.getStatus().code() == 200 && HttpHeaders.isTransferEncodingChunked(response)) { if (response.getStatus().code() == 200 && HttpHeaders.isTransferEncodingChunked(response)) {
readingChunks = true; readingChunks = true;
logger.info("CHUNKED CONTENT {"); System.err.println("CHUNKED CONTENT {");
} else { } else {
logger.info("CONTENT {"); System.err.println("CONTENT {");
} }
} }
if (msg instanceof HttpContent) { if (msg instanceof HttpContent) {
HttpContent chunk = (HttpContent) msg; HttpContent chunk = (HttpContent) msg;
logger.info(chunk.content().toString(CharsetUtil.UTF_8)); System.err.println(chunk.content().toString(CharsetUtil.UTF_8));
if (chunk instanceof LastHttpContent) { if (chunk instanceof LastHttpContent) {
if (readingChunks) { if (readingChunks) {
logger.info("} END OF CHUNKED CONTENT"); System.err.println("} END OF CHUNKED CONTENT");
} else { } else {
logger.info("} END OF CONTENT"); System.err.println("} END OF CONTENT");
} }
readingChunks = false; readingChunks = false;
} else { } else {
logger.info(chunk.content().toString(CharsetUtil.UTF_8)); System.err.println(chunk.content().toString(CharsetUtil.UTF_8));
} }
} }
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.channel().close(); ctx.channel().close();
} }

View File

@ -32,8 +32,7 @@ public class HttpUploadClientIntializer extends ChannelInitializer<SocketChannel
} }
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
// Create a default pipeline implementation.
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) { if (sslCtx != null) {

View File

@ -20,6 +20,8 @@ import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate; import io.netty.handler.ssl.util.SelfSignedCertificate;
@ -28,26 +30,32 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
*/ */
public class HttpUploadServer { public class HttpUploadServer {
private final SslContext sslCtx; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public static boolean isSSL;
public HttpUploadServer(SslContext sslCtx, int port) { public static void main(String[] args) throws Exception {
this.sslCtx = sslCtx; // Configure SSL.
this.port = port; final SslContext sslCtx;
} if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) b.group(bossGroup, workerGroup);
.childHandler(new HttpUploadServerInitializer(sslCtx)); b.channel(NioServerSocketChannel.class);
b.handler(new LoggingHandler(LogLevel.INFO));
b.childHandler(new HttpUploadServerInitializer(sslCtx));
Channel ch = b.bind(port).sync().channel(); Channel ch = b.bind(PORT).sync().channel();
System.out.println("HTTP Upload Server at port " + port + '.');
System.out.println("Open your browser and navigate to http://localhost:" + port + '/'); System.err.println("Open your web browser and navigate to " +
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
ch.closeFuture().sync(); ch.closeFuture().sync();
} finally { } finally {
@ -55,26 +63,4 @@ public class HttpUploadServer {
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
if (args.length > 1) {
isSSL = true;
}
// Configure SSL.
SslContext sslCtx;
if (isSSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
new HttpUploadServer(sslCtx, port).run();
}
} }

View File

@ -71,10 +71,8 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
private final StringBuilder responseContent = new StringBuilder(); private final StringBuilder responseContent = new StringBuilder();
private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk private static final HttpDataFactory factory =
// if new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed
// size
// exceed
private HttpPostRequestDecoder decoder; private HttpPostRequestDecoder decoder;
static { static {
@ -128,7 +126,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
cookies = CookieDecoder.decode(value); cookies = CookieDecoder.decode(value);
} }
for (Cookie cookie : cookies) { for (Cookie cookie : cookies) {
responseContent.append("COOKIE: " + cookie.toString() + "\r\n"); responseContent.append("COOKIE: " + cookie + "\r\n");
} }
responseContent.append("\r\n\r\n"); responseContent.append("\r\n\r\n");
@ -247,10 +245,10 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
+ attribute.getName() + " data too long\r\n"); + attribute.getName() + " data too long\r\n");
} else { } else {
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": " responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
+ attribute.toString() + "\r\n"); + attribute + "\r\n");
} }
} else { } else {
responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data.toString() responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data
+ "\r\n"); + "\r\n");
if (data.getHttpDataType() == HttpDataType.FileUpload) { if (data.getHttpDataType() == HttpDataType.FileUpload) {
FileUpload fileUpload = (FileUpload) data; FileUpload fileUpload = (FileUpload) data;

View File

@ -32,21 +32,19 @@ public class HttpUploadServerInitializer extends ChannelInitializer<SocketChanne
} }
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
// Create a default pipeline implementation.
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) { if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler(ch.alloc())); pipeline.addLast(sslCtx.newHandler(ch.alloc()));
} }
pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast(new HttpResponseEncoder());
// Remove the following line if you don't want automatic content // Remove the following line if you don't want automatic content compression.
// compression. pipeline.addLast(new HttpContentCompressor());
pipeline.addLast("deflater", new HttpContentCompressor());
pipeline.addLast("handler", new HttpUploadServerHandler()); pipeline.addLast(new HttpUploadServerHandler());
} }
} }

View File

@ -15,6 +15,29 @@
*/ */
package io.netty.example.http.websocketx.client; package io.netty.example.http.websocketx.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI; import java.net.URI;
/** /**
@ -31,17 +54,89 @@ import java.net.URI;
* as this is the default. * as this is the default.
*/ */
public final class WebSocketClient { public final class WebSocketClient {
private WebSocketClient() {
}
public static void main(String... args) throws Exception { static final String URL = System.getProperty("url", "ws://127.0.0.1:8080/websocket");
URI uri;
if (args.length > 0) { public static void main(String[] args) throws Exception {
uri = new URI(args[0]); URI uri = new URI(URL);
String scheme = uri.getScheme() == null? "http" : uri.getScheme();
final String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
final int port;
if (uri.getPort() == -1) {
if ("http".equalsIgnoreCase(scheme)) {
port = 80;
} else if ("https".equalsIgnoreCase(scheme)) {
port = 443;
} else {
port = -1;
}
} else { } else {
uri = new URI("ws://localhost:8080/websocket"); port = uri.getPort();
} }
new WebSocketClientRunner(uri).run(); if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) {
System.err.println("Only WS(S) is supported.");
return;
}
final boolean ssl = "wss".equalsIgnoreCase(scheme);
final SslContext sslCtx;
if (ssl) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
EventLoopGroup group = new NioEventLoopGroup();
try {
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
// If you change it to V00, ping is not supported and remember to change
// HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline.
final WebSocketClientHandler handler =
new WebSocketClientHandler(
WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, false, new DefaultHttpHeaders()));
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), host, port));
}
p.addLast(
new HttpClientCodec(),
new HttpObjectAggregator(8192),
handler);
}
});
Channel ch = b.connect(uri.getHost(), port).sync().channel();
handler.handshakeFuture().sync();
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = console.readLine();
if (msg == null) {
break;
} else if ("bye".equals(msg.toLowerCase())) {
ch.writeAndFlush(new CloseWebSocketFrame());
ch.closeFuture().sync();
break;
} else if ("ping".equals(msg.toLowerCase())) {
WebSocketFrame frame = new PingWebSocketFrame(Unpooled.wrappedBuffer(new byte[] { 8, 1, 8, 1 }));
ch.writeAndFlush(frame);
} else {
WebSocketFrame frame = new TextWebSocketFrame(msg);
ch.writeAndFlush(frame);
}
}
} finally {
group.shutdownGracefully();
}
} }
} }

View File

@ -64,22 +64,22 @@ public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object>
} }
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception { public void handlerAdded(ChannelHandlerContext ctx) {
handshakeFuture = ctx.newPromise(); handshakeFuture = ctx.newPromise();
} }
@Override @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) {
handshaker.handshake(ctx.channel()); handshaker.handshake(ctx.channel());
} }
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("WebSocket Client disconnected!"); System.out.println("WebSocket Client disconnected!");
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, Object msg) {
Channel ch = ctx.channel(); Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) { if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (FullHttpResponse) msg); handshaker.finishHandshake(ch, (FullHttpResponse) msg);
@ -90,8 +90,9 @@ public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object>
if (msg instanceof FullHttpResponse) { if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg; FullHttpResponse response = (FullHttpResponse) msg;
throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" throw new IllegalStateException(
+ response.content().toString(CharsetUtil.UTF_8) + ')'); "Unexpected FullHttpResponse (getStatus=" + response.getStatus() +
", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
} }
WebSocketFrame frame = (WebSocketFrame) msg; WebSocketFrame frame = (WebSocketFrame) msg;
@ -107,13 +108,11 @@ public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object>
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
if (!handshakeFuture.isDone()) { if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause); handshakeFuture.setFailure(cause);
} }
ctx.close(); ctx.close();
} }
} }

View File

@ -1,134 +0,0 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLEngine;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
public final class WebSocketClientRunner {
private final URI uri;
public WebSocketClientRunner(URI uri) {
this.uri = uri;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
// If you change it to V00, ping is not supported and remember to change
// HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline.
final WebSocketClientHandler handler =
new WebSocketClientHandler(
WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, false, new DefaultHttpHeaders()));
final String protocol = uri.getScheme();
int defaultPort;
ChannelInitializer<SocketChannel> initializer;
// Normal WebSocket
if ("ws".equals(protocol)) {
initializer = new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast("http-codec", new HttpClientCodec())
.addLast("aggregator", new HttpObjectAggregator(8192))
.addLast("ws-handler", handler);
}
};
defaultPort = 80;
// Secure WebSocket
} else if ("wss".equals(protocol)) {
initializer = new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
SSLEngine engine = WebSocketSslClientContextFactory.getContext().createSSLEngine();
engine.setUseClientMode(true);
ch.pipeline()
.addFirst("ssl", new SslHandler(engine))
.addLast("http-codec", new HttpClientCodec())
.addLast("aggregator", new HttpObjectAggregator(8192))
.addLast("ws-handler", handler);
}
};
defaultPort = 443;
} else {
throw new IllegalArgumentException("Unsupported protocol: " + protocol);
}
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(initializer);
int port = uri.getPort();
// If no port was specified, we'll try the default port: https://tools.ietf.org/html/rfc6455#section-1.7
if (uri.getPort() == -1) {
port = defaultPort;
}
Channel ch = b.connect(uri.getHost(), port).sync().channel();
handler.handshakeFuture().sync();
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = console.readLine();
if (msg == null) {
break;
} else if ("bye".equals(msg.toLowerCase())) {
ch.writeAndFlush(new CloseWebSocketFrame());
ch.closeFuture().sync();
break;
} else if ("ping".equals(msg.toLowerCase())) {
WebSocketFrame frame = new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[]{8, 1, 8, 1}));
ch.writeAndFlush(frame);
} else {
WebSocketFrame frame = new TextWebSocketFrame(msg);
ch.writeAndFlush(frame);
}
}
} finally {
group.shutdownGracefully();
}
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.client;
import java.net.URI;
/**
* This is an example of a secure WebSocket client.
* <p>
* In order to run this example you need a compatible secure WebSocket server.
* Therefore you can either start the secure WebSocket server from the examples
* by running {@link io.netty.example.http.websocketx.sslserver.WebSocketSslServer}
* or connect to an existing secure WebSocket server such as
* <a href="http://www.websocket.org/echo.html">wss://echo.websocket.org</a>.
* <p>
* The client will attempt to connect to the URI passed to it as the first argument.
* You don't have to specify any arguments if you want to connect to the example secure WebSocket server,
* as this is the default.
*/
public final class WebSocketSslClient {
private WebSocketSslClient() {
}
public static void main(String... args) throws Exception {
URI uri;
if (args.length > 0) {
uri = new URI(args[0]);
} else {
uri = new URI("wss://localhost:8443/websocket");
}
new WebSocketClientRunner(uri).run();
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.client;
import javax.net.ssl.SSLContext;
/**
* Creates a bogus {@link javax.net.ssl.SSLContext}. A client-side context created by this
* factory accepts any certificate even if it is invalid.
* <p>
* You will have to create your context differently in a real world application.
* <p>
* Modified from {@link io.netty.example.securechat.SecureChatSslContextFactory}
*/
public final class WebSocketSslClientContextFactory {
private static final String PROTOCOL = "TLS";
private static final SSLContext CONTEXT;
static {
SSLContext clientContext;
try {
clientContext = SSLContext.getInstance(PROTOCOL);
clientContext.init(null, WebSocketSslClientTrustManagerFactory.getTrustManagers(), null);
} catch (Exception e) {
throw new Error(
"Failed to initialize the client-side SSLContext", e);
}
CONTEXT = clientContext;
}
public static SSLContext getContext() {
return CONTEXT;
}
private WebSocketSslClientContextFactory() {
// Unused
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.client;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactorySpi;
import javax.net.ssl.X509TrustManager;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
/**
* Bogus {@link javax.net.ssl.TrustManagerFactorySpi} which accepts any certificate
* even if it is invalid.
* <p>
* Copied from {@link io.netty.example.securechat.SecureChatTrustManagerFactory}
*/
public class WebSocketSslClientTrustManagerFactory extends TrustManagerFactorySpi {
private static final TrustManager DUMMY_TRUST_MANAGER = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// Always trust - it is an example.
// You should do something in the real world.
// You will reach here only if you enabled client certificate auth,
// as described in WebSocketSslClientContextFactory.
System.err.println(
"UNKNOWN CLIENT CERTIFICATE: " + chain[0].getSubjectDN());
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
// Always trust - it is an example.
// You should do something in the real world.
System.err.println(
"UNKNOWN SERVER CERTIFICATE: " + chain[0].getSubjectDN());
}
};
public static TrustManager[] getTrustManagers() {
return new TrustManager[]{DUMMY_TRUST_MANAGER};
}
@Override
protected TrustManager[] engineGetTrustManagers() {
return getTrustManagers();
}
@Override
protected void engineInit(KeyStore keystore) throws KeyStoreException {
// Unused
}
@Override
protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
throws InvalidAlgorithmParameterException {
// Unused
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.html5;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
public class CustomTextFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override
protected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
String request = frame.text();
ctx.channel().writeAndFlush(new TextWebSocketFrame(request.toUpperCase()));
}
}

View File

@ -1,99 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.example.http.websocketx.html5;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
/**
* A WebSocket Server that respondes to requests at:
*
* <pre>
* http://localhost:8080/websocket
* </pre>
*
* The example differs from many of the other examples in Netty in that is does
* not have an acomponying client. Instead a html page is provided that
* interacts with this server. <br>
* Open up the following file a web browser that supports WebSocket's:
*
* <pre>
* example/src/main/resources/websocketx/html5/websocket.html
* </pre>
*
* The html page is very simple were you simply enter some text and the server
* will echo the same text back, but in uppercase. You, also see getStatus messages
* in the "Response From Server" area when client has connected, disconnected
* etc.
*
*/
public class WebSocketServer {
private final int port;
public WebSocketServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
final ServerBootstrap sb = new ServerBootstrap();
sb.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(final SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new HttpResponseEncoder(),
new HttpRequestDecoder(),
new HttpObjectAggregator(65536),
new WebSocketServerProtocolHandler("/websocket"),
new CustomTextFrameHandler());
}
});
final Channel ch = sb.bind(port).sync().channel();
System.out.println("Web socket server started at port " + port);
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new WebSocketServer(port).run();
}
}

View File

@ -20,6 +20,10 @@ import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* A HTTP server which serves Web Socket requests at: * A HTTP server which serves Web Socket requests at:
@ -40,26 +44,34 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
* <li>Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) * <li>Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* </ul> * </ul>
*/ */
public class WebSocketServer { public final class WebSocketServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public WebSocketServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new WebSocketServerInitializer()); .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new WebSocketServerInitializer(sslCtx));
Channel ch = b.bind(port).sync().channel(); Channel ch = b.bind(PORT).sync().channel();
System.out.println("Web socket server started at port " + port + '.');
System.out.println("Open your browser and navigate to http://localhost:" + port + '/'); System.err.println("Open your web browser and navigate to " +
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
ch.closeFuture().sync(); ch.closeFuture().sync();
} finally { } finally {
@ -67,14 +79,4 @@ public class WebSocketServer {
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new WebSocketServer(port).run();
}
} }

View File

@ -33,9 +33,6 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import java.util.logging.Level;
import java.util.logging.Logger;
import static io.netty.handler.codec.http.HttpHeaders.Names.*; import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpHeaders.*; import static io.netty.handler.codec.http.HttpHeaders.*;
import static io.netty.handler.codec.http.HttpMethod.*; import static io.netty.handler.codec.http.HttpMethod.*;
@ -46,14 +43,13 @@ import static io.netty.handler.codec.http.HttpVersion.*;
* Handles handshakes and messages * Handles handshakes and messages
*/ */
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> { public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(WebSocketServerHandler.class.getName());
private static final String WEBSOCKET_PATH = "/websocket"; private static final String WEBSOCKET_PATH = "/websocket";
private WebSocketServerHandshaker handshaker; private WebSocketServerHandshaker handshaker;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof FullHttpRequest) { if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg); handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) { } else if (msg instanceof WebSocketFrame) {
@ -62,11 +58,11 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
// Handle a bad request. // Handle a bad request.
if (!req.getDecoderResult().isSuccess()) { if (!req.getDecoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
@ -125,9 +121,7 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
// Send the uppercase string back. // Send the uppercase string back.
String request = ((TextWebSocketFrame) frame).text(); String request = ((TextWebSocketFrame) frame).text();
if (logger.isLoggable(Level.FINE)) { System.err.printf("%s received %s%n", ctx.channel(), request);
logger.fine(String.format("%s received %s", ctx.channel(), request));
}
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase())); ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
} }
@ -149,12 +143,17 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.close(); ctx.close();
} }
private static String getWebSocketLocation(FullHttpRequest req) { private static String getWebSocketLocation(FullHttpRequest req) {
return "ws://" + req.headers().get(HOST) + WEBSOCKET_PATH; String location = req.headers().get(HOST) + WEBSOCKET_PATH;
if (WebSocketServer.SSL) {
return "wss://" + location;
} else {
return "ws://" + location;
}
} }
} }

View File

@ -20,15 +20,26 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;
/** /**
*/ */
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> { public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public WebSocketServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("codec-http", new HttpServerCodec()); if (sslCtx != null) {
pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); pipeline.addLast(sslCtx.newHandler(ch.alloc()));
pipeline.addLast("handler", new WebSocketServerHandler()); }
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerHandler());
} }
} }

View File

@ -1,92 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.sslserver;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.internal.SystemPropertyUtil;
/**
* A HTTP server which serves Web Socket requests at:
*
* https://localhost:8081/websocket
*
* Open your browser at https://localhost:8081/, then the demo page will be loaded and a Web Socket connection will be
* made automatically.
*
* This server illustrates support for the different web socket specification versions and will work with:
*
* <ul>
* <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00)
* <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00)
* <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10)
* <li>Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10)
* </ul>
*/
public class WebSocketSslServer {
private final int port;
public WebSocketSslServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WebSocketSslServerInitializer());
Channel ch = b.bind(port).sync().channel();
System.out.println("Web socket server started at port " + port + '.');
System.out.println("Open your browser and navigate to https://localhost:" + port + '/');
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8443;
}
String keyStoreFilePath = SystemPropertyUtil.get("keystore.file.path");
if (keyStoreFilePath == null || keyStoreFilePath.isEmpty()) {
System.out.println("ERROR: System property keystore.file.path not set. Exiting now!");
System.exit(1);
}
String keyStoreFilePassword = SystemPropertyUtil.get("keystore.file.password");
if (keyStoreFilePassword == null || keyStoreFilePassword.isEmpty()) {
System.out.println("ERROR: System property keystore.file.password not set. Exiting now!");
System.exit(1);
}
new WebSocketSslServer(port).run();
}
}

View File

@ -1,162 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.sslserver;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.example.http.websocketx.server.WebSocketServerIndexPage;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;
import java.util.logging.Level;
import java.util.logging.Logger;
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpHeaders.*;
import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
/**
* Handles handshakes and messages
*/
public class WebSocketSslServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(WebSocketSslServerHandler.class.getName());
private static final String WEBSOCKET_PATH = "/websocket";
private WebSocketServerHandshaker handshaker;
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
// Handle a bad request.
if (!req.getDecoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
return;
}
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the demo page and favicon.ico
if ("/".equals(req.getUri())) {
ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
setContentLength(res, content.readableBytes());
sendHttpResponse(ctx, req, res);
return;
}
if ("/favicon.ico".equals(req.getUri())) {
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
sendHttpResponse(ctx, req, res);
return;
}
// Handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
getWebSocketLocation(req), null, false);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), req);
}
}
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
// Check for closing frame
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
return;
}
if (frame instanceof PingWebSocketFrame) {
ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
return;
}
if (!(frame instanceof TextWebSocketFrame)) {
throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()
.getName()));
}
// Send the uppercase string back.
String request = ((TextWebSocketFrame) frame).text();
if (logger.isLoggable(Level.FINE)) {
logger.fine(String.format("%s received %s", ctx.channel(), request));
}
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
}
private static void sendHttpResponse(
ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
// Generate an error page if response getStatus code is not OK (200).
if (res.getStatus().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
setContentLength(res, res.content().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().write(res);
if (!isKeepAlive(req) || res.getStatus().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
private static String getWebSocketLocation(FullHttpRequest req) {
return "wss://" + req.headers().get(HOST) + WEBSOCKET_PATH;
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.sslserver;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLEngine;
/**
*/
public class WebSocketSslServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
SSLEngine engine = WebSocketSslServerSslContext.getInstance().serverContext().createSSLEngine();
engine.setUseClientMode(false);
pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("handler", new WebSocketSslServerHandler());
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.websocketx.sslserver;
import io.netty.util.internal.SystemPropertyUtil;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.Security;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Creates a {@link SSLContext} for just server certificates.
*/
public final class WebSocketSslServerSslContext {
private static final Logger logger = Logger.getLogger(WebSocketSslServerSslContext.class.getName());
private static final String PROTOCOL = "TLS";
private final SSLContext _serverContext;
/**
* Returns the singleton instance for this class
*/
public static WebSocketSslServerSslContext getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance() or the first access to
* SingletonHolder.INSTANCE, not before.
*
* See http://en.wikipedia.org/wiki/Singleton_pattern
*/
private interface SingletonHolder {
WebSocketSslServerSslContext INSTANCE = new WebSocketSslServerSslContext();
}
/**
* Constructor for singleton
*/
private WebSocketSslServerSslContext() {
SSLContext serverContext = null;
try {
// Key store (Server side certificate)
String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
try {
String keyStoreFilePath = SystemPropertyUtil.get("keystore.file.path");
String keyStoreFilePassword = SystemPropertyUtil.get("keystore.file.password");
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fin = new FileInputStream(keyStoreFilePath);
ks.load(fin, keyStoreFilePassword.toCharArray());
// Set up key manager factory to use our key store
// Assume key password is the same as the key store file
// password
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
kmf.init(ks, keyStoreFilePassword.toCharArray());
// Initialise the SSLContext to work with our key managers.
serverContext = SSLContext.getInstance(PROTOCOL);
serverContext.init(kmf.getKeyManagers(), null, null);
} catch (Exception e) {
throw new Error("Failed to initialize the server-side SSLContext", e);
}
} catch (Exception ex) {
logger.log(Level.WARNING, "Error initializing SslContextManager.", ex);
System.exit(1);
} finally {
_serverContext = serverContext;
}
}
/**
* Returns the server context with server side key store
*/
public SSLContext serverContext() {
return _serverContext;
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* <p>This package contains an example web socket web server with server SSL.
* <p>To run this example, follow the steps below:
* <dl>
* <dt>Step 1. Generate Your Key
* <dd>
* {@code keytool -genkey -keystore mySrvKeystore -keyalg RSA}.
* Make sure that you set the key password to be the same the key file password.
* <dt>Step 2. Specify your key store file and password as system properties
* <dd>
* {@code -Dkeystore.file.path=<path to mySrvKeystore> -Dkeystore.file.password=<password>}
* <dt>Step 3. Run WebSocketSslServer as a Java application
* <dd>
* Once started, you can test the web server against your browser by navigating to https://localhost:8081/
* </dl>
* <p>To find out more about setting up key stores, refer to this
* <a href="http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html">giude</a>.
*/
package io.netty.example.http.websocketx.sslserver;

View File

@ -14,8 +14,6 @@
*/ */
package io.netty.example.http2; package io.netty.example.http2;
import java.util.Locale;
/** /**
* Utility methods used by the example client and server. * Utility methods used by the example client and server.
*/ */
@ -26,74 +24,5 @@ public final class Http2ExampleUtil {
*/ */
public static final String UPGRADE_RESPONSE_HEADER = "Http-To-Http2-Upgrade"; public static final String UPGRADE_RESPONSE_HEADER = "Http-To-Http2-Upgrade";
public static final String STANDARD_HOST = "localhost"; private Http2ExampleUtil() { }
public static final int STANDARD_HTTP_PORT = 8080;
public static final int STANDARD_HTTPS_PORT = 8443;
public static final String PORT_ARG = "-port=";
public static final String SSL_ARG = "-ssl=";
public static final String HOST_ARG = "-host=";
/**
* The configuration for the example client/server endpoints.
*/
public static final class EndpointConfig {
private final boolean ssl;
private final String host;
private final int port;
public EndpointConfig(boolean ssl, String host, int port) {
this.ssl = ssl;
this.host = host;
this.port = port;
}
public boolean isSsl() {
return ssl;
}
public String host() {
return host;
}
public int port() {
return port;
}
@Override
public String toString() {
return "EndpointConfig [ssl=" + ssl + ", host=" + host + ", port=" + port + "]";
}
}
/**
* Parse the command-line arguments to determine the configuration for the endpoint.
*/
public static EndpointConfig parseEndpointConfig(String[] args) {
boolean ssl = false;
int port = STANDARD_HTTP_PORT;
String host = STANDARD_HOST;
boolean portSpecified = false;
for (String arg : args) {
arg = arg.trim().toLowerCase(Locale.US);
if (arg.startsWith(PORT_ARG)) {
String value = arg.substring(PORT_ARG.length());
port = Integer.parseInt(value);
portSpecified = true;
} else if (arg.startsWith(SSL_ARG)) {
String value = arg.substring(SSL_ARG.length());
ssl = Boolean.parseBoolean(value);
if (!portSpecified) {
// Use the appropriate default.
port = ssl ? STANDARD_HTTPS_PORT : STANDARD_HTTP_PORT;
}
} else if (arg.startsWith(HOST_ARG)) {
host = arg.substring(HOST_ARG.length());
}
}
return new EndpointConfig(ssl, host, port);
}
private Http2ExampleUtil() {
}
} }

View File

@ -23,16 +23,13 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol; import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import javax.net.ssl.SSLException;
import java.net.InetSocketAddress;
import java.util.Arrays; import java.util.Arrays;
import static io.netty.example.http2.Http2ExampleUtil.*;
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpMethod.*; import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpVersion.*; import static io.netty.handler.codec.http.HttpVersion.*;
@ -40,22 +37,17 @@ import static io.netty.handler.codec.http.HttpVersion.*;
* An HTTP2 client that allows you to send HTTP2 frames to a server. Inbound and outbound frames are * An HTTP2 client that allows you to send HTTP2 frames to a server. Inbound and outbound frames are
* logged. When run from the command-line, sends a single HEADERS frame to the server and gets back * logged. When run from the command-line, sends a single HEADERS frame to the server and gets back
* a "Hello World" response. * a "Hello World" response.
* <p>
* To client accepts command-line arguments for {@code -host=<host/ip>}
* <i>(default="localhost")</i>, {@code -port=<port number>} <i>(default: http=8080,
* https=8443)</i>, and {@code -ssl=<true/false>} <i>(default=false)</i>.
*/ */
public class Http2Client { public final class Http2Client {
private final SslContext sslCtx; static final boolean SSL = System.getProperty("ssl") != null;
private final EndpointConfig config; static final String HOST = System.getProperty("host", "127.0.0.1");
private Http2ClientConnectionHandler http2ConnectionHandler; static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
private Channel channel;
private EventLoopGroup workerGroup;
public Http2Client(EndpointConfig config) throws SSLException { public static void main(String[] args) throws Exception {
this.config = config; // Configure SSL.
if (config.isSsl()) { final SslContext sslCtx;
if (SSL) {
sslCtx = SslContext.newClientContext( sslCtx = SslContext.newClientContext(
null, InsecureTrustManagerFactory.INSTANCE, null, null, InsecureTrustManagerFactory.INSTANCE, null,
Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()), Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
@ -63,96 +55,45 @@ public class Http2Client {
} else { } else {
sslCtx = null; sslCtx = null;
} }
}
/** EventLoopGroup workerGroup = new NioEventLoopGroup();
* Starts the client and waits for the HTTP/2 upgrade to occur.
*/
public void start() throws Exception {
if (channel != null) {
System.out.println("Already running!");
return;
}
workerGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.remoteAddress(new InetSocketAddress(config.host(), config.port()));
Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx); Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx);
b.handler(initializer);
// Start the client.
channel = b.connect().syncUninterruptibly().channel();
System.out.println("Connected to [" + config.host() + ':' + config.port() + ']');
// Wait for the HTTP/2 upgrade to occur.
http2ConnectionHandler = initializer.connectionHandler();
http2ConnectionHandler.awaitInitialization();
}
/**
* Sends the given request to the server.
*/
public void sendRequest(FullHttpRequest request) throws Exception {
ChannelFuture requestFuture = channel.writeAndFlush(request).sync();
System.out.println("Back from sending headers...");
if (!requestFuture.isSuccess()) {
throw new RuntimeException(requestFuture.cause());
}
}
/**
* Waits for the full response to be received.
*/
public void awaitResponse() throws Exception {
http2ConnectionHandler.awaitResponse();
}
/**
* Closes the channel and waits for shutdown to complete.
*/
public void stop() {
try { try {
// Wait until the connection is closed. // Configure the client.
channel.close().syncUninterruptibly(); Bootstrap b = new Bootstrap();
} finally { b.group(workerGroup);
if (workerGroup != null) { b.channel(NioSocketChannel.class);
workerGroup.shutdownGracefully(); b.option(ChannelOption.SO_KEEPALIVE, true);
} b.remoteAddress(HOST, PORT);
} b.handler(initializer);
}
public static void main(String[] args) throws Exception { // Start the client.
EndpointConfig config = parseEndpointConfig(args); Channel channel = b.connect().syncUninterruptibly().channel();
System.out.println(config); System.out.println("Connected to [" + HOST + ':' + PORT + ']');
final Http2Client client = new Http2Client(config); // Wait for the HTTP/2 upgrade to occur.
try { Http2ClientConnectionHandler http2ConnectionHandler = initializer.connectionHandler();
// Start the client and wait for the HTTP/2 upgrade to complete. http2ConnectionHandler.awaitInitialization();
client.start();
// Create a simple GET request with just headers. // Create a simple GET request with just headers.
FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/whatever"); FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/whatever");
request.headers().add(HOST, config.host()); request.headers().add(HttpHeaders.Names.HOST, HOST + ':' + PORT);
System.out.println("Sending request..."); // Send the request to the server.
ChannelFuture requestFuture = client.channel.writeAndFlush(request).sync(); System.err.println("Sending request...");
System.out.println("Back from sending headers..."); ChannelFuture requestFuture = channel.writeAndFlush(request).sync();
if (!requestFuture.isSuccess()) { System.err.println("Back from sending headers...");
requestFuture.cause().printStackTrace(); requestFuture.sync();
return;
}
// Waits for the complete response // Waits for the complete response
client.awaitResponse(); http2ConnectionHandler.awaitResponse();
System.out.println("Finished HTTP/2 request"); System.out.println("Finished HTTP/2 request");
} catch (Throwable t) {
t.printStackTrace(); // Wait until the connection is closed.
channel.close().syncUninterruptibly();
} finally { } finally {
client.stop(); workerGroup.shutdownGracefully();
} }
} }
} }

View File

@ -14,8 +14,6 @@
*/ */
package io.netty.example.http2.client; package io.netty.example.http2.client;
import static io.netty.example.http2.Http2ExampleUtil.UPGRADE_RESPONSE_HEADER;
import static io.netty.util.internal.logging.InternalLogLevel.INFO;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
@ -41,13 +39,18 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static io.netty.example.http2.Http2ExampleUtil.*;
import static io.netty.util.internal.logging.InternalLogLevel.*;
/** /**
* A subclass of the connection handler that interprets response messages as text and prints it out * A subclass of the connection handler that interprets response messages as text and prints it out
* to the console. * to the console.
*/ */
public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler { public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler {
private static final Http2FrameLogger logger = new Http2FrameLogger(INFO,
InternalLoggerFactory.getInstance(Http2ClientConnectionHandler.class)); private static final Http2FrameLogger logger =
new Http2FrameLogger(INFO, InternalLoggerFactory.getInstance(Http2ClientConnectionHandler.class));
private final ChannelPromise initPromise; private final ChannelPromise initPromise;
private final ChannelPromise responsePromise; private final ChannelPromise responsePromise;
private ByteBuf collectedData; private ByteBuf collectedData;
@ -88,8 +91,7 @@ public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler
* Handles conversion of a {@link FullHttpMessage} to HTTP/2 frames. * Handles conversion of a {@link FullHttpMessage} to HTTP/2 frames.
*/ */
@Override @Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
throws Exception {
if (msg instanceof FullHttpMessage) { if (msg instanceof FullHttpMessage) {
FullHttpMessage httpMsg = (FullHttpMessage) msg; FullHttpMessage httpMsg = (FullHttpMessage) msg;
boolean hasData = httpMsg.content().isReadable(); boolean hasData = httpMsg.content().isReadable();
@ -105,7 +107,7 @@ public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler
writeData(ctx, promise, streamId, httpMsg.content(), 0, true, true, false); writeData(ctx, promise, streamId, httpMsg.content(), 0, true, true, false);
} }
} else { } else {
super.write(ctx, msg, promise); ctx.write(msg, promise);
} }
} }
@ -170,8 +172,7 @@ public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler
} }
@Override @Override
public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
throws Http2Exception {
if (!initPromise.isDone()) { if (!initPromise.isDone()) {
initPromise.setSuccess(); initPromise.setSuccess();
} }

View File

@ -56,7 +56,8 @@ public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequ
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.close();
} }
} }

View File

@ -15,8 +15,6 @@
package io.netty.example.http2.server; package io.netty.example.http2.server;
import static io.netty.example.http2.Http2ExampleUtil.UPGRADE_RESPONSE_HEADER;
import static io.netty.util.internal.logging.InternalLogLevel.INFO;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.example.http2.client.Http2ClientConnectionHandler; import io.netty.example.http2.client.Http2ClientConnectionHandler;
@ -37,6 +35,9 @@ import io.netty.handler.codec.http2.Http2Settings;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import static io.netty.example.http2.Http2ExampleUtil.*;
import static io.netty.util.internal.logging.InternalLogLevel.*;
/** /**
* A simple handler that responds with the message "Hello World!". * A simple handler that responds with the message "Hello World!".
*/ */
@ -84,7 +85,7 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
*/ */
@Override @Override
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, public void onHeadersRead(ChannelHandlerContext ctx, int streamId,
io.netty.handler.codec.http2.Http2Headers headers, int padding, boolean endStream, Http2Headers headers, int padding, boolean endStream,
boolean endSegment) throws Http2Exception { boolean endSegment) throws Http2Exception {
if (endStream) { if (endStream) {
sendResponse(ctx(), streamId); sendResponse(ctx(), streamId);
@ -96,7 +97,7 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
*/ */
@Override @Override
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, public void onHeadersRead(ChannelHandlerContext ctx, int streamId,
io.netty.handler.codec.http2.Http2Headers headers, int streamDependency, short weight, Http2Headers headers, int streamDependency, short weight,
boolean exclusive, int padding, boolean endStream, boolean endSegment) boolean exclusive, int padding, boolean endStream, boolean endSegment)
throws Http2Exception { throws Http2Exception {
if (endStream) { if (endStream) {
@ -133,7 +134,7 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
@Override @Override
public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId, public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
io.netty.handler.codec.http2.Http2Headers headers, int padding) throws Http2Exception { Http2Headers headers, int padding) throws Http2Exception {
} }
@Override @Override
@ -156,15 +157,15 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
super.exceptionCaught(ctx, cause); ctx.close();
} }
/** /**
* Sends a "Hello World" DATA frame to the client. * Sends a "Hello World" DATA frame to the client.
*/ */
private void sendResponse(ChannelHandlerContext ctx, int streamId) throws Http2Exception { private void sendResponse(ChannelHandlerContext ctx, int streamId) {
// Send a frame for the response status // Send a frame for the response status
Http2Headers headers = DefaultHttp2Headers.newBuilder().status("200").build(); Http2Headers headers = DefaultHttp2Headers.newBuilder().status("200").build();
writeHeaders(ctx(), ctx().newPromise(), streamId, headers, 0, false, false); writeHeaders(ctx(), ctx().newPromise(), streamId, headers, 0, false, false);

View File

@ -18,14 +18,12 @@ import io.netty.channel.ChannelHandler;
import io.netty.handler.codec.http2.Http2OrHttpChooser; import io.netty.handler.codec.http2.Http2OrHttpChooser;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
import java.util.logging.Logger;
/** /**
* Negotiates with the browser if HTTP2 or HTTP is going to be used. Once decided, the Netty * Negotiates with the browser if HTTP2 or HTTP is going to be used. Once decided, the Netty
* pipeline is setup with the correct handlers for the selected protocol. * pipeline is setup with the correct handlers for the selected protocol.
*/ */
public class Http2OrHttpHandler extends Http2OrHttpChooser { public class Http2OrHttpHandler extends Http2OrHttpChooser {
private static final Logger logger = Logger.getLogger(Http2OrHttpHandler.class.getName());
private static final int MAX_CONTENT_LENGTH = 1024 * 100; private static final int MAX_CONTENT_LENGTH = 1024 * 100;
public Http2OrHttpHandler() { public Http2OrHttpHandler() {
@ -40,8 +38,7 @@ public class Http2OrHttpHandler extends Http2OrHttpChooser {
protected SelectedProtocol getProtocol(SSLEngine engine) { protected SelectedProtocol getProtocol(SSLEngine engine) {
String[] protocol = engine.getSession().getProtocol().split(":"); String[] protocol = engine.getSession().getProtocol().split(":");
SelectedProtocol selectedProtocol = SelectedProtocol.protocol(protocol[1]); SelectedProtocol selectedProtocol = SelectedProtocol.protocol(protocol[1]);
System.err.println("Selected Protocol is " + selectedProtocol);
logger.info("Selected Protocol is " + selectedProtocol);
return selectedProtocol; return selectedProtocol;
} }

View File

@ -16,15 +16,15 @@
package io.netty.example.http2.server; package io.netty.example.http2.server;
import static io.netty.example.http2.Http2ExampleUtil.parseEndpointConfig;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.example.http2.Http2ExampleUtil.EndpointConfig;
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol; import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate; import io.netty.handler.ssl.util.SelfSignedCertificate;
@ -33,54 +33,46 @@ import java.util.Arrays;
/** /**
* A HTTP/2 Server that responds to requests with a Hello World. Once started, you can test the * A HTTP/2 Server that responds to requests with a Hello World. Once started, you can test the
* server with the example client. * server with the example client.
* <p>
* To server accepts command-line arguments for {@code -port=<port number>} <i>(default: http=8080,
* https=8443)</i>, and {@code -ssl=<true/false>} <i>(default=false)</i>.
*/ */
public class Http2Server { public final class Http2Server {
private final EndpointConfig config; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public Http2Server(EndpointConfig config) { public static void main(String[] args) throws Exception {
this.config = config; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
public void run() throws Exception { SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(
ssc.certificate(), ssc.privateKey(), null, null,
Arrays.asList(
SelectedProtocol.HTTP_2.protocolName(),
SelectedProtocol.HTTP_1_1.protocolName()),
0, 0);
} else {
sslCtx = null;
}
// Configure the server. // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024); b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new Http2ServerInitializer(sslCtx));
// If SSL was selected, configure the SSL context. Channel ch = b.bind(PORT).sync().channel();
SslContext sslCtx = null;
if (config.isSsl()) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(
ssc.certificate(), ssc.privateKey(), null, null,
Arrays.asList(
SelectedProtocol.HTTP_2.protocolName(),
SelectedProtocol.HTTP_1_1.protocolName()),
0, 0);
}
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) System.err.println("Open your HTTP/2-enabled web browser and navigate to " +
.childHandler(new Http2ServerInitializer(sslCtx)); (SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
Channel ch = b.bind(config.port()).sync().channel();
ch.closeFuture().sync(); ch.closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
EndpointConfig config = parseEndpointConfig(args);
System.out.println(config);
System.out.println("HTTP2 server started at port " + config.port() + '.');
new Http2Server(config).run();
}
} }

View File

@ -20,7 +20,6 @@ import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerAppender; import io.netty.channel.ChannelHandlerAppender;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpRequestDecoder;
@ -29,7 +28,7 @@ import io.netty.handler.codec.http.HttpServerUpgradeHandler;
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec; import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import java.util.Arrays; import java.util.Collections;
/** /**
* Sets up the Netty pipeline for the example server. Depending on the endpoint config, sets up the * Sets up the Netty pipeline for the example server. Depending on the endpoint config, sets up the
@ -43,7 +42,7 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
} }
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
if (sslCtx != null) { if (sslCtx != null) {
configureSsl(ch); configureSsl(ch);
} else { } else {
@ -61,12 +60,12 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
/** /**
* Configure the pipeline for a cleartext upgrade from HTTP to HTTP/2. * Configure the pipeline for a cleartext upgrade from HTTP to HTTP/2.
*/ */
private void configureClearText(SocketChannel ch) { private static void configureClearText(SocketChannel ch) {
HttpCodec sourceCodec = new HttpCodec(); HttpCodec sourceCodec = new HttpCodec();
HttpServerUpgradeHandler.UpgradeCodec upgradeCodec = HttpServerUpgradeHandler.UpgradeCodec upgradeCodec =
new Http2ServerUpgradeCodec(new HelloWorldHttp2Handler()); new Http2ServerUpgradeCodec(new HelloWorldHttp2Handler());
HttpServerUpgradeHandler upgradeHandler = HttpServerUpgradeHandler upgradeHandler =
new HttpServerUpgradeHandler(sourceCodec, Arrays.asList(upgradeCodec), 65536); new HttpServerUpgradeHandler(sourceCodec, Collections.singletonList(upgradeCodec), 65536);
ch.pipeline().addLast(sourceCodec); ch.pipeline().addLast(sourceCodec);
ch.pipeline().addLast(upgradeHandler); ch.pipeline().addLast(upgradeHandler);
@ -76,8 +75,8 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
/** /**
* Source codec for HTTP cleartext upgrade. * Source codec for HTTP cleartext upgrade.
*/ */
private static final class HttpCodec extends ChannelHandlerAppender implements private static final class HttpCodec
HttpServerUpgradeHandler.SourceCodec { extends ChannelHandlerAppender implements HttpServerUpgradeHandler.SourceCodec {
HttpCodec() { HttpCodec() {
add("httpRequestDecoder", new HttpRequestDecoder()); add("httpRequestDecoder", new HttpRequestDecoder());
add("httpResponseEncoder", new HttpResponseEncoder()); add("httpResponseEncoder", new HttpResponseEncoder());
@ -98,9 +97,9 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
*/ */
private static class UserEventLogger extends ChannelHandlerAdapter { private static class UserEventLogger extends ChannelHandlerAdapter {
@Override @Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
System.out.println("User Event Triggered: " + evt); System.out.println("User Event Triggered: " + evt);
super.userEventTriggered(ctx, evt); ctx.fireUserEventTriggered(evt);
} }
} }
} }

View File

@ -32,17 +32,13 @@ import io.netty.handler.logging.LoggingHandler;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
public class LocalEcho { public final class LocalEcho {
private final String port; static final String PORT = System.getProperty("port", "test_port");
public LocalEcho(String port) { public static void main(String[] args) throws Exception {
this.port = port;
}
public void run() throws Exception {
// Address to bind on / connect to. // Address to bind on / connect to.
final LocalAddress addr = new LocalAddress(port); final LocalAddress addr = new LocalAddress(PORT);
EventLoopGroup serverGroup = new DefaultEventLoopGroup(); EventLoopGroup serverGroup = new DefaultEventLoopGroup();
EventLoopGroup clientGroup = new NioEventLoopGroup(); // NIO event loops are also OK EventLoopGroup clientGroup = new NioEventLoopGroup(); // NIO event loops are also OK
@ -109,8 +105,4 @@ public class LocalEcho {
clientGroup.shutdownGracefully(); clientGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
new LocalEcho("1").run();
}
} }

View File

@ -21,7 +21,7 @@ import io.netty.channel.SimpleChannelInboundHandler;
public class LocalEchoClientHandler extends SimpleChannelInboundHandler<Object> { public class LocalEchoClientHandler extends SimpleChannelInboundHandler<Object> {
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, Object msg) {
// Print as received // Print as received
System.out.println(msg); System.out.println(msg);
} }

View File

@ -18,17 +18,16 @@ package io.netty.example.localecho;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
public class LocalEchoServerHandler extends ChannelHandlerAdapter { public class LocalEchoServerHandler extends ChannelHandlerAdapter {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
// Write back as received // Write back as received
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }

View File

@ -24,26 +24,37 @@ import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
import io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec; import io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec;
import io.netty.handler.codec.memcache.binary.BinaryMemcacheObjectAggregator; import io.netty.handler.codec.memcache.binary.BinaryMemcacheObjectAggregator;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Arrays;
/** /**
* Simple memcache client that demonstrates get and set commands against a memcache server. * Simple memcache client that demonstrates get and set commands against a memcache server.
*/ */
public class MemcacheClient { public final class MemcacheClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "11211"));
public MemcacheClient(String host, int port) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
} if (SSL) {
sslCtx = SslContext.newClientContext(
null, InsecureTrustManagerFactory.INSTANCE, null,
Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
0, 0);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
@ -53,6 +64,9 @@ public class MemcacheClient {
@Override @Override
protected void initChannel(SocketChannel ch) throws Exception { protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
p.addLast(new BinaryMemcacheClientCodec()); p.addLast(new BinaryMemcacheClientCodec());
p.addLast(new BinaryMemcacheObjectAggregator(Integer.MAX_VALUE)); p.addLast(new BinaryMemcacheObjectAggregator(Integer.MAX_VALUE));
p.addLast(new MemcacheClientHandler()); p.addLast(new MemcacheClientHandler());
@ -60,7 +74,7 @@ public class MemcacheClient {
}); });
// Start the connection attempt. // Start the connection attempt.
Channel ch = b.connect(host, port).sync().channel(); Channel ch = b.connect(HOST, PORT).sync().channel();
// Read commands from the stdin. // Read commands from the stdin.
System.out.println("Enter commands (quit to end)"); System.out.println("Enter commands (quit to end)");
@ -89,20 +103,4 @@ public class MemcacheClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length != 2) {
System.err.println(
"Usage: " + MemcacheClient.class.getSimpleName() +
" <host> <port>");
return;
}
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
new MemcacheClient(host, port).run();
}
} }

View File

@ -33,7 +33,7 @@ public class MemcacheClientHandler extends ChannelHandlerAdapter {
* Transforms basic string requests to binary memcache requests * Transforms basic string requests to binary memcache requests
*/ */
@Override @Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
String command = (String) msg; String command = (String) msg;
if (command.startsWith("get ")) { if (command.startsWith("get ")) {
String key = command.substring("get ".length()); String key = command.substring("get ".length());
@ -68,13 +68,13 @@ public class MemcacheClientHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
FullBinaryMemcacheResponse res = (FullBinaryMemcacheResponse) msg; FullBinaryMemcacheResponse res = (FullBinaryMemcacheResponse) msg;
System.out.println(res.content().toString(CharsetUtil.UTF_8)); System.out.println(res.content().toString(CharsetUtil.UTF_8));
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.close(); ctx.close();
} }

View File

@ -17,6 +17,7 @@ package io.netty.example.objectecho;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
@ -25,23 +26,28 @@ import io.netty.example.echo.EchoClient;
import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder; import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/** /**
* Modification of {@link EchoClient} which utilizes Java object serialization. * Modification of {@link EchoClient} which utilizes Java object serialization.
*/ */
public class ObjectEchoClient { public final class ObjectEchoClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int firstMessageSize; static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public ObjectEchoClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.firstMessageSize = firstMessageSize; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
@ -50,40 +56,21 @@ public class ObjectEchoClient {
.handler(new ChannelInitializer<SocketChannel>() { .handler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast( ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
p.addLast(
new ObjectEncoder(), new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)), new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoClientHandler(firstMessageSize)); new ObjectEchoClientHandler());
} }
}); });
// Start the connection attempt. // Start the connection attempt.
b.connect(host, port).sync().channel().closeFuture().sync(); b.connect(HOST, PORT).sync().channel().closeFuture().sync();
} finally { } finally {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + ObjectEchoClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
}
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new ObjectEchoClient(host, port, firstMessageSize).run();
}
} }

View File

@ -20,8 +20,6 @@ import io.netty.channel.ChannelHandlerContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler implementation for the object echo client. It initiates the * Handler implementation for the object echo client. It initiates the
@ -30,48 +28,38 @@ import java.util.logging.Logger;
*/ */
public class ObjectEchoClientHandler extends ChannelHandlerAdapter { public class ObjectEchoClientHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(
ObjectEchoClientHandler.class.getName());
private final List<Integer> firstMessage; private final List<Integer> firstMessage;
/** /**
* Creates a client-side handler. * Creates a client-side handler.
*/ */
public ObjectEchoClientHandler(int firstMessageSize) { public ObjectEchoClientHandler() {
if (firstMessageSize <= 0) { firstMessage = new ArrayList<Integer>(ObjectEchoClient.SIZE);
throw new IllegalArgumentException( for (int i = 0; i < ObjectEchoClient.SIZE; i ++) {
"firstMessageSize: " + firstMessageSize);
}
firstMessage = new ArrayList<Integer>(firstMessageSize);
for (int i = 0; i < firstMessageSize; i ++) {
firstMessage.add(Integer.valueOf(i)); firstMessage.add(Integer.valueOf(i));
} }
} }
@Override @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) {
// Send the first message if this handler is a client-side handler. // Send the first message if this handler is a client-side handler.
ctx.writeAndFlush(firstMessage); ctx.writeAndFlush(firstMessage);
} }
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
// Echo back the received object to the server. // Echo back the received object to the server.
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close(); ctx.close();
} }
} }

View File

@ -17,6 +17,7 @@ package io.netty.example.objectecho;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
@ -25,29 +26,44 @@ import io.netty.example.echo.EchoServer;
import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder; import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
/** /**
* Modification of {@link EchoServer} which utilizes Java object serialization. * Modification of {@link EchoServer} which utilizes Java object serialization.
*/ */
public class ObjectEchoServer { public final class ObjectEchoServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public ObjectEchoServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast( ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(
new ObjectEncoder(), new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)), new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoServerHandler()); new ObjectEchoServerHandler());
@ -55,20 +71,10 @@ public class ObjectEchoServer {
}); });
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
b.bind(port).sync().channel().closeFuture().sync(); b.bind(PORT).sync().channel().closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new ObjectEchoServer(port).run();
}
} }

View File

@ -18,36 +18,26 @@ package io.netty.example.objectecho;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handles both client-side and server-side handler depending on which * Handles both client-side and server-side handler depending on which
* constructor was called. * constructor was called.
*/ */
public class ObjectEchoServerHandler extends ChannelHandlerAdapter { public class ObjectEchoServerHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(
ObjectEchoServerHandler.class.getName());
@Override @Override
public void channelRead( public void channelRead(ChannelHandlerContext ctx, Object msg) {
ChannelHandlerContext ctx, Object msg) throws Exception {
// Echo back the received object to the client. // Echo back the received object to the client.
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close(); ctx.close();
} }
} }

View File

@ -21,6 +21,8 @@ import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate; import io.netty.handler.ssl.util.SelfSignedCertificate;
@ -31,23 +33,22 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
* Because SSL and GZIP are enabled on demand, 5 combinations per protocol * Because SSL and GZIP are enabled on demand, 5 combinations per protocol
* are possible: none, SSL only, GZIP only, SSL + GZIP, and GZIP + SSL. * are possible: none, SSL only, GZIP only, SSL + GZIP, and GZIP + SSL.
*/ */
public class PortUnificationServer { public final class PortUnificationServer {
private final SslContext sslCtx; static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
private final int port;
public PortUnificationServer(SslContext sslCtx, int port) { public static void main(String[] args) throws Exception {
this.sslCtx = sslCtx; // Configure SSL context
this.port = port; SelfSignedCertificate ssc = new SelfSignedCertificate();
} final SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { try {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
@ -56,25 +57,10 @@ public class PortUnificationServer {
}); });
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
b.bind(port).sync().channel().closeFuture().sync(); b.bind(PORT).sync().channel().closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
// Configure SSL.
SelfSignedCertificate ssc = new SelfSignedCertificate();
SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
new PortUnificationServer(sslCtx, port).run();
}
} }

View File

@ -20,23 +20,17 @@ import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class HexDumpProxy { public final class HexDumpProxy {
private final int localPort; static final int LOCAL_PORT = Integer.parseInt(System.getProperty("localPort", "8443"));
private final String remoteHost; static final String REMOTE_HOST = System.getProperty("remoteHost", "www.google.com");
private final int remotePort; static final int REMOTE_PORT = Integer.parseInt(System.getProperty("remotePort", "443"));
public HexDumpProxy(int localPort, String remoteHost, int remotePort) { public static void main(String[] args) throws Exception {
this.localPort = localPort; System.err.println("Proxying *:" + LOCAL_PORT + " to " + REMOTE_HOST + ':' + REMOTE_PORT + " ...");
this.remoteHost = remoteHost;
this.remotePort = remotePort;
}
public void run() throws Exception {
System.err.println(
"Proxying *:" + localPort + " to " +
remoteHost + ':' + remotePort + " ...");
// Configure the bootstrap. // Configure the bootstrap.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
@ -45,29 +39,13 @@ public class HexDumpProxy {
ServerBootstrap b = new ServerBootstrap(); ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup) b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.childHandler(new HexDumpProxyInitializer(remoteHost, remotePort)) .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HexDumpProxyInitializer(REMOTE_HOST, REMOTE_PORT))
.childOption(ChannelOption.AUTO_READ, false) .childOption(ChannelOption.AUTO_READ, false)
.bind(localPort).sync().channel().closeFuture().sync(); .bind(LOCAL_PORT).sync().channel().closeFuture().sync();
} finally { } finally {
bossGroup.shutdownGracefully(); bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Validate command line options.
if (args.length != 3) {
System.err.println(
"Usage: " + HexDumpProxy.class.getSimpleName() +
" <local port> <remote host> <remote port>");
return;
}
// Parse command line options.
int localPort = Integer.parseInt(args[0]);
String remoteHost = args[1];
int remotePort = Integer.parseInt(args[2]);
new HexDumpProxy(localPort, remoteHost, remotePort).run();
}
} }

View File

@ -31,16 +31,16 @@ public class HexDumpProxyBackendHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) {
ctx.read(); ctx.read();
ctx.write(Unpooled.EMPTY_BUFFER); ctx.write(Unpooled.EMPTY_BUFFER);
} }
@Override @Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(final ChannelHandlerContext ctx, Object msg) {
inboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() { inboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { if (future.isSuccess()) {
ctx.channel().read(); ctx.channel().read();
} else { } else {
@ -51,12 +51,12 @@ public class HexDumpProxyBackendHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) {
HexDumpProxyFrontendHandler.closeOnFlush(inboundChannel); HexDumpProxyFrontendHandler.closeOnFlush(inboundChannel);
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
HexDumpProxyFrontendHandler.closeOnFlush(ctx.channel()); HexDumpProxyFrontendHandler.closeOnFlush(ctx.channel());
} }

View File

@ -37,7 +37,7 @@ public class HexDumpProxyFrontendHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) {
final Channel inboundChannel = ctx.channel(); final Channel inboundChannel = ctx.channel();
// Start the connection attempt. // Start the connection attempt.
@ -50,7 +50,7 @@ public class HexDumpProxyFrontendHandler extends ChannelHandlerAdapter {
outboundChannel = f.channel(); outboundChannel = f.channel();
f.addListener(new ChannelFutureListener() { f.addListener(new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { if (future.isSuccess()) {
// connection complete start to read first data // connection complete start to read first data
inboundChannel.read(); inboundChannel.read();
@ -63,11 +63,11 @@ public class HexDumpProxyFrontendHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(final ChannelHandlerContext ctx, Object msg) {
if (outboundChannel.isActive()) { if (outboundChannel.isActive()) {
outboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() { outboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { if (future.isSuccess()) {
// was able to flush out data, start to read the next chunk // was able to flush out data, start to read the next chunk
ctx.channel().read(); ctx.channel().read();
@ -80,14 +80,14 @@ public class HexDumpProxyFrontendHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) {
if (outboundChannel != null) { if (outboundChannel != null) {
closeOnFlush(outboundChannel); closeOnFlush(outboundChannel);
} }
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
closeOnFlush(ctx.channel()); closeOnFlush(ctx.channel());
} }

View File

@ -31,7 +31,7 @@ public class HexDumpProxyInitializer extends ChannelInitializer<SocketChannel> {
} }
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) {
ch.pipeline().addLast( ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO), new LoggingHandler(LogLevel.INFO),
new HexDumpProxyFrontendHandler(remoteHost, remotePort)); new HexDumpProxyFrontendHandler(remoteHost, remotePort));

View File

@ -28,20 +28,17 @@ import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
/** /**
* A UDP broadcast client that asks for a quote of the moment (QOTM) to * A UDP broadcast client that asks for a quote of the moment (QOTM) to {@link QuoteOfTheMomentServer}.
* {@link QuoteOfTheMomentServer}.
* *
* Inspired by <a href="http://goo.gl/BsXVR">the official Java tutorial</a>. * Inspired by <a href="http://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html">the official
* Java tutorial</a>.
*/ */
public class QuoteOfTheMomentClient { public final class QuoteOfTheMomentClient {
private final int port; static final int PORT = Integer.parseInt(System.getProperty("port", "7686"));
public QuoteOfTheMomentClient(int port) { public static void main(String[] args) throws Exception {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
@ -55,7 +52,7 @@ public class QuoteOfTheMomentClient {
// Broadcast the QOTM request to port 8080. // Broadcast the QOTM request to port 8080.
ch.writeAndFlush(new DatagramPacket( ch.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8), Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
new InetSocketAddress("255.255.255.255", port))).sync(); new InetSocketAddress("255.255.255.255", PORT))).sync();
// QuoteOfTheMomentClientHandler will close the DatagramChannel when a // QuoteOfTheMomentClientHandler will close the DatagramChannel when a
// response is received. If the channel is not closed within 5 seconds, // response is received. If the channel is not closed within 5 seconds,
@ -67,14 +64,4 @@ public class QuoteOfTheMomentClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new QuoteOfTheMomentClient(port).run();
}
} }

View File

@ -23,7 +23,7 @@ import io.netty.util.CharsetUtil;
public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> { public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) {
String response = msg.content().toString(CharsetUtil.UTF_8); String response = msg.content().toString(CharsetUtil.UTF_8);
if (response.startsWith("QOTM: ")) { if (response.startsWith("QOTM: ")) {
System.out.println("Quote of the Moment: " + response.substring(6)); System.out.println("Quote of the Moment: " + response.substring(6));
@ -32,7 +32,7 @@ public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<D
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace(); cause.printStackTrace();
ctx.close(); ctx.close();
} }

View File

@ -22,20 +22,16 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel;
/** /**
* A UDP server that responds to the QOTM (quote of the moment) request to a * A UDP server that responds to the QOTM (quote of the moment) request to a {@link QuoteOfTheMomentClient}.
* {@link QuoteOfTheMomentClient}.
* *
* Inspired by <a href="http://goo.gl/BsXVR">the official Java tutorial</a>. * Inspired by <a href="http://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html">the official
* Java tutorial</a>.
*/ */
public class QuoteOfTheMomentServer { public final class QuoteOfTheMomentServer {
private final int port; private static final int PORT = Integer.parseInt(System.getProperty("port", "7686"));
public QuoteOfTheMomentServer(int port) { public static void main(String[] args) throws Exception {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
@ -44,19 +40,9 @@ public class QuoteOfTheMomentServer {
.option(ChannelOption.SO_BROADCAST, true) .option(ChannelOption.SO_BROADCAST, true)
.handler(new QuoteOfTheMomentServerHandler()); .handler(new QuoteOfTheMomentServerHandler());
b.bind(port).sync().channel().closeFuture().await(); b.bind(PORT).sync().channel().closeFuture().await();
} finally { } finally {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new QuoteOfTheMomentServer(port).run();
}
} }

View File

@ -44,7 +44,7 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelInboundHandler<D
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { public void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet) {
System.err.println(packet); System.err.println(packet);
if ("QOTM?".equals(packet.content().toString(CharsetUtil.UTF_8))) { if ("QOTM?".equals(packet.content().toString(CharsetUtil.UTF_8))) {
ctx.write(new DatagramPacket( ctx.write(new DatagramPacket(
@ -53,14 +53,12 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelInboundHandler<D
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace(); cause.printStackTrace();
// We don't close the channel because we can keep serving requests. // We don't close the channel because we can keep serving requests.
} }

View File

@ -31,6 +31,8 @@ import io.netty.handler.codec.string.StringEncoder;
*/ */
public final class RxtxClient { public final class RxtxClient {
static final String PORT = System.getProperty("port", "/dev/ttyUSB0");
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
EventLoopGroup group = new OioEventLoopGroup(); EventLoopGroup group = new OioEventLoopGroup();
try { try {
@ -49,14 +51,11 @@ public final class RxtxClient {
} }
}); });
ChannelFuture f = b.connect(new RxtxDeviceAddress("/dev/ttyUSB0")).sync(); ChannelFuture f = b.connect(new RxtxDeviceAddress(PORT)).sync();
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
} finally { } finally {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
private RxtxClient() {
}
} }

View File

@ -26,7 +26,7 @@ public class RxtxClientHandler extends SimpleChannelInboundHandler<String> {
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, String msg) {
if ("OK".equals(msg)) { if ("OK".equals(msg)) {
System.out.println("Serial port responded to AT"); System.out.println("Serial port responded to AT");
} else { } else {

View File

@ -1,98 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.sctp;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.sctp.SctpChannel;
import io.netty.channel.sctp.SctpChannelOption;
import io.netty.channel.sctp.oio.OioSctpChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* Sends one message when a connection is open and echoes back any received
* data to the server over SCTP connection.
*
* Simply put, the echo client initiates the ping-pong
* traffic between the echo client and server by sending the first message to
* the server.
*/
public class OioSctpEchoClient {
private final String host;
private final int port;
private final int firstMessageSize;
public OioSctpEchoClient(String host, int port, int firstMessageSize) {
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public void run() throws Exception {
// Configure the client.
EventLoopGroup group = new OioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(OioSctpChannel.class)
.option(SctpChannelOption.SCTP_NODELAY, true)
.handler(new ChannelInitializer<SctpChannel>() {
@Override
public void initChannel(SctpChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
new SctpEchoClientHandler(firstMessageSize));
}
});
// Start the client.
ChannelFuture f = b.connect(host, port).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down the event loop to terminate all threads.
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + OioSctpEchoClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
}
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new OioSctpEchoClient(host, port, firstMessageSize).run();
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.sctp;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.sctp.SctpChannel;
import io.netty.channel.sctp.oio.OioSctpServerChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* Echoes back any received data from a SCTP client.
*/
public class OioSctpEchoServer {
private final int port;
public OioSctpEchoServer(int port) {
this.port = port;
}
public void run() throws Exception {
// Configure the server.
EventLoopGroup bossGroup = new OioEventLoopGroup(1);
EventLoopGroup workerGroup = new OioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(OioSctpServerChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SctpChannel>() {
@Override
public void initChannel(SctpChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
new SctpEchoServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(port).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 2556;
}
new OioSctpEchoServer(port).run();
}
}

View File

@ -23,8 +23,6 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.sctp.SctpChannel; import io.netty.channel.sctp.SctpChannel;
import io.netty.channel.sctp.SctpChannelOption; import io.netty.channel.sctp.SctpChannelOption;
import io.netty.channel.sctp.nio.NioSctpChannel; import io.netty.channel.sctp.nio.NioSctpChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/** /**
* Sends one message when a connection is open and echoes back any received * Sends one message when a connection is open and echoes back any received
@ -34,19 +32,13 @@ import io.netty.handler.logging.LoggingHandler;
* traffic between the echo client and server by sending the first message to * traffic between the echo client and server by sending the first message to
* the server. * the server.
*/ */
public class NioSctpEchoClient { public final class SctpEchoClient {
private final String host; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int port; static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
private final int firstMessageSize; static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public NioSctpEchoClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public void run() throws Exception {
// Configure the client. // Configure the client.
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
@ -58,13 +50,13 @@ public class NioSctpEchoClient {
@Override @Override
public void initChannel(SctpChannel ch) throws Exception { public void initChannel(SctpChannel ch) throws Exception {
ch.pipeline().addLast( ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO), //new LoggingHandler(LogLevel.INFO),
new SctpEchoClientHandler(firstMessageSize)); new SctpEchoClientHandler());
} }
}); });
// Start the client. // Start the client.
ChannelFuture f = b.connect(host, port).sync(); ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed. // Wait until the connection is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
@ -73,26 +65,4 @@ public class NioSctpEchoClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + NioSctpEchoClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
}
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new NioSctpEchoClient(host, port, firstMessageSize).run();
}
} }

View File

@ -21,9 +21,6 @@ import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.sctp.SctpMessage; import io.netty.channel.sctp.SctpMessage;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler implementation for the SCTP echo client. It initiates the ping-pong * Handler implementation for the SCTP echo client. It initiates the ping-pong
* traffic between the echo client and server by sending the first message to * traffic between the echo client and server by sending the first message to
@ -31,19 +28,13 @@ import java.util.logging.Logger;
*/ */
public class SctpEchoClientHandler extends ChannelHandlerAdapter { public class SctpEchoClientHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(
SctpEchoClientHandler.class.getName());
private final ByteBuf firstMessage; private final ByteBuf firstMessage;
/** /**
* Creates a client-side handler. * Creates a client-side handler.
*/ */
public SctpEchoClientHandler(int firstMessageSize) { public SctpEchoClientHandler() {
if (firstMessageSize <= 0) { firstMessage = Unpooled.buffer(SctpEchoClient.SIZE);
throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);
}
firstMessage = Unpooled.buffer(firstMessageSize);
for (int i = 0; i < firstMessage.capacity(); i++) { for (int i = 0; i < firstMessage.capacity(); i++) {
firstMessage.writeByte((byte) i); firstMessage.writeByte((byte) i);
} }
@ -55,19 +46,19 @@ public class SctpEchoClientHandler extends ChannelHandlerAdapter {
} }
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); cause.printStackTrace();
ctx.close(); ctx.close();
} }
} }

View File

@ -29,15 +29,11 @@ import io.netty.handler.logging.LoggingHandler;
/** /**
* Echoes back any received data from a SCTP client. * Echoes back any received data from a SCTP client.
*/ */
public class NioSctpEchoServer { public final class SctpEchoServer {
private final int port; static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public NioSctpEchoServer(int port) { public static void main(String[] args) throws Exception {
this.port = port;
}
public void run() throws Exception {
// Configure the server. // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -51,13 +47,13 @@ public class NioSctpEchoServer {
@Override @Override
public void initChannel(SctpChannel ch) throws Exception { public void initChannel(SctpChannel ch) throws Exception {
ch.pipeline().addLast( ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO), //new LoggingHandler(LogLevel.INFO),
new SctpEchoServerHandler()); new SctpEchoServerHandler());
} }
}); });
// Start the server. // Start the server.
ChannelFuture f = b.bind(port).sync(); ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed. // Wait until the server socket is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
@ -67,14 +63,4 @@ public class NioSctpEchoServer {
workerGroup.shutdownGracefully(); workerGroup.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 2556;
}
new NioSctpEchoServer(port).run();
}
} }

View File

@ -19,32 +19,26 @@ import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handler implementation for the SCTP echo server. * Handler implementation for the SCTP echo server.
*/ */
@Sharable @Sharable
public class SctpEchoServerHandler extends ChannelHandlerAdapter { public class SctpEchoServerHandler extends ChannelHandlerAdapter {
private static final Logger logger = Logger.getLogger(
SctpEchoServerHandler.class.getName());
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void channelRead(ChannelHandlerContext ctx, Object msg) {
// Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.write(msg); ctx.write(msg);
} }
@Override @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush(); ctx.flush();
} }
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
} }

View File

@ -31,19 +31,15 @@ import java.io.InputStreamReader;
/** /**
* Simple SSL chat client modified from {@link TelnetClient}. * Simple SSL chat client modified from {@link TelnetClient}.
*/ */
public class SecureChatClient { public final class SecureChatClient {
private final SslContext sslCtx; static final String HOST = System.getProperty("host", "127.0.0.1");
private final String host; static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
private final int port;
public SecureChatClient(SslContext sslCtx, String host, int port) { public static void main(String[] args) throws Exception {
this.sslCtx = sslCtx; // Configure SSL.
this.host = host; final SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
this.port = port;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); EventLoopGroup group = new NioEventLoopGroup();
try { try {
Bootstrap b = new Bootstrap(); Bootstrap b = new Bootstrap();
@ -52,7 +48,7 @@ public class SecureChatClient {
.handler(new SecureChatClientInitializer(sslCtx)); .handler(new SecureChatClientInitializer(sslCtx));
// Start the connection attempt. // Start the connection attempt.
Channel ch = b.connect(host, port).sync().channel(); Channel ch = b.connect(HOST, PORT).sync().channel();
// Read commands from the stdin. // Read commands from the stdin.
ChannelFuture lastWriteFuture = null; ChannelFuture lastWriteFuture = null;
@ -83,22 +79,4 @@ public class SecureChatClient {
group.shutdownGracefully(); group.shutdownGracefully();
} }
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length != 2) {
System.err.println(
"Usage: " + SecureChatClient.class.getSimpleName() +
" <host> <port>");
return;
}
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
// Configure SSL.
SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
new SecureChatClient(sslCtx, host, port).run();
}
} }

View File

@ -18,27 +18,19 @@ package io.netty.example.securechat;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handles a client-side channel. * Handles a client-side channel.
*/ */
public class SecureChatClientHandler extends SimpleChannelInboundHandler<String> { public class SecureChatClientHandler extends SimpleChannelInboundHandler<String> {
private static final Logger logger = Logger.getLogger(
SecureChatClientHandler.class.getName());
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { public void messageReceived(ChannelHandlerContext ctx, String msg) {
System.err.println(msg); System.err.println(msg);
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.log( cause.printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close(); ctx.close();
} }
} }

View File

@ -44,15 +44,14 @@ public class SecureChatClientInitializer extends ChannelInitializer<SocketChanne
// and accept any invalid certificates in the client 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.
pipeline.addLast("ssl", sslCtx.newHandler(ch.alloc())); pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT));
// On top of the SSL handler, add the text line codec. // On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder( pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
8192, Delimiters.lineDelimiter())); pipeline.addLast(new StringDecoder());
pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast(new StringEncoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic. // and then business logic.
pipeline.addLast("handler", new SecureChatClientHandler()); pipeline.addLast(new SecureChatClientHandler());
} }
} }

Some files were not shown because too many files have changed in this diff Show More