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 51648d0d50
commit dd557c536e
145 changed files with 2058 additions and 4167 deletions

View File

@ -29,6 +29,10 @@ import java.util.List;
public class SocksAuthRequestDecoder extends ReplayingDecoder<SocksAuthRequestDecoder.State> {
private static final String name = "SOCKS_AUTH_REQUEST_DECODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

View File

@ -28,6 +28,10 @@ import java.util.List;
public class SocksAuthResponseDecoder extends ReplayingDecoder<SocksAuthResponseDecoder.State> {
private static final String name = "SOCKS_AUTH_RESPONSE_DECODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

View File

@ -29,6 +29,10 @@ import java.util.List;
public class SocksCmdRequestDecoder extends ReplayingDecoder<SocksCmdRequestDecoder.State> {
private static final String name = "SOCKS_CMD_REQUEST_DECODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

View File

@ -29,6 +29,10 @@ import java.util.List;
public class SocksCmdResponseDecoder extends ReplayingDecoder<SocksCmdResponseDecoder.State> {
private static final String name = "SOCKS_CMD_RESPONSE_DECODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

View File

@ -29,6 +29,10 @@ import java.util.List;
public class SocksInitRequestDecoder extends ReplayingDecoder<SocksInitRequestDecoder.State> {
private static final String name = "SOCKS_INIT_REQUEST_DECODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

View File

@ -28,6 +28,10 @@ import java.util.List;
public class SocksInitResponseDecoder extends ReplayingDecoder<SocksInitResponseDecoder.State> {
private static final String name = "SOCKS_INIT_RESPONSE_DECODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

View File

@ -30,6 +30,10 @@ import io.netty.handler.codec.MessageToByteEncoder;
public class SocksMessageEncoder extends MessageToByteEncoder<SocksMessage> {
private static final String name = "SOCKS_MESSAGE_ENCODER";
/**
* @deprecated Will be removed at the next minor version bump.
*/
@Deprecated
public static String getName() {
return name;
}

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 channelRead0(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.channel.ChannelFuture;
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.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/**
* Keeps sending random data to the specified address.
*/
public class DiscardClient {
public final class DiscardClient {
private final String host;
private final int port;
private final int firstMessageSize;
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
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) {
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.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.
ChannelFuture f = b.connect(host, port).sync();
ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
@ -53,26 +70,4 @@ public class DiscardClient {
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,43 +21,27 @@ import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handles a client-side channel.
*/
public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(
DiscardClientHandler.class.getName());
private final int messageSize;
private ByteBuf content;
private ChannelHandlerContext ctx;
public DiscardClientHandler(int messageSize) {
if (messageSize <= 0) {
throw new IllegalArgumentException(
"messageSize: " + messageSize);
}
this.messageSize = messageSize;
}
@Override
public void channelActive(ChannelHandlerContext ctx)
throws Exception {
public void channelActive(ChannelHandlerContext ctx) {
this.ctx = ctx;
// Initialize the message.
content = ctx.alloc().directBuffer(messageSize).writeZero(messageSize);
content = ctx.alloc().directBuffer(DiscardClient.SIZE).writeZero(DiscardClient.SIZE);
// Send the initial messages.
generateTraffic();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
public void channelInactive(ChannelHandlerContext ctx) {
content.release();
}
@ -67,13 +51,9 @@ public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
cause);
cause.printStackTrace();
ctx.close();
}
@ -87,9 +67,12 @@ public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
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.channel.ChannelFuture;
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.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.
*/
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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new DiscardServerHandler());
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new DiscardServerHandler());
}
});
// 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.
// In this example, this does not happen, but you can do that to gracefully
@ -60,14 +76,4 @@ public class DiscardServer {
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.SimpleChannelInboundHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handles a server-side channel.
*/
public class DiscardServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(
DiscardServerHandler.class.getName());
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
// discard
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
cause);
cause.printStackTrace();
ctx.close();
}
}

View File

@ -19,10 +19,15 @@ import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.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
@ -30,19 +35,22 @@ import io.netty.channel.socket.nio.NioSocketChannel;
* traffic between the echo client and server by sending the first message to
* the server.
*/
public class EchoClient {
public final class EchoClient {
private final String host;
private final int port;
private final int firstMessageSize;
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
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) {
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public static void main(String[] args) throws Exception {
// Configure SSL.git
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
// Configure the client.
EventLoopGroup group = new NioEventLoopGroup();
try {
@ -53,14 +61,17 @@ public class EchoClient {
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
//new LoggingHandler(LogLevel.INFO),
new EchoClientHandler(firstMessageSize));
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoClientHandler());
}
});
// Start the client.
ChannelFuture f = b.connect(host, port).sync();
ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
@ -69,26 +80,4 @@ public class EchoClient {
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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handler implementation for the echo client. It initiates the ping-pong
* 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 ChannelInboundHandlerAdapter {
private static final Logger logger = Logger.getLogger(
EchoClientHandler.class.getName());
private final ByteBuf firstMessage;
/**
* Creates a client-side handler.
*/
public EchoClientHandler(int firstMessageSize) {
if (firstMessageSize <= 0) {
throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);
}
firstMessage = Unpooled.buffer(firstMessageSize);
public EchoClientHandler() {
firstMessage = Unpooled.buffer(EchoClient.SIZE);
for (int i = 0; i < firstMessage.capacity(); i ++) {
firstMessage.writeByte((byte) i);
}
@ -54,19 +45,19 @@ public class EchoClientHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);
cause.printStackTrace();
ctx.close();
}
}

View File

@ -19,25 +19,34 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.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;
/**
* 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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -50,14 +59,17 @@ public class EchoServer {
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
//new LoggingHandler(LogLevel.INFO),
new EchoServerHandler());
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(port).sync();
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
@ -67,14 +79,4 @@ public class EchoServer {
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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handler implementation for the echo server.
*/
@Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = Logger.getLogger(
EchoServerHandler.class.getName());
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);
cause.printStackTrace();
ctx.close();
}
}

View File

@ -44,8 +44,7 @@ public class BigIntegerDecoder extends ByteToMessageDecoder {
int magicNumber = in.readUnsignedByte();
if (magicNumber != 'F') {
in.resetReaderIndex();
throw new CorruptedFrameException(
"Invalid magic number: " + magicNumber);
throw new CorruptedFrameException("Invalid magic number: " + magicNumber);
}
// 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.nio.NioEventLoopGroup;
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
* the factorial of the specified integer.
*/
public class FactorialClient {
public final class FactorialClient {
private final String host;
private final int port;
private final int count;
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
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) {
this.host = host;
this.port = port;
this.count = count;
}
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new FactorialClientInitializer(count));
.handler(new FactorialClientInitializer(sslCtx));
// 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.
FactorialClientHandler handler =
(FactorialClientHandler) f.channel().pipeline().last();
// Print out the answer.
System.err.format(
"Factorial of %,d is: %,d", count, handler.getFactorial());
System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial());
} finally {
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.util.concurrent.BlockingQueue;
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
@ -35,30 +33,24 @@ import java.util.logging.Logger;
*/
public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteger> {
private static final Logger logger = Logger.getLogger(
FactorialClientHandler.class.getName());
private ChannelHandlerContext ctx;
private int receivedMessages;
private int next = 1;
private final int count;
final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>();
public FactorialClientHandler(int count) {
this.count = count;
}
public BigInteger getFactorial() {
boolean interrupted = false;
for (;;) {
try {
BigInteger factorial = answer.take();
if (interrupted) {
Thread.currentThread().interrupt();
try {
for (;;) {
try {
return answer.take();
} catch (InterruptedException ignore) {
interrupted = true;
}
return factorial;
} catch (InterruptedException e) {
interrupted = true;
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
@ -72,7 +64,7 @@ public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteg
@Override
public void channelRead0(ChannelHandlerContext ctx, final BigInteger msg) {
receivedMessages ++;
if (receivedMessages == count) {
if (receivedMessages == FactorialClient.COUNT) {
// Offer the answer after closing the connection.
ctx.channel().close().addListener(new ChannelFutureListener() {
@Override
@ -85,22 +77,19 @@ public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteg
}
@Override
public void exceptionCaught(
ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private void sendNumbers() {
// Do not send more than 4096 numbers.
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));
next++;
}
if (next <= count) {
if (next <= FactorialClient.COUNT) {
assert future != null;
future.addListener(numberSender);
}
@ -112,6 +101,9 @@ public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteg
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
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.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.ssl.SslContext;
/**
* Creates a newly configured {@link ChannelPipeline} for a client-side channel.
*/
public class FactorialClientInitializer extends ChannelInitializer<SocketChannel> {
private final int count;
private final SslContext sslCtx;
public FactorialClientInitializer(int count) {
this.count = count;
public FactorialClientInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
public void initChannel(SocketChannel ch) {
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)
pipeline.addLast("deflater", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast("inflater", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
// Add the number codec first,
pipeline.addLast("decoder", new BigIntegerDecoder());
pipeline.addLast("encoder", new NumberEncoder());
pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast(new NumberEncoder());
// 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.nio.NioEventLoopGroup;
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
* 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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.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 {
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 FactorialServer(port).run();
}
}

View File

@ -19,9 +19,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
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
@ -32,9 +29,6 @@ import java.util.logging.Logger;
*/
public class FactorialServerHandler extends SimpleChannelInboundHandler<BigInteger> {
private static final Logger logger = Logger.getLogger(
FactorialServerHandler.class.getName());
private BigInteger lastMultiplier = new BigInteger("1");
private BigInteger factorial = new BigInteger("1");
@ -48,17 +42,12 @@ public class FactorialServerHandler extends SimpleChannelInboundHandler<BigInteg
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Formatter fmt = new Formatter();
logger.info(fmt.format(
"Factorial of %,d is: %,d", lastMultiplier, factorial).toString());
fmt.close();
System.err.printf("Factorial of %,d is: %,d%n", lastMultiplier, factorial);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
cause.printStackTrace();
ctx.close();
}
}

View File

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

View File

@ -29,7 +29,7 @@ import java.math.BigInteger;
public class NumberEncoder extends MessageToByteEncoder<Number> {
@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.
BigInteger v;
if (msg instanceof BigInteger) {

View File

@ -13,17 +13,14 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.filetransfer;
package io.netty.example.file;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.ChannelPipeline;
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.socket.SocketChannel;
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.logging.LogLevel;
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 java.io.File;
import java.io.FileInputStream;
/**
* 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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -61,16 +65,21 @@ public class FileServer {
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
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 LineBasedFrameDecoder(8192),
new StringDecoder(CharsetUtil.UTF_8),
new FileHandler());
new ChunkedWriteHandler(),
new FileServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(port).sync();
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
@ -80,41 +89,4 @@ public class FileServer {
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 channelRead0(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 channelRead0(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.nio.NioEventLoopGroup;
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
@ -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.
* <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
* wildcard origin ('*').
* <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'
* 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
* 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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.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 {
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 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.cors.CorsConfig;
import io.netty.handler.codec.http.cors.CorsHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler;
/**
@ -68,19 +69,27 @@ import io.netty.handler.stream.ChunkedWriteHandler;
* corsConfig.exposedHeaders("custom-response-header");
* </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
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
public void initChannel(SocketChannel ch) {
CorsConfig corsConfig = CorsConfig.withAnyOrigin().build();
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
pipeline.addLast("cors", new CorsHandler(corsConfig));
pipeline.addLast("handler", new OkResponseHandler());
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new CorsHandler(corsConfig));
pipeline.addLast(new OkResponseHandler());
}
}

View File

@ -16,41 +16,49 @@
package io.netty.example.http.file;
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.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 {
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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.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 {
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 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.HttpResponseStatus;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil;
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 int HTTP_CACHE_SECONDS = 60;
private final boolean useSendFile;
public HttpStaticFileServerHandler(boolean useSendFile) {
this.useSendFile = useSendFile;
}
@Override
public void channelRead0(
ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
if (!request.getDecoderResult().isSuccess()) {
sendError(ctx, BAD_REQUEST);
return;
@ -173,7 +167,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
RandomAccessFile raf;
try {
raf = new RandomAccessFile(file, "r");
} catch (FileNotFoundException fnfe) {
} catch (FileNotFoundException ignore) {
sendError(ctx, NOT_FOUND);
return;
}
@ -192,7 +186,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
// Write the content.
ChannelFuture sendFileFuture;
if (useSendFile) {
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
} else {
@ -204,15 +198,15 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
@Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) { // total unknown
System.err.println("Transfer progress: " + progress);
System.err.println(future.channel() + " Transfer progress: " + progress);
} else {
System.err.println("Transfer progress: " + progress + " / " + total);
System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total);
}
}
@Override
public void operationComplete(ChannelProgressiveFuture future) throws Exception {
System.err.println("Transfer complete.");
public void operationComplete(ChannelProgressiveFuture future) {
System.err.println(future.channel() + " Transfer complete.");
}
});
@ -227,7 +221,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
if (ctx.channel().isActive()) {
sendError(ctx, INTERNAL_SERVER_ERROR);
@ -241,11 +235,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
try {
uri = URLDecoder.decode(uri, "UTF-8");
} catch (UnsupportedEncodingException e) {
try {
uri = URLDecoder.decode(uri, "ISO-8859-1");
} catch (UnsupportedEncodingException e1) {
throw new Error();
}
throw new Error(e);
}
if (!uri.startsWith("/")) {
@ -326,7 +316,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
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");
// 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();
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.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.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler;
public class HttpStaticFileServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpStaticFileServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
// Create a default pipeline implementation.
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
// Uncomment the following line if you want HTTPS
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().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("chunkedWriter", new ChunkedWriteHandler());
pipeline.addLast("handler", new HttpStaticFileServerHandler(true)); // Specify false if SSL.
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpStaticFileServerHandler());
}
}

View File

@ -21,20 +21,30 @@ import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
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
* 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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -43,23 +53,18 @@ public class HttpHelloWorldServer {
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup)
.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();
} 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 HttpHelloWorldServer(port).run();
}
}

View File

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

View File

@ -19,18 +19,23 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;
public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpHelloWorldServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
// Uncomment the following line if you want HTTPS
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
//engine.setUseClientMode(false);
//p.addLast("ssl", new SslHandler(engine));
p.addLast("codec", new HttpServerCodec());
p.addLast("handler", new HttpHelloWorldServerHandler());
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new HttpServerCodec());
p.addLast(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
* {@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) {
this.uri = uri;
}
public void run() throws Exception {
public static void main(String[] args) throws Exception {
URI uri = new URI(URL);
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();
if (port == -1) {
if ("http".equalsIgnoreCase(scheme)) {
@ -61,8 +58,9 @@ public class HttpSnoopClient {
return;
}
// Configure SSL context if necessary.
final boolean ssl = "https".equalsIgnoreCase(scheme);
final SslContext sslCtx;
boolean ssl = "https".equalsIgnoreCase(scheme);
if (ssl) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
@ -104,16 +102,4 @@ public class HttpSnoopClient {
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

@ -31,40 +31,40 @@ public class HttpSnoopClientHandler extends SimpleChannelInboundHandler<HttpObje
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
System.out.println("STATUS: " + response.getStatus());
System.out.println("VERSION: " + response.getProtocolVersion());
System.out.println();
System.err.println("STATUS: " + response.getStatus());
System.err.println("VERSION: " + response.getProtocolVersion());
System.err.println();
if (!response.headers().isEmpty()) {
for (String name: response.headers().names()) {
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)) {
System.out.println("CHUNKED CONTENT {");
System.err.println("CHUNKED CONTENT {");
} else {
System.out.println("CONTENT {");
System.err.println("CONTENT {");
}
}
if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
System.out.print(content.content().toString(CharsetUtil.UTF_8));
System.out.flush();
System.err.print(content.content().toString(CharsetUtil.UTF_8));
System.err.flush();
if (content instanceof LastHttpContent) {
System.out.println("} END OF CONTENT");
System.err.println("} END OF CONTENT");
ctx.close();
}
}
}
@Override
public void exceptionCaught(
ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}

View File

@ -20,8 +20,6 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
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;
public class HttpSnoopClientInitializer extends ChannelInitializer<SocketChannel> {
@ -33,25 +31,22 @@ public class HttpSnoopClientInitializer extends ChannelInitializer<SocketChannel
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
// Create a default pipeline implementation.
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast("log", new LoggingHandler(LogLevel.INFO));
// Enable HTTPS if necessary.
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.
p.addLast("inflater", new HttpContentDecompressor());
p.addLast(new HttpContentDecompressor());
// Uncomment the following line if you don't want to handle HttpChunks.
//p.addLast("aggregator", new HttpObjectAggregator(1048576));
// Uncomment the following line if you don't want to handle HttpContents.
//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.nio.NioEventLoopGroup;
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
@ -27,13 +31,19 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
*/
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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -41,23 +51,18 @@ public class HttpSnoopServer {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.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();
} 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 HttpSnoopServer(port).run();
}
}

View File

@ -17,6 +17,7 @@ package io.netty.example.http.snoop;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.DecoderResult;
@ -50,7 +51,7 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
private final StringBuilder buf = new StringBuilder();
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@ -123,7 +124,10 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
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
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}

View File

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

View File

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

View File

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

View File

@ -20,6 +20,8 @@ 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.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
@ -28,26 +30,32 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
*/
public class HttpUploadServer {
private final SslContext sslCtx;
private final int port;
public static boolean isSSL;
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpUploadServer(SslContext sslCtx, int port) {
this.sslCtx = sslCtx;
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new HttpUploadServerInitializer(sslCtx));
b.group(bossGroup, workerGroup);
b.channel(NioServerSocketChannel.class);
b.handler(new LoggingHandler(LogLevel.INFO));
b.childHandler(new HttpUploadServerInitializer(sslCtx));
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 + '/');
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 {
@ -55,26 +63,4 @@ public class HttpUploadServer {
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 static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk
// if
// size
// exceed
private static final HttpDataFactory factory =
new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed
private HttpPostRequestDecoder decoder;
static {
@ -128,7 +126,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
cookies = CookieDecoder.decode(value);
}
for (Cookie cookie : cookies) {
responseContent.append("COOKIE: " + cookie.toString() + "\r\n");
responseContent.append("COOKIE: " + cookie + "\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");
} else {
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
+ attribute.toString() + "\r\n");
+ attribute + "\r\n");
}
} else {
responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data.toString()
responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data
+ "\r\n");
if (data.getHttpDataType() == HttpDataType.FileUpload) {
FileUpload fileUpload = (FileUpload) data;

View File

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

View File

@ -15,6 +15,29 @@
*/
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;
/**
@ -31,17 +54,89 @@ import java.net.URI;
* as this is the default.
*/
public final class WebSocketClient {
private WebSocketClient() {
}
public static void main(String... args) throws Exception {
URI uri;
if (args.length > 0) {
uri = new URI(args[0]);
static final String URL = System.getProperty("url", "ws://127.0.0.1:8080/websocket");
public static void main(String[] args) throws Exception {
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 {
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,17 +64,17 @@ public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object>
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
public void handlerAdded(ChannelHandlerContext ctx) {
handshakeFuture = ctx.newPromise();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
public void channelActive(ChannelHandlerContext ctx) {
handshaker.handshake(ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("WebSocket Client disconnected!");
}
@ -90,8 +90,9 @@ public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object>
if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content="
+ response.content().toString(CharsetUtil.UTF_8) + ')');
throw new IllegalStateException(
"Unexpected FullHttpResponse (getStatus=" + response.getStatus() +
", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
}
WebSocketFrame frame = (WebSocketFrame) msg;
@ -107,13 +108,11 @@ public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object>
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause);
}
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 channelRead0(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.nio.NioEventLoopGroup;
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:
@ -40,26 +44,34 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
* <li>Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* </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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WebSocketServerInitializer());
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new WebSocketServerInitializer(sslCtx));
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 + '/');
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 {
@ -67,14 +79,4 @@ public class WebSocketServer {
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.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.*;
@ -46,7 +43,6 @@ import static io.netty.handler.codec.http.HttpVersion.*;
* Handles handshakes and messages
*/
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger.getLogger(WebSocketServerHandler.class.getName());
private static final String WEBSOCKET_PATH = "/websocket";
@ -62,11 +58,11 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
// Handle a bad request.
if (!req.getDecoderResult().isSuccess()) {
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.
String request = ((TextWebSocketFrame) frame).text();
if (logger.isLoggable(Level.FINE)) {
logger.fine(String.format("%s received %s", ctx.channel(), request));
}
System.err.printf("%s received %s%n", ctx.channel(), request);
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
}
@ -149,12 +143,17 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
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.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;
/**
*/
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public WebSocketServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("codec-http", new HttpServerCodec());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("handler", new WebSocketServerHandler());
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
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 channelRead0(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

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

View File

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

View File

@ -17,6 +17,7 @@ package io.netty.example.objectecho;
import io.netty.bootstrap.Bootstrap;
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;
@ -25,23 +26,28 @@ import io.netty.example.echo.EchoClient;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
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.
*/
public class ObjectEchoClient {
public final class ObjectEchoClient {
private final String host;
private final int port;
private final int firstMessageSize;
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
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) {
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
@ -50,40 +56,21 @@ public class ObjectEchoClient {
.handler(new ChannelInitializer<SocketChannel>() {
@Override
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 ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoClientHandler(firstMessageSize));
new ObjectEchoClientHandler());
}
});
// Start the connection attempt.
b.connect(host, port).sync().channel().closeFuture().sync();
b.connect(HOST, PORT).sync().channel().closeFuture().sync();
} finally {
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.ChannelInboundHandlerAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handler implementation for the object echo client. It initiates the
@ -30,48 +28,38 @@ import java.util.logging.Logger;
*/
public class ObjectEchoClientHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = Logger.getLogger(
ObjectEchoClientHandler.class.getName());
private final List<Integer> firstMessage;
/**
* Creates a client-side handler.
*/
public ObjectEchoClientHandler(int firstMessageSize) {
if (firstMessageSize <= 0) {
throw new IllegalArgumentException(
"firstMessageSize: " + firstMessageSize);
}
firstMessage = new ArrayList<Integer>(firstMessageSize);
for (int i = 0; i < firstMessageSize; i ++) {
public ObjectEchoClientHandler() {
firstMessage = new ArrayList<Integer>(ObjectEchoClient.SIZE);
for (int i = 0; i < ObjectEchoClient.SIZE; i ++) {
firstMessage.add(Integer.valueOf(i));
}
}
@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.
ctx.writeAndFlush(firstMessage);
}
@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.
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(
ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

View File

@ -17,6 +17,7 @@ package io.netty.example.objectecho;
import io.netty.bootstrap.ServerBootstrap;
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;
@ -25,29 +26,44 @@ import io.netty.example.echo.EchoServer;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
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.
*/
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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
// 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 workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
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 ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoServerHandler());
@ -55,20 +71,10 @@ public class ObjectEchoServer {
});
// Bind and start to accept incoming connections.
b.bind(port).sync().channel().closeFuture().sync();
b.bind(PORT).sync().channel().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 ObjectEchoServer(port).run();
}
}

View File

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

View File

@ -21,6 +21,8 @@ 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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
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
* are possible: none, SSL only, GZIP only, SSL + GZIP, and GZIP + SSL.
*/
public class PortUnificationServer {
public final class PortUnificationServer {
private final SslContext sslCtx;
private final int port;
static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
public PortUnificationServer(SslContext sslCtx, int port) {
this.sslCtx = sslCtx;
this.port = port;
}
public static void main(String[] args) throws Exception {
// Configure SSL context
SelfSignedCertificate ssc = new SelfSignedCertificate();
final SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
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)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
@ -56,25 +57,10 @@ public class PortUnificationServer {
});
// Bind and start to accept incoming connections.
b.bind(port).sync().channel().closeFuture().sync();
b.bind(PORT).sync().channel().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;
}
// 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.nio.NioEventLoopGroup;
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;
private final String remoteHost;
private final int remotePort;
static final int LOCAL_PORT = Integer.parseInt(System.getProperty("localPort", "8443"));
static final String REMOTE_HOST = System.getProperty("remoteHost", "www.google.com");
static final int REMOTE_PORT = Integer.parseInt(System.getProperty("remotePort", "443"));
public HexDumpProxy(int localPort, String remoteHost, int remotePort) {
this.localPort = localPort;
this.remoteHost = remoteHost;
this.remotePort = remotePort;
}
public void run() throws Exception {
System.err.println(
"Proxying *:" + localPort + " to " +
remoteHost + ':' + remotePort + " ...");
public static void main(String[] args) throws Exception {
System.err.println("Proxying *:" + LOCAL_PORT + " to " + REMOTE_HOST + ':' + REMOTE_PORT + " ...");
// Configure the bootstrap.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
@ -45,29 +39,13 @@ public class HexDumpProxy {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.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)
.bind(localPort).sync().channel().closeFuture().sync();
.bind(LOCAL_PORT).sync().channel().closeFuture().sync();
} finally {
bossGroup.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 ChannelInboundHandlerAdapter {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
public void channelActive(ChannelHandlerContext ctx) {
ctx.read();
ctx.write(Unpooled.EMPTY_BUFFER);
}
@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() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
ctx.channel().read();
} else {
@ -51,12 +51,12 @@ public class HexDumpProxyBackendHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
public void channelInactive(ChannelHandlerContext ctx) {
HexDumpProxyFrontendHandler.closeOnFlush(inboundChannel);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
HexDumpProxyFrontendHandler.closeOnFlush(ctx.channel());
}

View File

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

View File

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

View File

@ -28,20 +28,17 @@ import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
/**
* A UDP broadcast client that asks for a quote of the moment (QOTM) to
* {@link QuoteOfTheMomentServer}.
* A UDP broadcast client that asks for a quote of the moment (QOTM) to {@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) {
this.port = port;
}
public static void main(String[] args) throws Exception {
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
@ -55,7 +52,7 @@ public class QuoteOfTheMomentClient {
// Broadcast the QOTM request to port 8080.
ch.writeAndFlush(new DatagramPacket(
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
// response is received. If the channel is not closed within 5 seconds,
@ -67,14 +64,4 @@ public class QuoteOfTheMomentClient {
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

@ -32,7 +32,7 @@ public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<D
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}

View File

@ -22,20 +22,16 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
/**
* A UDP server that responds to the QOTM (quote of the moment) request to a
* {@link QuoteOfTheMomentClient}.
* A UDP server that responds to the QOTM (quote of the moment) request to a {@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) {
this.port = port;
}
public void run() throws Exception {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
@ -44,19 +40,9 @@ public class QuoteOfTheMomentServer {
.option(ChannelOption.SO_BROADCAST, true)
.handler(new QuoteOfTheMomentServerHandler());
b.bind(port).sync().channel().closeFuture().await();
b.bind(PORT).sync().channel().closeFuture().await();
} finally {
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

@ -53,14 +53,12 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelInboundHandler<D
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(
ChannelHandlerContext ctx, Throwable cause)
throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
// 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 {
static final String PORT = System.getProperty("port", "/dev/ttyUSB0");
public static void main(String[] args) throws Exception {
EventLoopGroup group = new OioEventLoopGroup();
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();
} finally {
group.shutdownGracefully();
}
}
private RxtxClient() {
}
}

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.SctpChannelOption;
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
@ -34,19 +32,13 @@ import io.netty.handler.logging.LoggingHandler;
* traffic between the echo client and server by sending the first message to
* the server.
*/
public class NioSctpEchoClient {
public final class SctpEchoClient {
private final String host;
private final int port;
private final int firstMessageSize;
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public NioSctpEchoClient(String host, int port, int firstMessageSize) {
this.host = host;
this.port = port;
this.firstMessageSize = firstMessageSize;
}
public void run() throws Exception {
public static void main(String[] args) throws Exception {
// Configure the client.
EventLoopGroup group = new NioEventLoopGroup();
try {
@ -58,13 +50,13 @@ public class NioSctpEchoClient {
@Override
public void initChannel(SctpChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
new SctpEchoClientHandler(firstMessageSize));
//new LoggingHandler(LogLevel.INFO),
new SctpEchoClientHandler());
}
});
// Start the client.
ChannelFuture f = b.connect(host, port).sync();
ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
@ -73,26 +65,4 @@ public class NioSctpEchoClient {
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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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
* 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 ChannelInboundHandlerAdapter {
private static final Logger logger = Logger.getLogger(
SctpEchoClientHandler.class.getName());
private final ByteBuf firstMessage;
/**
* Creates a client-side handler.
*/
public SctpEchoClientHandler(int firstMessageSize) {
if (firstMessageSize <= 0) {
throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);
}
firstMessage = Unpooled.buffer(firstMessageSize);
public SctpEchoClientHandler() {
firstMessage = Unpooled.buffer(SctpEchoClient.SIZE);
for (int i = 0; i < firstMessage.capacity(); i++) {
firstMessage.writeByte((byte) i);
}
@ -55,19 +46,19 @@ public class SctpEchoClientHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.", cause);
cause.printStackTrace();
ctx.close();
}
}

View File

@ -29,15 +29,11 @@ import io.netty.handler.logging.LoggingHandler;
/**
* 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) {
this.port = port;
}
public void run() throws Exception {
public static void main(String[] args) throws Exception {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
@ -51,13 +47,13 @@ public class NioSctpEchoServer {
@Override
public void initChannel(SctpChannel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
//new LoggingHandler(LogLevel.INFO),
new SctpEchoServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(port).sync();
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
@ -67,14 +63,4 @@ public class NioSctpEchoServer {
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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handler implementation for the SCTP echo server.
*/
@Sharable
public class SctpEchoServerHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = Logger.getLogger(
SctpEchoServerHandler.class.getName());
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 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 {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
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}.
*/
public class SecureChatClient {
public final class SecureChatClient {
private final SslContext sslCtx;
private final String host;
private final int port;
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
public SecureChatClient(SslContext sslCtx, String host, int port) {
this.sslCtx = sslCtx;
this.host = host;
this.port = port;
}
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
@ -52,7 +48,7 @@ public class SecureChatClient {
.handler(new SecureChatClientInitializer(sslCtx));
// 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.
ChannelFuture lastWriteFuture = null;
@ -83,22 +79,4 @@ public class SecureChatClient {
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.SimpleChannelInboundHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handles a client-side channel.
*/
public class SecureChatClientHandler extends SimpleChannelInboundHandler<String> {
private static final Logger logger = Logger.getLogger(
SecureChatClientHandler.class.getName());
@Override
public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.err.println(msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

View File

@ -44,15 +44,14 @@ public class SecureChatClientInitializer extends ChannelInitializer<SocketChanne
// and accept any invalid certificates in the client side.
// You will need something more complicated to identify both
// 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.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
// and then business logic.
pipeline.addLast("handler", new SecureChatClientHandler());
pipeline.addLast(new SecureChatClientHandler());
}
}

View File

@ -20,50 +20,35 @@ import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.example.telnet.TelnetServer;
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;
/**
* Simple SSL chat server modified from {@link TelnetServer}.
*/
public class SecureChatServer {
public final class SecureChatServer {
private final SslContext sslCtx;
private final int port;
static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
public SecureChatServer(SslContext sslCtx, int port) {
this.sslCtx = sslCtx;
this.port = port;
}
public static void main(String[] args) throws Exception {
SelfSignedCertificate ssc = new SelfSignedCertificate();
SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
public void run() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new SecureChatServerInitializer(sslCtx));
b.bind(port).sync().channel().closeFuture().sync();
b.bind(PORT).sync().channel().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;
}
// Configure SSL context.
SelfSignedCertificate ssc = new SelfSignedCertificate();
SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
new SecureChatServer(sslCtx, port).run();
}
}

View File

@ -26,37 +26,31 @@ import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.net.InetAddress;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Handles a server-side channel.
*/
public class SecureChatServerHandler extends SimpleChannelInboundHandler<String> {
private static final Logger logger = Logger.getLogger(
SecureChatServerHandler.class.getName());
static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
public void channelActive(final ChannelHandlerContext ctx) {
// Once session is secured, send a greeting and register the channel to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
new GenericFutureListener<Future<Channel>>() {
@Override
public void operationComplete(Future<Channel> future) throws Exception {
ctx.writeAndFlush(
"Welcome to " + InetAddress.getLocalHost().getHostName() +
" secure chat service!\n");
ctx.writeAndFlush(
"Your session is protected by " +
ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
" cipher suite.\n");
@Override
public void operationComplete(Future<Channel> future) throws Exception {
ctx.writeAndFlush(
"Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n");
ctx.writeAndFlush(
"Your session is protected by " +
ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
" cipher suite.\n");
channels.add(ctx.channel());
}
channels.add(ctx.channel());
}
});
}
@ -65,8 +59,7 @@ public class SecureChatServerHandler extends SimpleChannelInboundHandler<String>
// Send the received message to all channels but the current one.
for (Channel c: channels) {
if (c != ctx.channel()) {
c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " +
msg + '\n');
c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n');
} else {
c.writeAndFlush("[you] " + msg + '\n');
}
@ -79,10 +72,8 @@ public class SecureChatServerHandler extends SimpleChannelInboundHandler<String>
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

View File

@ -44,18 +44,14 @@ public class SecureChatServerInitializer extends ChannelInitializer<SocketChanne
// and accept any invalid certificates in the client side.
// You will need something more complicated to identify both
// and server in the real world.
//
// Read SecureChatSslContextFactory
// if you need client certificate authentication.
pipeline.addLast("ssl", sslCtx.newHandler(ch.alloc()));
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
// and then business logic.
pipeline.addLast("handler", new SecureChatServerHandler());
pipeline.addLast(new SecureChatServerHandler());
}
}

View File

@ -15,20 +15,16 @@
*/
package io.netty.example.socksproxy;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.Promise;
public final class DirectClientHandler extends ChannelInboundHandlerAdapter {
private static final String name = "DIRECT_CLIENT_HANDLER";
public static String getName() {
return name;
}
private final Promise promise;
private final Promise<Channel> promise;
public DirectClientHandler(Promise promise) {
public DirectClientHandler(Promise<Channel> promise) {
this.promise = promise;
}
@ -39,7 +35,7 @@ public final class DirectClientHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
promise.setFailure(throwable);
}
}

View File

@ -1,37 +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.socksproxy;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.Promise;
public final class DirectClientInitializer extends ChannelInitializer<SocketChannel> {
private final Promise promise;
public DirectClientInitializer(Promise promise) {
this.promise = promise;
}
@Override
public void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(DirectClientHandler.getName(), new DirectClientHandler(promise));
}
}

View File

@ -21,13 +21,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
public final class RelayHandler extends ChannelInboundHandlerAdapter {
private static final String name = "RELAY_HANDLER";
public static String getName() {
return name;
}
private final Channel relayChannel;
@ -36,12 +30,12 @@ public final class RelayHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (relayChannel.isActive()) {
relayChannel.writeAndFlush(msg);
} else {
@ -50,16 +44,15 @@ public final class RelayHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
public void channelInactive(ChannelHandlerContext ctx) {
if (relayChannel.isActive()) {
SocksServerUtils.closeOnFlush(relayChannel);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

View File

@ -19,32 +19,26 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public final class SocksServer {
private final int localPort;
public SocksServer(int localPort) {
this.localPort = localPort;
}
static final int PORT = Integer.parseInt(System.getProperty("port", "1080"));
public void run() throws Exception {
System.err.println(
"Listening on*:" + localPort + "...");
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new SocksServerInitializer());
b.bind(localPort).sync().channel().closeFuture().sync();
b.bind(PORT).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new SocksServer(1080).run();
}
}

View File

@ -33,11 +33,6 @@ import io.netty.util.concurrent.Promise;
@ChannelHandler.Sharable
public final class SocksServerConnectHandler extends SimpleChannelInboundHandler<SocksCmdRequest> {
private static final String name = "SOCKS_SERVER_CONNECT_HANDLER";
public static String getName() {
return name;
}
private final Bootstrap b = new Bootstrap();
@ -53,10 +48,10 @@ public final class SocksServerConnectHandler extends SimpleChannelInboundHandler
ctx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.SUCCESS, request.addressType()))
.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
ctx.pipeline().remove(getName());
public void operationComplete(ChannelFuture channelFuture) {
ctx.pipeline().remove(SocksServerConnectHandler.this);
outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
ctx.channel().pipeline().addLast(new RelayHandler(outboundChannel));
ctx.pipeline().addLast(new RelayHandler(outboundChannel));
}
});
} else {
@ -71,21 +66,21 @@ public final class SocksServerConnectHandler extends SimpleChannelInboundHandler
.channel(NioSocketChannel.class)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new DirectClientInitializer(promise));
b.connect(request.host(), request.port())
.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// Connection established use handler provided results
} else {
// Close the connection if the connection attempt has failed.
ctx.channel().writeAndFlush(
new SocksCmdResponse(SocksCmdStatus.FAILURE, request.addressType()));
SocksServerUtils.closeOnFlush(ctx.channel());
}
.handler(new DirectClientHandler(promise));
b.connect(request.host(), request.port()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// Connection established use handler provided results
} else {
// Close the connection if the connection attempt has failed.
ctx.channel().writeAndFlush(
new SocksCmdResponse(SocksCmdStatus.FAILURE, request.addressType()));
SocksServerUtils.closeOnFlush(ctx.channel());
}
});
}
});
}
@Override

View File

@ -30,31 +30,26 @@ import io.netty.handler.codec.socks.SocksRequest;
@ChannelHandler.Sharable
public final class SocksServerHandler extends SimpleChannelInboundHandler<SocksRequest> {
private static final String name = "SOCKS_SERVER_HANDLER";
public static String getName() {
return name;
}
@Override
public void channelRead0(ChannelHandlerContext ctx, SocksRequest socksRequest) throws Exception {
switch (socksRequest.requestType()) {
case INIT: {
// auth support example
// ctx.pipeline().addFirst("socksAuthRequestDecoder",new SocksAuthRequestDecoder());
// ctx.write(new SocksInitResponse(SocksMessage.SocksAuthScheme.AUTH_PASSWORD));
ctx.pipeline().addFirst(SocksCmdRequestDecoder.getName(), new SocksCmdRequestDecoder());
// auth support example
//ctx.pipeline().addFirst(new SocksAuthRequestDecoder());
//ctx.write(new SocksInitResponse(SocksAuthScheme.AUTH_PASSWORD));
ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
ctx.write(new SocksInitResponse(SocksAuthScheme.NO_AUTH));
break;
}
case AUTH:
ctx.pipeline().addFirst(SocksCmdRequestDecoder.getName(), new SocksCmdRequestDecoder());
ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
ctx.write(new SocksAuthResponse(SocksAuthStatus.SUCCESS));
break;
case CMD:
SocksCmdRequest req = (SocksCmdRequest) socksRequest;
if (req.cmdType() == SocksCmdType.CONNECT) {
ctx.pipeline().addLast(SocksServerConnectHandler.getName(), new SocksServerConnectHandler());
ctx.pipeline().addLast(new SocksServerConnectHandler());
ctx.pipeline().remove(this);
ctx.fireChannelRead(socksRequest);
} else {
@ -68,12 +63,12 @@ public final class SocksServerHandler extends SimpleChannelInboundHandler<SocksR
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
throwable.printStackTrace();
SocksServerUtils.closeOnFlush(ctx.channel());
}

View File

@ -22,14 +22,15 @@ import io.netty.handler.codec.socks.SocksInitRequestDecoder;
import io.netty.handler.codec.socks.SocksMessageEncoder;
public final class SocksServerInitializer extends ChannelInitializer<SocketChannel> {
private final SocksMessageEncoder socksMessageEncoder = new SocksMessageEncoder();
private final SocksServerHandler socksServerHandler = new SocksServerHandler();
@Override
public void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(SocksInitRequestDecoder.getName(), new SocksInitRequestDecoder());
channelPipeline.addLast(SocksMessageEncoder.getName(), socksMessageEncoder);
channelPipeline.addLast(SocksServerHandler.getName(), socksServerHandler);
ChannelPipeline p = socketChannel.pipeline();
p.addLast(new SocksInitRequestDecoder());
p.addLast(socksMessageEncoder);
p.addLast(socksServerHandler);
}
}

View File

@ -21,10 +21,6 @@ import io.netty.channel.ChannelFutureListener;
public final class SocksServerUtils {
private SocksServerUtils() {
//NOOP
}
/**
* Closes the specified channel after all queued write requests are flushed.
*/
@ -33,4 +29,6 @@ public final class SocksServerUtils {
ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
}
private SocksServerUtils() { }
}

View File

@ -75,7 +75,7 @@ public class HttpResponseClientHandler extends SimpleChannelInboundHandler<HttpO
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
queue.add(ctx.channel().newFailedFuture(cause));
cause.printStackTrace();
ctx.close();
@ -84,5 +84,4 @@ public class HttpResponseClientHandler extends SimpleChannelInboundHandler<HttpO
public BlockingQueue<ChannelFuture> queue() {
return queue;
}
}

View File

@ -17,7 +17,6 @@ package io.netty.example.spdy.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
@ -31,12 +30,7 @@ import io.netty.handler.codec.spdy.SpdyOrHttpChooser.SelectedProtocol;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import javax.net.ssl.SSLException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import static java.util.concurrent.TimeUnit.*;
/**
* An SPDY client that allows you to send HTTP GET to a SPDY server.
@ -48,51 +42,49 @@ import static java.util.concurrent.TimeUnit.*;
* <p>
* You may also use the {@code run-example.sh} script to start the client from the command line:
* <pre>
* ./run-example spdy-client
* ./run-example.sh spdy-client
* </pre>
*/
public class SpdyClient {
private final SslContext sslCtx;
private final String host;
private final int port;
private final HttpResponseClientHandler httpResponseHandler;
private Channel channel;
private EventLoopGroup workerGroup;
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public SpdyClient(String host, int port) throws SSLException {
sslCtx = SslContext.newClientContext(
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx = SslContext.newClientContext(
null, InsecureTrustManagerFactory.INSTANCE, null,
Arrays.asList(SelectedProtocol.SPDY_3_1.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
0, 0);
this.host = host;
this.port = port;
httpResponseHandler = new HttpResponseClientHandler();
}
HttpResponseClientHandler httpResponseHandler = new HttpResponseClientHandler();
EventLoopGroup workerGroup = new NioEventLoopGroup();
public void start() {
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(host, port));
b.handler(new SpdyClientInitializer(sslCtx, httpResponseHandler));
// Start the client.
channel = b.connect().syncUninterruptibly().channel();
System.out.println("Connected to [" + host + ':' + port + ']');
}
public void stop() {
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.remoteAddress(HOST, PORT);
b.handler(new SpdyClientInitializer(sslCtx, httpResponseHandler));
// Start the client.
Channel channel = b.connect().syncUninterruptibly().channel();
System.out.println("Connected to " + HOST + ':' + PORT);
// Create a GET request.
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "");
request.headers().set(HttpHeaders.Names.HOST, HOST);
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
// Send the GET request.
channel.writeAndFlush(request).sync();
// Waits for the complete HTTP response
httpResponseHandler.queue().take().sync();
System.out.println("Finished SPDY HTTP GET");
// Wait until the connection is closed.
channel.close().syncUninterruptibly();
} finally {
@ -101,51 +93,4 @@ public class SpdyClient {
}
}
}
public ChannelFuture send(HttpRequest request) {
// Sends the HTTP request.
return channel.writeAndFlush(request);
}
public HttpRequest get() {
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "");
request.headers().set(HttpHeaders.Names.HOST, host);
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
return request;
}
public BlockingQueue<ChannelFuture> httpResponseQueue() {
return httpResponseHandler.queue();
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8443;
}
final SpdyClient client = new SpdyClient("localhost", port);
try {
client.start();
ChannelFuture requestFuture = client.send(client.get()).sync();
if (!requestFuture.isSuccess()) {
requestFuture.cause().printStackTrace();
}
// Waits for the complete HTTP response
ChannelFuture responseFuture = client.httpResponseQueue().poll(5, SECONDS);
if (!responseFuture.isSuccess()) {
responseFuture.cause().printStackTrace();
}
System.out.println("Finished SPDY HTTP GET");
} finally {
client.stop();
}
}
}

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