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:
parent
51648d0d50
commit
dd557c536e
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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()));
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() { }
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user