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
47f961b6b9
commit
3f8194557b
@ -27,11 +27,6 @@ import java.util.List;
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksAuthRequestDecoder extends ReplayingDecoder<SocksAuthRequestDecoder.State> {
|
||||
private static final String name = "SOCKS_AUTH_REQUEST_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksSubnegotiationVersion version;
|
||||
private int fieldLength;
|
||||
|
@ -26,11 +26,6 @@ import java.util.List;
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksAuthResponseDecoder extends ReplayingDecoder<SocksAuthResponseDecoder.State> {
|
||||
private static final String name = "SOCKS_AUTH_RESPONSE_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksSubnegotiationVersion version;
|
||||
private SocksAuthStatus authStatus;
|
||||
|
@ -27,11 +27,6 @@ import java.util.List;
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksCmdRequestDecoder extends ReplayingDecoder<SocksCmdRequestDecoder.State> {
|
||||
private static final String name = "SOCKS_CMD_REQUEST_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksProtocolVersion version;
|
||||
private int fieldLength;
|
||||
|
@ -27,11 +27,6 @@ import java.util.List;
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksCmdResponseDecoder extends ReplayingDecoder<SocksCmdResponseDecoder.State> {
|
||||
private static final String name = "SOCKS_CMD_RESPONSE_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksProtocolVersion version;
|
||||
private int fieldLength;
|
||||
|
@ -27,11 +27,6 @@ import java.util.List;
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksInitRequestDecoder extends ReplayingDecoder<SocksInitRequestDecoder.State> {
|
||||
private static final String name = "SOCKS_INIT_REQUEST_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private final List<SocksAuthScheme> authSchemes = new ArrayList<SocksAuthScheme>();
|
||||
private SocksProtocolVersion version;
|
||||
|
@ -26,11 +26,6 @@ import java.util.List;
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksInitResponseDecoder extends ReplayingDecoder<SocksInitResponseDecoder.State> {
|
||||
private static final String name = "SOCKS_INIT_RESPONSE_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksProtocolVersion version;
|
||||
private SocksAuthScheme authScheme;
|
||||
|
@ -28,12 +28,6 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class SocksMessageEncoder extends MessageToByteEncoder<SocksMessage> {
|
||||
private static final String name = "SOCKS_MESSAGE_ENCODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, SocksMessage msg, ByteBuf out) throws Exception {
|
||||
msg.encodeAsByteBuf(out);
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.applet;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import javax.swing.JApplet;
|
||||
|
||||
/**
|
||||
* {@link JApplet} which starts up a Server that receive data and discard it.
|
||||
*/
|
||||
public class AppletDiscardServer extends JApplet {
|
||||
|
||||
private static final long serialVersionUID = -7824894101960583175L;
|
||||
|
||||
private EventLoopGroup bossGroup;
|
||||
private EventLoopGroup workerGroup;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
bossGroup = new NioEventLoopGroup(1);
|
||||
workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new DiscardServerHandler());
|
||||
}
|
||||
});
|
||||
ChannelFuture f = bootstrap.bind(9999).sync();
|
||||
f.channel().closeFuture().sync();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
if (bossGroup != null) {
|
||||
bossGroup.shutdownGracefully();
|
||||
}
|
||||
if (workerGroup != null) {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DiscardServerHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
|
||||
System.out.println("Received: " + msg.toString(CharsetUtil.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -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,59 +21,39 @@ 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) {
|
||||
// Server is supposed to send nothing, but if it sends something, discard it.
|
||||
}
|
||||
|
||||
@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 messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) {
|
||||
// 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.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Handler implementation for the echo client. It initiates the ping-pong
|
||||
* traffic between the echo client and server by sending the first message to
|
||||
@ -30,19 +27,13 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class EchoClientHandler extends ChannelHandlerAdapter {
|
||||
|
||||
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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Handler implementation for the echo server.
|
||||
*/
|
||||
@Sharable
|
||||
public class EchoServerHandler extends ChannelHandlerAdapter {
|
||||
|
||||
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 messageReceived(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,14 +29,11 @@ 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");
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, BigInteger msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, BigInteger msg) {
|
||||
// Calculate the cumulative factorial and send it to the client.
|
||||
lastMultiplier = msg;
|
||||
factorial = factorial.multiply(msg);
|
||||
@ -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 messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||
File file = new File(msg);
|
||||
if (file.exists()) {
|
||||
if (!file.isFile()) {
|
||||
ctx.writeAndFlush("Not a file: " + file + '\n');
|
||||
return;
|
||||
}
|
||||
ctx.write(file + " " + file.length() + '\n');
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
FileRegion region = new DefaultFileRegion(fis.getChannel(), 0, file.length());
|
||||
ctx.write(region);
|
||||
ctx.writeAndFlush("\n");
|
||||
fis.close();
|
||||
} else {
|
||||
ctx.writeAndFlush("File not found: " + file + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.example.file;
|
||||
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.DefaultFileRegion;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.handler.stream.ChunkedFile;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class FileServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) {
|
||||
ctx.writeAndFlush("HELO: Type the path of the file to retrieve.\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||
RandomAccessFile raf = null;
|
||||
long length = -1;
|
||||
try {
|
||||
raf = new RandomAccessFile(msg, "r");
|
||||
length = raf.length();
|
||||
} catch (Exception e) {
|
||||
ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n');
|
||||
return;
|
||||
} finally {
|
||||
if (length < 0 && raf != null) {
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
|
||||
ctx.write("OK: " + raf.length() + '\n');
|
||||
if (ctx.pipeline().get(SslHandler.class) == null) {
|
||||
// SSL not enabled - can use zero-copy file transfer.
|
||||
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length));
|
||||
} else {
|
||||
// SSL enabled - cannot use zero-copy file transfer.
|
||||
ctx.write(new ChunkedFile(raf));
|
||||
}
|
||||
ctx.writeAndFlush("\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
|
||||
if (ctx.channel().isActive()) {
|
||||
ctx.writeAndFlush("ERR: " +
|
||||
cause.getClass().getSimpleName() + ": " +
|
||||
cause.getMessage() + '\n').addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ import io.netty.handler.codec.http.HttpVersion;
|
||||
public class OkResponseHandler extends ChannelHandlerAdapter {
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
final DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||
response.headers().set("custom-response-header", "Some value");
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
|
@ -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 messageReceived(
|
||||
ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
|
||||
public void messageReceived(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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
@ -27,44 +27,44 @@ import io.netty.util.CharsetUtil;
|
||||
public class HttpSnoopClientHandler extends SimpleChannelInboundHandler<HttpObject> {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) {
|
||||
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,59 +24,55 @@ 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
|
||||
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) {
|
||||
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,22 +64,22 @@ 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!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) {
|
||||
Channel ch = ctx.channel();
|
||||
if (!handshaker.isHandshakeComplete()) {
|
||||
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
|
||||
@ -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 messageReceived(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,14 +43,13 @@ 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";
|
||||
|
||||
private WebSocketServerHandshaker handshaker;
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) {
|
||||
if (msg instanceof FullHttpRequest) {
|
||||
handleHttpRequest(ctx, (FullHttpRequest) msg);
|
||||
} else if (msg instanceof WebSocketFrame) {
|
||||
@ -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 messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof FullHttpRequest) {
|
||||
handleHttpRequest(ctx, (FullHttpRequest) msg);
|
||||
} else if (msg instanceof WebSocketFrame) {
|
||||
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
|
||||
// Handle a bad request.
|
||||
if (!req.getDecoderResult().isSuccess()) {
|
||||
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow only GET methods.
|
||||
if (req.getMethod() != GET) {
|
||||
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the demo page and favicon.ico
|
||||
if ("/".equals(req.getUri())) {
|
||||
ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
|
||||
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
|
||||
|
||||
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
setContentLength(res, content.readableBytes());
|
||||
|
||||
sendHttpResponse(ctx, req, res);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("/favicon.ico".equals(req.getUri())) {
|
||||
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
|
||||
sendHttpResponse(ctx, req, res);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handshake
|
||||
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
|
||||
getWebSocketLocation(req), null, false);
|
||||
handshaker = wsFactory.newHandshaker(req);
|
||||
if (handshaker == null) {
|
||||
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
|
||||
} else {
|
||||
handshaker.handshake(ctx.channel(), req);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
||||
|
||||
// Check for closing frame
|
||||
if (frame instanceof CloseWebSocketFrame) {
|
||||
handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
|
||||
return;
|
||||
}
|
||||
if (frame instanceof PingWebSocketFrame) {
|
||||
ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
|
||||
return;
|
||||
}
|
||||
if (!(frame instanceof TextWebSocketFrame)) {
|
||||
throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()
|
||||
.getName()));
|
||||
}
|
||||
|
||||
// Send the uppercase string back.
|
||||
String request = ((TextWebSocketFrame) frame).text();
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine(String.format("%s received %s", ctx.channel(), request));
|
||||
}
|
||||
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
|
||||
}
|
||||
|
||||
private static void sendHttpResponse(
|
||||
ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
|
||||
// Generate an error page if response getStatus code is not OK (200).
|
||||
if (res.getStatus().code() != 200) {
|
||||
ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
|
||||
res.content().writeBytes(buf);
|
||||
buf.release();
|
||||
setContentLength(res, res.content().readableBytes());
|
||||
}
|
||||
|
||||
// Send the response and close the connection if necessary.
|
||||
ChannelFuture f = ctx.channel().write(res);
|
||||
if (!isKeepAlive(req) || res.getStatus().code() != 200) {
|
||||
f.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
||||
ctx.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
private static String getWebSocketLocation(FullHttpRequest req) {
|
||||
return "wss://" + req.headers().get(HOST) + WEBSOCKET_PATH;
|
||||
}
|
||||
}
|
@ -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;
|
@ -14,8 +14,6 @@
|
||||
*/
|
||||
package io.netty.example.http2;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Utility methods used by the example client and server.
|
||||
*/
|
||||
@ -26,74 +24,5 @@ public final class Http2ExampleUtil {
|
||||
*/
|
||||
public static final String UPGRADE_RESPONSE_HEADER = "Http-To-Http2-Upgrade";
|
||||
|
||||
public static final String STANDARD_HOST = "localhost";
|
||||
public static final int STANDARD_HTTP_PORT = 8080;
|
||||
public static final int STANDARD_HTTPS_PORT = 8443;
|
||||
public static final String PORT_ARG = "-port=";
|
||||
public static final String SSL_ARG = "-ssl=";
|
||||
public static final String HOST_ARG = "-host=";
|
||||
|
||||
/**
|
||||
* The configuration for the example client/server endpoints.
|
||||
*/
|
||||
public static final class EndpointConfig {
|
||||
private final boolean ssl;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public EndpointConfig(boolean ssl, String host, int port) {
|
||||
this.ssl = ssl;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public boolean isSsl() {
|
||||
return ssl;
|
||||
}
|
||||
|
||||
public String host() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EndpointConfig [ssl=" + ssl + ", host=" + host + ", port=" + port + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the command-line arguments to determine the configuration for the endpoint.
|
||||
*/
|
||||
public static EndpointConfig parseEndpointConfig(String[] args) {
|
||||
boolean ssl = false;
|
||||
int port = STANDARD_HTTP_PORT;
|
||||
String host = STANDARD_HOST;
|
||||
boolean portSpecified = false;
|
||||
for (String arg : args) {
|
||||
arg = arg.trim().toLowerCase(Locale.US);
|
||||
if (arg.startsWith(PORT_ARG)) {
|
||||
String value = arg.substring(PORT_ARG.length());
|
||||
port = Integer.parseInt(value);
|
||||
portSpecified = true;
|
||||
} else if (arg.startsWith(SSL_ARG)) {
|
||||
String value = arg.substring(SSL_ARG.length());
|
||||
ssl = Boolean.parseBoolean(value);
|
||||
if (!portSpecified) {
|
||||
// Use the appropriate default.
|
||||
port = ssl ? STANDARD_HTTPS_PORT : STANDARD_HTTP_PORT;
|
||||
}
|
||||
} else if (arg.startsWith(HOST_ARG)) {
|
||||
host = arg.substring(HOST_ARG.length());
|
||||
}
|
||||
}
|
||||
|
||||
return new EndpointConfig(ssl, host, port);
|
||||
}
|
||||
|
||||
private Http2ExampleUtil() {
|
||||
}
|
||||
private Http2ExampleUtil() { }
|
||||
}
|
||||
|
@ -23,16 +23,13 @@ import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.netty.example.http2.Http2ExampleUtil.*;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
|
||||
import static io.netty.handler.codec.http.HttpMethod.*;
|
||||
import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
|
||||
@ -40,22 +37,17 @@ import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
* An HTTP2 client that allows you to send HTTP2 frames to a server. Inbound and outbound frames are
|
||||
* logged. When run from the command-line, sends a single HEADERS frame to the server and gets back
|
||||
* a "Hello World" response.
|
||||
* <p>
|
||||
* To client accepts command-line arguments for {@code -host=<host/ip>}
|
||||
* <i>(default="localhost")</i>, {@code -port=<port number>} <i>(default: http=8080,
|
||||
* https=8443)</i>, and {@code -ssl=<true/false>} <i>(default=false)</i>.
|
||||
*/
|
||||
public class Http2Client {
|
||||
public final class Http2Client {
|
||||
|
||||
private final SslContext sslCtx;
|
||||
private final EndpointConfig config;
|
||||
private Http2ClientConnectionHandler http2ConnectionHandler;
|
||||
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 Http2Client(EndpointConfig config) throws SSLException {
|
||||
this.config = config;
|
||||
if (config.isSsl()) {
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Configure SSL.
|
||||
final SslContext sslCtx;
|
||||
if (SSL) {
|
||||
sslCtx = SslContext.newClientContext(
|
||||
null, InsecureTrustManagerFactory.INSTANCE, null,
|
||||
Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
|
||||
@ -63,96 +55,45 @@ public class Http2Client {
|
||||
} else {
|
||||
sslCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the client and waits for the HTTP/2 upgrade to occur.
|
||||
*/
|
||||
public void start() throws Exception {
|
||||
if (channel != null) {
|
||||
System.out.println("Already running!");
|
||||
return;
|
||||
}
|
||||
|
||||
workerGroup = new NioEventLoopGroup();
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(workerGroup);
|
||||
b.channel(NioSocketChannel.class);
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
b.remoteAddress(new InetSocketAddress(config.host(), config.port()));
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx);
|
||||
b.handler(initializer);
|
||||
|
||||
// Start the client.
|
||||
channel = b.connect().syncUninterruptibly().channel();
|
||||
System.out.println("Connected to [" + config.host() + ':' + config.port() + ']');
|
||||
|
||||
// Wait for the HTTP/2 upgrade to occur.
|
||||
http2ConnectionHandler = initializer.connectionHandler();
|
||||
http2ConnectionHandler.awaitInitialization();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the given request to the server.
|
||||
*/
|
||||
public void sendRequest(FullHttpRequest request) throws Exception {
|
||||
ChannelFuture requestFuture = channel.writeAndFlush(request).sync();
|
||||
System.out.println("Back from sending headers...");
|
||||
if (!requestFuture.isSuccess()) {
|
||||
throw new RuntimeException(requestFuture.cause());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the full response to be received.
|
||||
*/
|
||||
public void awaitResponse() throws Exception {
|
||||
http2ConnectionHandler.awaitResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the channel and waits for shutdown to complete.
|
||||
*/
|
||||
public void stop() {
|
||||
try {
|
||||
// Wait until the connection is closed.
|
||||
channel.close().syncUninterruptibly();
|
||||
} finally {
|
||||
if (workerGroup != null) {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Configure the client.
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(workerGroup);
|
||||
b.channel(NioSocketChannel.class);
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
b.remoteAddress(HOST, PORT);
|
||||
b.handler(initializer);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
EndpointConfig config = parseEndpointConfig(args);
|
||||
System.out.println(config);
|
||||
// Start the client.
|
||||
Channel channel = b.connect().syncUninterruptibly().channel();
|
||||
System.out.println("Connected to [" + HOST + ':' + PORT + ']');
|
||||
|
||||
final Http2Client client = new Http2Client(config);
|
||||
try {
|
||||
// Start the client and wait for the HTTP/2 upgrade to complete.
|
||||
client.start();
|
||||
// Wait for the HTTP/2 upgrade to occur.
|
||||
Http2ClientConnectionHandler http2ConnectionHandler = initializer.connectionHandler();
|
||||
http2ConnectionHandler.awaitInitialization();
|
||||
|
||||
// Create a simple GET request with just headers.
|
||||
FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/whatever");
|
||||
request.headers().add(HOST, config.host());
|
||||
request.headers().add(HttpHeaders.Names.HOST, HOST + ':' + PORT);
|
||||
|
||||
System.out.println("Sending request...");
|
||||
ChannelFuture requestFuture = client.channel.writeAndFlush(request).sync();
|
||||
System.out.println("Back from sending headers...");
|
||||
if (!requestFuture.isSuccess()) {
|
||||
requestFuture.cause().printStackTrace();
|
||||
return;
|
||||
}
|
||||
// Send the request to the server.
|
||||
System.err.println("Sending request...");
|
||||
ChannelFuture requestFuture = channel.writeAndFlush(request).sync();
|
||||
System.err.println("Back from sending headers...");
|
||||
requestFuture.sync();
|
||||
|
||||
// Waits for the complete response
|
||||
client.awaitResponse();
|
||||
http2ConnectionHandler.awaitResponse();
|
||||
System.out.println("Finished HTTP/2 request");
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
|
||||
// Wait until the connection is closed.
|
||||
channel.close().syncUninterruptibly();
|
||||
} finally {
|
||||
client.stop();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@
|
||||
*/
|
||||
package io.netty.example.http2.client;
|
||||
|
||||
import static io.netty.example.http2.Http2ExampleUtil.UPGRADE_RESPONSE_HEADER;
|
||||
import static io.netty.util.internal.logging.InternalLogLevel.INFO;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
@ -41,13 +39,18 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.netty.example.http2.Http2ExampleUtil.*;
|
||||
import static io.netty.util.internal.logging.InternalLogLevel.*;
|
||||
|
||||
/**
|
||||
* A subclass of the connection handler that interprets response messages as text and prints it out
|
||||
* to the console.
|
||||
*/
|
||||
public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler {
|
||||
private static final Http2FrameLogger logger = new Http2FrameLogger(INFO,
|
||||
InternalLoggerFactory.getInstance(Http2ClientConnectionHandler.class));
|
||||
|
||||
private static final Http2FrameLogger logger =
|
||||
new Http2FrameLogger(INFO, InternalLoggerFactory.getInstance(Http2ClientConnectionHandler.class));
|
||||
|
||||
private final ChannelPromise initPromise;
|
||||
private final ChannelPromise responsePromise;
|
||||
private ByteBuf collectedData;
|
||||
@ -88,8 +91,7 @@ public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler
|
||||
* Handles conversion of a {@link FullHttpMessage} to HTTP/2 frames.
|
||||
*/
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
|
||||
throws Exception {
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
|
||||
if (msg instanceof FullHttpMessage) {
|
||||
FullHttpMessage httpMsg = (FullHttpMessage) msg;
|
||||
boolean hasData = httpMsg.content().isReadable();
|
||||
@ -105,7 +107,7 @@ public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler
|
||||
writeData(ctx, promise, streamId, httpMsg.content(), 0, true, true, false);
|
||||
}
|
||||
} else {
|
||||
super.write(ctx, msg, promise);
|
||||
ctx.write(msg, promise);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,8 +172,7 @@ public class Http2ClientConnectionHandler extends AbstractHttp2ConnectionHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings)
|
||||
throws Http2Exception {
|
||||
public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
|
||||
if (!initPromise.isDone()) {
|
||||
initPromise.setSuccess();
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ public class HelloWorldHttp1Handler extends SimpleChannelInboundHandler<HttpRequ
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
|
||||
package io.netty.example.http2.server;
|
||||
|
||||
import static io.netty.example.http2.Http2ExampleUtil.UPGRADE_RESPONSE_HEADER;
|
||||
import static io.netty.util.internal.logging.InternalLogLevel.INFO;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.example.http2.client.Http2ClientConnectionHandler;
|
||||
@ -37,6 +35,9 @@ import io.netty.handler.codec.http2.Http2Settings;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import static io.netty.example.http2.Http2ExampleUtil.*;
|
||||
import static io.netty.util.internal.logging.InternalLogLevel.*;
|
||||
|
||||
/**
|
||||
* A simple handler that responds with the message "Hello World!".
|
||||
*/
|
||||
@ -84,7 +85,7 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
|
||||
*/
|
||||
@Override
|
||||
public void onHeadersRead(ChannelHandlerContext ctx, int streamId,
|
||||
io.netty.handler.codec.http2.Http2Headers headers, int padding, boolean endStream,
|
||||
Http2Headers headers, int padding, boolean endStream,
|
||||
boolean endSegment) throws Http2Exception {
|
||||
if (endStream) {
|
||||
sendResponse(ctx(), streamId);
|
||||
@ -96,7 +97,7 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
|
||||
*/
|
||||
@Override
|
||||
public void onHeadersRead(ChannelHandlerContext ctx, int streamId,
|
||||
io.netty.handler.codec.http2.Http2Headers headers, int streamDependency, short weight,
|
||||
Http2Headers headers, int streamDependency, short weight,
|
||||
boolean exclusive, int padding, boolean endStream, boolean endSegment)
|
||||
throws Http2Exception {
|
||||
if (endStream) {
|
||||
@ -133,7 +134,7 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
|
||||
|
||||
@Override
|
||||
public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
|
||||
io.netty.handler.codec.http2.Http2Headers headers, int padding) throws Http2Exception {
|
||||
Http2Headers headers, int padding) throws Http2Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,15 +157,15 @@ public class HelloWorldHttp2Handler extends AbstractHttp2ConnectionHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
super.exceptionCaught(ctx, cause);
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a "Hello World" DATA frame to the client.
|
||||
*/
|
||||
private void sendResponse(ChannelHandlerContext ctx, int streamId) throws Http2Exception {
|
||||
private void sendResponse(ChannelHandlerContext ctx, int streamId) {
|
||||
// Send a frame for the response status
|
||||
Http2Headers headers = DefaultHttp2Headers.newBuilder().status("200").build();
|
||||
writeHeaders(ctx(), ctx().newPromise(), streamId, headers, 0, false, false);
|
||||
|
@ -18,14 +18,12 @@ import io.netty.channel.ChannelHandler;
|
||||
import io.netty.handler.codec.http2.Http2OrHttpChooser;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Negotiates with the browser if HTTP2 or HTTP is going to be used. Once decided, the Netty
|
||||
* pipeline is setup with the correct handlers for the selected protocol.
|
||||
*/
|
||||
public class Http2OrHttpHandler extends Http2OrHttpChooser {
|
||||
private static final Logger logger = Logger.getLogger(Http2OrHttpHandler.class.getName());
|
||||
private static final int MAX_CONTENT_LENGTH = 1024 * 100;
|
||||
|
||||
public Http2OrHttpHandler() {
|
||||
@ -40,8 +38,7 @@ public class Http2OrHttpHandler extends Http2OrHttpChooser {
|
||||
protected SelectedProtocol getProtocol(SSLEngine engine) {
|
||||
String[] protocol = engine.getSession().getProtocol().split(":");
|
||||
SelectedProtocol selectedProtocol = SelectedProtocol.protocol(protocol[1]);
|
||||
|
||||
logger.info("Selected Protocol is " + selectedProtocol);
|
||||
System.err.println("Selected Protocol is " + selectedProtocol);
|
||||
return selectedProtocol;
|
||||
}
|
||||
|
||||
|
@ -16,15 +16,15 @@
|
||||
|
||||
package io.netty.example.http2.server;
|
||||
|
||||
import static io.netty.example.http2.Http2ExampleUtil.parseEndpointConfig;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
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.example.http2.Http2ExampleUtil.EndpointConfig;
|
||||
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||
|
||||
@ -33,54 +33,46 @@ import java.util.Arrays;
|
||||
/**
|
||||
* A HTTP/2 Server that responds to requests with a Hello World. Once started, you can test the
|
||||
* server with the example client.
|
||||
* <p>
|
||||
* To server accepts command-line arguments for {@code -port=<port number>} <i>(default: http=8080,
|
||||
* https=8443)</i>, and {@code -ssl=<true/false>} <i>(default=false)</i>.
|
||||
*/
|
||||
public class Http2Server {
|
||||
public final class Http2Server {
|
||||
|
||||
private final EndpointConfig config;
|
||||
static final boolean SSL = System.getProperty("ssl") != null;
|
||||
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
|
||||
|
||||
public Http2Server(EndpointConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
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(), null, null,
|
||||
Arrays.asList(
|
||||
SelectedProtocol.HTTP_2.protocolName(),
|
||||
SelectedProtocol.HTTP_1_1.protocolName()),
|
||||
0, 0);
|
||||
} else {
|
||||
sslCtx = null;
|
||||
}
|
||||
// Configure the server.
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.option(ChannelOption.SO_BACKLOG, 1024);
|
||||
b.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.childHandler(new Http2ServerInitializer(sslCtx));
|
||||
|
||||
// If SSL was selected, configure the SSL context.
|
||||
SslContext sslCtx = null;
|
||||
if (config.isSsl()) {
|
||||
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||
sslCtx = SslContext.newServerContext(
|
||||
ssc.certificate(), ssc.privateKey(), null, null,
|
||||
Arrays.asList(
|
||||
SelectedProtocol.HTTP_2.protocolName(),
|
||||
SelectedProtocol.HTTP_1_1.protocolName()),
|
||||
0, 0);
|
||||
}
|
||||
Channel ch = b.bind(PORT).sync().channel();
|
||||
|
||||
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
|
||||
.childHandler(new Http2ServerInitializer(sslCtx));
|
||||
System.err.println("Open your HTTP/2-enabled web browser and navigate to " +
|
||||
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
|
||||
|
||||
Channel ch = b.bind(config.port()).sync().channel();
|
||||
ch.closeFuture().sync();
|
||||
} finally {
|
||||
bossGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
EndpointConfig config = parseEndpointConfig(args);
|
||||
System.out.println(config);
|
||||
|
||||
System.out.println("HTTP2 server started at port " + config.port() + '.');
|
||||
new Http2Server(config).run();
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import io.netty.channel.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerAppender;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
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;
|
||||
@ -29,7 +28,7 @@ import io.netty.handler.codec.http.HttpServerUpgradeHandler;
|
||||
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Sets up the Netty pipeline for the example server. Depending on the endpoint config, sets up the
|
||||
@ -43,7 +42,7 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
public void initChannel(SocketChannel ch) {
|
||||
if (sslCtx != null) {
|
||||
configureSsl(ch);
|
||||
} else {
|
||||
@ -61,12 +60,12 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
/**
|
||||
* Configure the pipeline for a cleartext upgrade from HTTP to HTTP/2.
|
||||
*/
|
||||
private void configureClearText(SocketChannel ch) {
|
||||
private static void configureClearText(SocketChannel ch) {
|
||||
HttpCodec sourceCodec = new HttpCodec();
|
||||
HttpServerUpgradeHandler.UpgradeCodec upgradeCodec =
|
||||
new Http2ServerUpgradeCodec(new HelloWorldHttp2Handler());
|
||||
HttpServerUpgradeHandler upgradeHandler =
|
||||
new HttpServerUpgradeHandler(sourceCodec, Arrays.asList(upgradeCodec), 65536);
|
||||
new HttpServerUpgradeHandler(sourceCodec, Collections.singletonList(upgradeCodec), 65536);
|
||||
|
||||
ch.pipeline().addLast(sourceCodec);
|
||||
ch.pipeline().addLast(upgradeHandler);
|
||||
@ -76,8 +75,8 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
/**
|
||||
* Source codec for HTTP cleartext upgrade.
|
||||
*/
|
||||
private static final class HttpCodec extends ChannelHandlerAppender implements
|
||||
HttpServerUpgradeHandler.SourceCodec {
|
||||
private static final class HttpCodec
|
||||
extends ChannelHandlerAppender implements HttpServerUpgradeHandler.SourceCodec {
|
||||
HttpCodec() {
|
||||
add("httpRequestDecoder", new HttpRequestDecoder());
|
||||
add("httpResponseEncoder", new HttpResponseEncoder());
|
||||
@ -98,9 +97,9 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
*/
|
||||
private static class UserEventLogger extends ChannelHandlerAdapter {
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
|
||||
System.out.println("User Event Triggered: " + evt);
|
||||
super.userEventTriggered(ctx, evt);
|
||||
ctx.fireUserEventTriggered(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 DefaultEventLoopGroup();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import io.netty.channel.SimpleChannelInboundHandler;
|
||||
public class LocalEchoClientHandler extends SimpleChannelInboundHandler<Object> {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, Object msg) {
|
||||
// Print as received
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
@ -18,17 +18,16 @@ package io.netty.example.localecho;
|
||||
import io.netty.channel.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
|
||||
public class LocalEchoServerHandler extends ChannelHandlerAdapter {
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
|
@ -24,26 +24,37 @@ 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.http2.Http2OrHttpChooser.SelectedProtocol;
|
||||
import io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec;
|
||||
import io.netty.handler.codec.memcache.binary.BinaryMemcacheObjectAggregator;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Simple memcache client that demonstrates get and set commands against a memcache server.
|
||||
*/
|
||||
public class MemcacheClient {
|
||||
public final class MemcacheClient {
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
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", "11211"));
|
||||
|
||||
public MemcacheClient(String host, int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Configure SSL.
|
||||
final SslContext sslCtx;
|
||||
if (SSL) {
|
||||
sslCtx = SslContext.newClientContext(
|
||||
null, InsecureTrustManagerFactory.INSTANCE, null,
|
||||
Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
|
||||
0, 0);
|
||||
} else {
|
||||
sslCtx = null;
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
EventLoopGroup group = new NioEventLoopGroup();
|
||||
try {
|
||||
Bootstrap b = new Bootstrap();
|
||||
@ -53,6 +64,9 @@ public class MemcacheClient {
|
||||
@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 BinaryMemcacheClientCodec());
|
||||
p.addLast(new BinaryMemcacheObjectAggregator(Integer.MAX_VALUE));
|
||||
p.addLast(new MemcacheClientHandler());
|
||||
@ -60,7 +74,7 @@ public class MemcacheClient {
|
||||
});
|
||||
|
||||
// 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.
|
||||
System.out.println("Enter commands (quit to end)");
|
||||
@ -89,20 +103,4 @@ public class MemcacheClient {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Print usage if no argument is specified.
|
||||
if (args.length != 2) {
|
||||
System.err.println(
|
||||
"Usage: " + MemcacheClient.class.getSimpleName() +
|
||||
" <host> <port>");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse options.
|
||||
String host = args[0];
|
||||
int port = Integer.parseInt(args[1]);
|
||||
|
||||
new MemcacheClient(host, port).run();
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public class MemcacheClientHandler extends ChannelHandlerAdapter {
|
||||
* Transforms basic string requests to binary memcache requests
|
||||
*/
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
|
||||
String command = (String) msg;
|
||||
if (command.startsWith("get ")) {
|
||||
String key = command.substring("get ".length());
|
||||
@ -68,13 +68,13 @@ public class MemcacheClientHandler extends ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
FullBinaryMemcacheResponse res = (FullBinaryMemcacheResponse) msg;
|
||||
System.out.println(res.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.close();
|
||||
}
|
||||
|
@ -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.ChannelHandlerContext;
|
||||
|
||||
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 ChannelHandlerAdapter {
|
||||
|
||||
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.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Handles both client-side and server-side handler depending on which
|
||||
* constructor was called.
|
||||
*/
|
||||
public class ObjectEchoServerHandler extends ChannelHandlerAdapter {
|
||||
|
||||
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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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 ChannelHandlerAdapter {
|
||||
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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import io.netty.util.CharsetUtil;
|
||||
public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) {
|
||||
String response = msg.content().toString(CharsetUtil.UTF_8);
|
||||
if (response.startsWith("QOTM: ")) {
|
||||
System.out.println("Quote of the Moment: " + response.substring(6));
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelInboundHandler<D
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet) {
|
||||
System.err.println(packet);
|
||||
if ("QOTM?".equals(packet.content().toString(CharsetUtil.UTF_8))) {
|
||||
ctx.write(new DatagramPacket(
|
||||
@ -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() {
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public class RxtxClientHandler extends SimpleChannelInboundHandler<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, String msg) {
|
||||
if ("OK".equals(msg)) {
|
||||
System.out.println("Serial port responded to AT");
|
||||
} else {
|
||||
|
@ -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.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
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 ChannelHandlerAdapter {
|
||||
|
||||
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 ChannelHandlerAdapter {
|
||||
}
|
||||
|
||||
@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.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Handler implementation for the SCTP echo server.
|
||||
*/
|
||||
@Sharable
|
||||
public class SctpEchoServerHandler extends ChannelHandlerAdapter {
|
||||
|
||||
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 messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||
public void messageReceived(ChannelHandlerContext ctx, String msg) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user