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:
  - websocket/html5
  - websocketx/sslserver
  - localecho/multithreaded
- Add run-example.sh which simplifies launching an example from command
  line

Result:

Shorter and simpler examples.  A user can focus more on what it actually
does than miscellaneous stuff.  A user can launch an example very
easily.
This commit is contained in:
Trustin Lee 2014-05-22 17:00:32 +09:00
parent aa2c6b77e3
commit ba28679775
93 changed files with 3138 additions and 3847 deletions

16
pom.xml
View File

@ -726,10 +726,24 @@
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>netty-build</artifactId> <artifactId>netty-build</artifactId>
<version>20</version> <version>21</version>
</dependency> </dependency>
</dependencies> </dependencies>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3</version>
<configuration>
<executable>${java.home}/bin/java</executable>
<commandlineArgs>
-classpath %classpath
${argLine.example}
${exampleClass}
</commandlineArgs>
<classpathScope>runtime</classpathScope>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

87
run-example.sh Executable file
View File

@ -0,0 +1,87 @@
#!/bin/bash -e
EXAMPLE_MAP=(
'discard-client:org.jboss.netty.example.discard.DiscardClient'
'discard-server:org.jboss.netty.example.discard.DiscardServer'
'echo-client:org.jboss.netty.example.echo.EchoClient'
'echo-server:org.jboss.netty.example.echo.EchoServer'
'factorial-client:org.jboss.netty.example.factorial.FactorialClient'
'factorial-server:org.jboss.netty.example.factorial.FactorialServer'
'http-snoop-client:org.jboss.netty.example.http.snoop.HttpSnoopClient'
'http-snoop-server:org.jboss.netty.example.http.snoop.HttpSnoopServer'
'http-file-server:org.jboss.netty.example.http.file.HttpStaticFileServer'
'http-helloworld-server:org.jboss.netty.example.http.helloworld.HttpHelloWorldServer'
'http-upload-client:org.jboss.netty.example.http.upload.HttpUploadClient'
'http-upload-server:org.jboss.netty.example.http.upload.HttpUploadServer'
'websocket-client:org.jboss.netty.example.websocketx.client.WebSocketClient'
'websocket-server:org.jboss.netty.example.websocketx.server.WebSocketServer'
'localtime-client:org.jboss.netty.example.localtime.LocalTimeClient'
'localtime-server:org.jboss.netty.example.localtime.LocalTimeServer'
'objectecho-client:org.jboss.netty.example.objectecho.ObjectEchoClient'
'objectecho-server:org.jboss.netty.example.objectecho.ObjectEchoServer'
'quote-client:org.jboss.netty.example.qotm.QuoteOfTheMomentClient'
'quote-server:org.jboss.netty.example.qotm.QuoteOfTheMomentServer'
'securechat-client:org.jboss.netty.example.securechat.SecureChatClient'
'securechat-server:org.jboss.netty.example.securechat.SecureChatServer'
'telnet-client:org.jboss.netty.example.telnet.TelnetClient'
'telnet-server:org.jboss.netty.example.telnet.TelnetServer'
'proxy-server:org.jboss.netty.example.proxy.HexDumpProxy'
'uptime-client:org.jboss.netty.example.uptime.UptimeClient'
'local-transport:org.jboss.netty.example.local.LocalExample'
)
EXAMPLE=''
EXAMPLE_CLASS=''
EXAMPLE_ARGS='-D_'
I=0
while [[ $# -gt 0 ]]; do
ARG="$1"
shift
if [[ "$ARG" =~ (^-.+) ]]; then
EXAMPLE_ARGS="$EXAMPLE_ARGS $ARG"
else
EXAMPLE="$ARG"
for E in "${EXAMPLE_MAP[@]}"; do
KEY="${E%%:*}"
VAL="${E##*:}"
if [[ "$EXAMPLE" == "$KEY" ]]; then
EXAMPLE_CLASS="$VAL"
break
fi
done
break
fi
done
if [[ -z "$EXAMPLE" ]] || [[ -z "$EXAMPLE_CLASS" ]] || [[ $# -ne 0 ]]; then
echo " Usage: $0 [-D<name>[=<value>] ...] <example-name>" >&2
echo "Example: $0 -Dport=8443 -Dssl http-server" >&2
echo " $0 -Dhost=127.0.0.1 -Dport=8009 echo-client" >&2
echo >&2
echo "Available examples:" >&2
echo >&2
I=0
for E in "${EXAMPLE_MAP[@]}"; do
if [[ $I -eq 0 ]]; then
echo -n ' '
fi
printf '%-24s' "${E%%:*}"
((I++)) || true
if [[ $I -eq 2 ]]; then
I=0
echo
fi
done >&2
if [[ $I -ne 0 ]]; then
echo >&2
fi
echo >&2
exit 1
fi
cd "`dirname "$0"`"
echo "[INFO] Running: $EXAMPLE ($EXAMPLE_CLASS $EXAMPLE_ARGS)"
exec mvn -nsu compile exec:exec -DargLine.example="$EXAMPLE_ARGS" -DexampleClass="$EXAMPLE_CLASS"

View File

@ -15,75 +15,63 @@
*/ */
package org.jboss.netty.example.discard; package org.jboss.netty.example.discard;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Keeps sending random data to the specified address. * Keeps sending random data to the specified address.
*/ */
public class DiscardClient { public final class DiscardClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int firstMessageSize; static final int PORT = Integer.parseInt(System.getProperty("port", "8009"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public DiscardClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.firstMessageSize = firstMessageSize; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() { // Configure the bootstrap.
// Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the pipeline factory. try {
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline( ChannelPipeline p = Channels.pipeline();
new DiscardClientHandler(firstMessageSize)); if (sslCtx != null) {
} p.addLast("ssl", sslCtx.newHandler(HOST, PORT));
}); }
p.addLast("discard", new DiscardClientHandler());
return p;
}
});
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(HOST, PORT));
// Wait until the connection is closed or the connection attempt fails. // Wait until the connection is closed or the connection attempt fails.
future.getChannel().getCloseFuture().awaitUninterruptibly(); future.getChannel().getCloseFuture().sync();
} finally {
// Shut down thread pools to exit. // Shut down thread pools to exit.
bootstrap.releaseExternalResources(); bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + DiscardClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
} }
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new DiscardClient(host, port, firstMessageSize).run();
} }
} }

View File

@ -15,9 +15,6 @@
*/ */
package org.jboss.netty.example.discard; package org.jboss.netty.example.discard;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
@ -35,18 +32,11 @@ import org.jboss.netty.channel.WriteCompletionEvent;
*/ */
public class DiscardClientHandler extends SimpleChannelUpstreamHandler { public class DiscardClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
DiscardClientHandler.class.getName());
private long transferredBytes; private long transferredBytes;
private final byte[] content; private final byte[] content;
public DiscardClientHandler(int messageSize) { public DiscardClientHandler() {
if (messageSize <= 0) { content = new byte[DiscardClient.SIZE];
throw new IllegalArgumentException(
"messageSize: " + messageSize);
}
content = new byte[messageSize];
} }
public long getTransferredBytes() { public long getTransferredBytes() {
@ -57,7 +47,7 @@ public class DiscardClientHandler extends SimpleChannelUpstreamHandler {
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
if (((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) { if (((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) {
logger.info(e.toString()); System.err.println(e);
} }
} }
@ -90,10 +80,7 @@ public class DiscardClientHandler extends SimpleChannelUpstreamHandler {
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log( e.getCause().printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -15,51 +15,53 @@
*/ */
package org.jboss.netty.example.discard; package org.jboss.netty.example.discard;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Discards any incoming data. * Discards any incoming data.
*/ */
public class DiscardServer { public final class DiscardServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8009"));
public DiscardServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() { // Configure the bootstrap.
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline(new DiscardServerHandler()); ChannelPipeline p = Channels.pipeline();
if (sslCtx != null) {
p.addLast("ssl", sslCtx.newHandler());
}
p.addLast("discard", new DiscardServerHandler());
return p;
} }
}); });
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new DiscardServer(port).run();
} }
} }

View File

@ -15,9 +15,6 @@
*/ */
package org.jboss.netty.example.discard; package org.jboss.netty.example.discard;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
@ -31,9 +28,6 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
*/ */
public class DiscardServerHandler extends SimpleChannelUpstreamHandler { public class DiscardServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
DiscardServerHandler.class.getName());
private long transferredBytes; private long transferredBytes;
public long getTransferredBytes() { public long getTransferredBytes() {
@ -43,7 +37,7 @@ public class DiscardServerHandler extends SimpleChannelUpstreamHandler {
@Override @Override
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
// Let SimpleChannelHandler call actual event handler methods below. // Let SimpleChannelHandler call actual event handler methods below.
@ -59,10 +53,7 @@ public class DiscardServerHandler extends SimpleChannelUpstreamHandler {
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log( e.getCause().printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,15 +15,17 @@
*/ */
package org.jboss.netty.example.echo; package org.jboss.netty.example.echo;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Sends one message when a connection is open and echoes back any received * Sends one message when a connection is open and echoes back any received
@ -31,62 +33,51 @@ import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
* traffic between the echo client and server by sending the first message to * traffic between the echo client and server by sending the first message to
* the server. * the server.
*/ */
public class EchoClient { public final class EchoClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int firstMessageSize; static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public EchoClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.git
this.port = port; final SslContext sslCtx;
this.firstMessageSize = firstMessageSize; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() { // Configure the bootstrap.
// Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the pipeline factory. try {
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline( ChannelPipeline p = Channels.pipeline();
new EchoClientHandler(firstMessageSize)); if (sslCtx != null) {
} p.addLast("ssl", sslCtx.newHandler(HOST, PORT));
}); }
p.addLast("echo", new EchoClientHandler());
return p;
}
});
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("receiveBufferSize", 1048576);
bootstrap.setOption("sendBufferSize", 1048576);
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(HOST, PORT));
// Wait until the connection is closed or the connection attempt fails. // Wait until the connection is closed or the connection attempt fails.
future.getChannel().getCloseFuture().awaitUninterruptibly(); future.getChannel().getCloseFuture().sync();
} finally {
// Shut down thread pools to exit. // Shut down thread pools to exit.
bootstrap.releaseExternalResources(); bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length < 2 || args.length > 3) {
System.err.println(
"Usage: " + EchoClient.class.getSimpleName() +
" <host> <port> [<first message size>]");
return;
} }
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new EchoClient(host, port, firstMessageSize).run();
} }
} }

View File

@ -15,10 +15,6 @@
*/ */
package org.jboss.netty.example.echo; package org.jboss.netty.example.echo;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
@ -27,6 +23,8 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Handler implementation for the echo client. It initiates the ping-pong * Handler implementation for the echo client. It initiates the ping-pong
* traffic between the echo client and server by sending the first message to * traffic between the echo client and server by sending the first message to
@ -34,21 +32,14 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
*/ */
public class EchoClientHandler extends SimpleChannelUpstreamHandler { public class EchoClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
EchoClientHandler.class.getName());
private final ChannelBuffer firstMessage; private final ChannelBuffer firstMessage;
private final AtomicLong transferredBytes = new AtomicLong(); private final AtomicLong transferredBytes = new AtomicLong();
/** /**
* Creates a client-side handler. * Creates a client-side handler.
*/ */
public EchoClientHandler(int firstMessageSize) { public EchoClientHandler() {
if (firstMessageSize <= 0) { firstMessage = ChannelBuffers.buffer(EchoClient.SIZE);
throw new IllegalArgumentException(
"firstMessageSize: " + firstMessageSize);
}
firstMessage = ChannelBuffers.buffer(firstMessageSize);
for (int i = 0; i < firstMessage.capacity(); i ++) { for (int i = 0; i < firstMessage.capacity(); i ++) {
firstMessage.writeByte((byte) i); firstMessage.writeByte((byte) i);
} }
@ -59,29 +50,23 @@ public class EchoClientHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelConnected( public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelHandlerContext ctx, ChannelStateEvent e) {
// Send the first message. Server will not send anything here // Send the first message. Server will not send anything here
// because the firstMessage's capacity is 0. // because the firstMessage's capacity is 0.
e.getChannel().write(firstMessage); e.getChannel().write(firstMessage);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer. // Send back the received message to the remote peer.
transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes()); transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
e.getChannel().write(e.getMessage()); e.getChannel().write(e.getMessage());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log( e.getCause().printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,51 +15,57 @@
*/ */
package org.jboss.netty.example.echo; package org.jboss.netty.example.echo;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Echoes back any received data from a client. * Echoes back any received data from a client.
*/ */
public class EchoServer { public final class EchoServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public EchoServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() { // Configure the bootstrap.
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline(new EchoServerHandler()); ChannelPipeline p = Channels.pipeline();
if (sslCtx != null) {
p.addLast("ssl", sslCtx.newHandler());
}
p.addLast("echo", new EchoServerHandler());
return p;
} }
}); });
// Bind and start to accept incoming connections. bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.bind(new InetSocketAddress(port)); bootstrap.setOption("child.receiveBufferSize", 1048576);
} bootstrap.setOption("child.sendBufferSize", 1048576);
public static void main(String[] args) throws Exception { // Bind and start to accept incoming connections.
int port; bootstrap.bind(new InetSocketAddress(PORT));
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new EchoServer(port).run();
} }
} }

View File

@ -15,24 +15,19 @@
*/ */
package org.jboss.netty.example.echo; package org.jboss.netty.example.echo;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Handler implementation for the echo server. * Handler implementation for the echo server.
*/ */
public class EchoServerHandler extends SimpleChannelUpstreamHandler { public class EchoServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
EchoServerHandler.class.getName());
private final AtomicLong transferredBytes = new AtomicLong(); private final AtomicLong transferredBytes = new AtomicLong();
public long getTransferredBytes() { public long getTransferredBytes() {
@ -40,21 +35,16 @@ public class EchoServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer. // Send back the received message to the remote peer.
transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes()); transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
e.getChannel().write(e.getMessage()); e.getChannel().write(e.getMessage());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised. // Close the connection when an exception is raised.
logger.log( e.getCause().printStackTrace();
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,14 +15,14 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import java.math.BigInteger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.CorruptedFrameException; import org.jboss.netty.handler.codec.frame.CorruptedFrameException;
import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.jboss.netty.handler.codec.frame.FrameDecoder;
import java.math.BigInteger;
/** /**
* Decodes the binary representation of a {@link BigInteger} prepended * Decodes the binary representation of a {@link BigInteger} prepended
* with a magic number ('F' or 0x46) and a 32-bit integer length prefix into a * with a magic number ('F' or 0x46) and a 32-bit integer length prefix into a
@ -32,8 +32,7 @@ import org.jboss.netty.handler.codec.frame.FrameDecoder;
public class BigIntegerDecoder extends FrameDecoder { public class BigIntegerDecoder extends FrameDecoder {
@Override @Override
protected Object decode( protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
// Wait until the length prefix is available. // Wait until the length prefix is available.
if (buffer.readableBytes() < 5) { if (buffer.readableBytes() < 5) {
return null; return null;
@ -45,8 +44,7 @@ public class BigIntegerDecoder extends FrameDecoder {
int magicNumber = buffer.readUnsignedByte(); int magicNumber = buffer.readUnsignedByte();
if (magicNumber != 'F') { if (magicNumber != 'F') {
buffer.resetReaderIndex(); buffer.resetReaderIndex();
throw new CorruptedFrameException( throw new CorruptedFrameException("Invalid magic number: " + magicNumber);
"Invalid magic number: " + magicNumber);
} }
// Wait until the whole data is available. // Wait until the whole data is available.

View File

@ -15,76 +15,59 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Sends a sequence of integers to a {@link FactorialServer} to calculate * Sends a sequence of integers to a {@link FactorialServer} to calculate
* the factorial of the specified integer. * the factorial of the specified integer.
*/ */
public class FactorialClient { public final class FactorialClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int count; static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
static final int COUNT = Integer.parseInt(System.getProperty("count", "1000"));
public FactorialClient(String host, int port, int count) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.count = count; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() { // Configure the bootstrap.
// Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the event pipeline factory. try {
bootstrap.setPipelineFactory(new FactorialClientPipelineFactory(count)); bootstrap.setPipelineFactory(new FactorialClientPipelineFactory(sslCtx));
// Make a new connection. // Make a new connection.
ChannelFuture connectFuture = ChannelFuture connectFuture = bootstrap.connect(new InetSocketAddress(HOST, PORT));
bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection is made successfully. // Wait until the connection is made successfully.
Channel channel = connectFuture.awaitUninterruptibly().getChannel(); Channel channel = connectFuture.sync().getChannel();
// Get the handler instance to retrieve the answer. // Get the handler instance to retrieve the answer.
FactorialClientHandler handler = FactorialClientHandler handler = (FactorialClientHandler) channel.getPipeline().getLast();
(FactorialClientHandler) channel.getPipeline().getLast();
// Print out the answer. // Print out the answer.
System.err.format( System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial());
"Factorial of %,d is: %,d", count, handler.getFactorial()); } finally {
// Shut down all thread pools to exit.
// Shut down all thread pools to exit. bootstrap.releaseExternalResources();
bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length != 3) {
System.err.println(
"Usage: " + FactorialClient.class.getSimpleName() +
" <host> <port> <count>");
return;
} }
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
int count = Integer.parseInt(args[2]);
if (count <= 0) {
throw new IllegalArgumentException("count must be a positive integer.");
}
new FactorialClient(host, port, count).run();
} }
} }

View File

@ -15,12 +15,6 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import java.math.BigInteger;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
@ -31,6 +25,10 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.math.BigInteger;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/** /**
* Handler for a client-side channel. This handler maintains stateful * Handler for a client-side channel. This handler maintains stateful
* information which is specific to a certain channel using member variables. * information which is specific to a certain channel using member variables.
@ -40,39 +38,32 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
*/ */
public class FactorialClientHandler extends SimpleChannelUpstreamHandler { public class FactorialClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
FactorialClientHandler.class.getName());
// Stateful properties // Stateful properties
private int i = 1; private int i = 1;
private int receivedMessages; private int receivedMessages;
private final int count;
final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>(); final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>();
public FactorialClientHandler(int count) {
this.count = count;
}
public BigInteger getFactorial() { public BigInteger getFactorial() {
boolean interrupted = false; boolean interrupted = false;
for (;;) { try {
try { for (;;) {
BigInteger factorial = answer.take(); try {
if (interrupted) { return answer.take();
Thread.currentThread().interrupt(); } catch (InterruptedException ignore) {
interrupted = true;
} }
return factorial; }
} catch (InterruptedException e) { } finally {
interrupted = true; if (interrupted) {
Thread.currentThread().interrupt();
} }
} }
} }
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@ -91,7 +82,7 @@ public class FactorialClientHandler extends SimpleChannelUpstreamHandler {
public void messageReceived( public void messageReceived(
ChannelHandlerContext ctx, final MessageEvent e) { ChannelHandlerContext ctx, final MessageEvent e) {
receivedMessages ++; receivedMessages ++;
if (receivedMessages == count) { if (receivedMessages == FactorialClient.COUNT) {
// Offer the answer after closing the connection. // Offer the answer after closing the connection.
e.getChannel().close().addListener(new ChannelFutureListener() { e.getChannel().close().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) { public void operationComplete(ChannelFuture future) {
@ -103,19 +94,15 @@ public class FactorialClientHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
private void sendNumbers(ChannelStateEvent e) { private void sendNumbers(ChannelStateEvent e) {
Channel channel = e.getChannel(); Channel channel = e.getChannel();
while (channel.isWritable()) { while (channel.isWritable()) {
if (i <= count) { if (i <= FactorialClient.COUNT) {
channel.write(i); channel.write(i);
i ++; i ++;
} else { } else {

View File

@ -15,29 +15,34 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.compression.ZlibDecoder; import org.jboss.netty.handler.codec.compression.ZlibDecoder;
import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibEncoder;
import org.jboss.netty.handler.codec.compression.ZlibWrapper; import org.jboss.netty.handler.codec.compression.ZlibWrapper;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
/** /**
* Creates a newly configured {@link ChannelPipeline} for a client-side channel. * Creates a newly configured {@link ChannelPipeline} for a client-side channel.
*/ */
public class FactorialClientPipelineFactory implements public class FactorialClientPipelineFactory implements ChannelPipelineFactory {
ChannelPipelineFactory {
private final int count; private final SslContext sslCtx;
public FactorialClientPipelineFactory(int count) { public FactorialClientPipelineFactory(SslContext sslCtx) {
this.count = count; this.sslCtx = sslCtx;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Enabls SSL if necessary.
if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler(FactorialClient.HOST, FactorialClient.PORT));
}
// Enable stream compression (you can remove these two if unnecessary) // Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast("deflater", new ZlibEncoder(ZlibWrapper.GZIP)); pipeline.addLast("deflater", new ZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast("inflater", new ZlibDecoder(ZlibWrapper.GZIP)); pipeline.addLast("inflater", new ZlibDecoder(ZlibWrapper.GZIP));
@ -47,7 +52,7 @@ public class FactorialClientPipelineFactory implements
pipeline.addLast("encoder", new NumberEncoder()); pipeline.addLast("encoder", new NumberEncoder());
// and then business logic. // and then business logic.
pipeline.addLast("handler", new FactorialClientHandler(count)); pipeline.addLast("handler", new FactorialClientHandler());
return pipeline; return pipeline;
} }

View File

@ -15,25 +15,33 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Receives a sequence of integers from a {@link FactorialClient} to calculate * Receives a sequence of integers from a {@link FactorialClient} to calculate
* the factorial of the specified integer. * the factorial of the specified integer.
*/ */
public class FactorialServer { public final class FactorialServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
public FactorialServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -41,19 +49,9 @@ public class FactorialServer {
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the event pipeline factory. // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new FactorialServerPipelineFactory()); bootstrap.setPipelineFactory(new FactorialServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new FactorialServer(port).run();
} }
} }

View File

@ -15,11 +15,6 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import java.math.BigInteger;
import java.util.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelStateEvent;
@ -27,6 +22,9 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.math.BigInteger;
import java.util.Formatter;
/** /**
* Handler for a server-side channel. This handler maintains stateful * Handler for a server-side channel. This handler maintains stateful
* information which is specific to a certain channel using member variables. * information which is specific to a certain channel using member variables.
@ -36,26 +34,20 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
*/ */
public class FactorialServerHandler extends SimpleChannelUpstreamHandler { public class FactorialServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
FactorialServerHandler.class.getName());
// Stateful properties. // Stateful properties.
private int lastMultiplier = 1; private int lastMultiplier = 1;
private BigInteger factorial = new BigInteger(new byte[] { 1 }); private BigInteger factorial = new BigInteger(new byte[] { 1 });
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Calculate the cumulative factorial and send it to the client. // Calculate the cumulative factorial and send it to the client.
BigInteger number; BigInteger number;
if (e.getMessage() instanceof BigInteger) { if (e.getMessage() instanceof BigInteger) {
@ -69,19 +61,13 @@ public class FactorialServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelDisconnected(ChannelHandlerContext ctx, public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelStateEvent e) throws Exception { System.err.println(new Formatter().format("Factorial of %,d is: %,d", lastMultiplier, factorial));
logger.info(new Formatter().format(
"Factorial of %,d is: %,d", lastMultiplier, factorial).toString());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,23 +15,33 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.compression.ZlibDecoder; import org.jboss.netty.handler.codec.compression.ZlibDecoder;
import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibEncoder;
import org.jboss.netty.handler.codec.compression.ZlibWrapper; import org.jboss.netty.handler.codec.compression.ZlibWrapper;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
/** /**
* Creates a newly configured {@link ChannelPipeline} for a server-side channel. * Creates a newly configured {@link ChannelPipeline} for a server-side channel.
*/ */
public class FactorialServerPipelineFactory implements public class FactorialServerPipelineFactory implements ChannelPipelineFactory {
ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception { private final SslContext sslCtx;
public FactorialServerPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler());
}
// Enable stream compression (you can remove these two if unnecessary) // Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast("deflater", new ZlibEncoder(ZlibWrapper.GZIP)); pipeline.addLast("deflater", new ZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast("inflater", new ZlibDecoder(ZlibWrapper.GZIP)); pipeline.addLast("inflater", new ZlibDecoder(ZlibWrapper.GZIP));

View File

@ -15,14 +15,14 @@
*/ */
package org.jboss.netty.example.factorial; package org.jboss.netty.example.factorial;
import java.math.BigInteger;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
import java.math.BigInteger;
/** /**
* Encodes a {@link Number} into the binary representation prepended with * Encodes a {@link Number} into the binary representation prepended with
* a magic number ('F' or 0x46) and a 32-bit length prefix. For example, 42 * a magic number ('F' or 0x46) and a 32-bit length prefix. For example, 42
@ -31,8 +31,7 @@ import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
public class NumberEncoder extends OneToOneEncoder { public class NumberEncoder extends OneToOneEncoder {
@Override @Override
protected Object encode( protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) {
ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
if (!(msg instanceof Number)) { if (!(msg instanceof Number)) {
// Ignore what this encoder can't encode. // Ignore what this encoder can't encode.
return msg; return msg;

View File

@ -23,19 +23,21 @@ import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class HttpStaticFileServer { public final class HttpStaticFileServer {
private static final boolean useSsl = false; // Set to true to enable SSL. static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
private final SslContext sslCtx; public static void main(String[] args) throws Exception {
private final int port; // Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public HttpStaticFileServer(SslContext sslCtx, int port) {
this.sslCtx = sslCtx;
this.port = port;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -46,25 +48,6 @@ public class HttpStaticFileServer {
bootstrap.setPipelineFactory(new HttpStaticFileServerPipelineFactory(sslCtx)); bootstrap.setPipelineFactory(new HttpStaticFileServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
final SslContext sslCtx;
if (useSsl) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
new HttpStaticFileServer(sslCtx, port).run();
} }
} }

View File

@ -102,9 +102,9 @@ import static org.jboss.netty.handler.codec.http.HttpVersion.*;
*/ */
public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler { public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
public static final String HTTP_DATE_GMT_TIMEZONE = "GMT"; static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
public static final int HTTP_CACHE_SECONDS = 60; static final int HTTP_CACHE_SECONDS = 60;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
@ -182,7 +182,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
public void operationProgressed( public void operationProgressed(
ChannelFuture future, long amount, long current, long total) { ChannelFuture future, long amount, long current, long total) {
System.out.printf("%s: %d / %d (+%d)%n", path, current, total, amount); System.err.printf("%s: %d / %d (+%d)%n", path, current, total, amount);
} }
}); });
} }
@ -195,8 +195,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
Channel ch = e.getChannel(); Channel ch = e.getChannel();
Throwable cause = e.getCause(); Throwable cause = e.getCause();
if (cause instanceof TooLongFrameException) { if (cause instanceof TooLongFrameException) {
@ -240,9 +239,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
response.setContent(ChannelBuffers.copiedBuffer( response.setContent(ChannelBuffers.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
"Failure: " + status.toString() + "\r\n",
CharsetUtil.UTF_8));
// Close the connection as soon as the error message is sent. // Close the connection as soon as the error message is sent.
ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE); ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
@ -250,9 +247,6 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
/** /**
* When file timestamp is the same as what the browser is sending up, send a "304 Not Modified" * When file timestamp is the same as what the browser is sending up, send a "304 Not Modified"
*
* @param ctx
* Context
*/ */
private static void sendNotModified(ChannelHandlerContext ctx) { private static void sendNotModified(ChannelHandlerContext ctx) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NOT_MODIFIED); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NOT_MODIFIED);
@ -264,9 +258,6 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
/** /**
* Sets the Date header for the HTTP response * Sets the Date header for the HTTP response
*
* @param response
* HTTP response
*/ */
private static void setDateHeader(HttpResponse response) { private static void setDateHeader(HttpResponse response) {
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
@ -279,10 +270,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
/** /**
* Sets the Date and Cache headers for the HTTP Response * Sets the Date and Cache headers for the HTTP Response
* *
* @param response * @param fileToCache the file to extract content type
* HTTP response
* @param fileToCache
* file to extract content type
*/ */
private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) { private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) {
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
@ -296,21 +284,16 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
time.add(Calendar.SECOND, HTTP_CACHE_SECONDS); time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
response.headers().set(EXPIRES, dateFormatter.format(time.getTime())); response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));
response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS); response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
response.headers().set( response.headers().set(LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
} }
/** /**
* Sets the content type header for the HTTP Response * Sets the content type header for the HTTP Response
* *
* @param response * @param file the file to extract content type
* HTTP response
* @param file
* file to extract content type
*/ */
private static void setContentTypeHeader(HttpResponse response, File file) { private static void setContentTypeHeader(HttpResponse response, File file) {
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath())); response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
} }
} }

View File

@ -33,7 +33,7 @@ public class HttpStaticFileServerPipelineFactory implements ChannelPipelineFacto
this.sslCtx = sslCtx; this.sslCtx = sslCtx;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();

View File

@ -17,6 +17,8 @@ package org.jboss.netty.example.http.helloworld;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -25,15 +27,21 @@ import java.util.concurrent.Executors;
* An HTTP server that sends back the content of the received HTTP request * An HTTP server that sends back the content of the received HTTP request
* in a pretty plaintext form. * in a pretty plaintext form.
*/ */
public class HttpHelloWorldServer { public final class HttpHelloWorldServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpHelloWorldServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -44,20 +52,9 @@ public class HttpHelloWorldServer {
bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.tcpNoDelay", true);
// Set up the event pipeline factory. // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new HttpHelloWorldServerPipelineFactory()); bootstrap.setPipelineFactory(new HttpHelloWorldServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
} }
public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new HttpHelloWorldServer(port).run();
}
} }

View File

@ -38,7 +38,7 @@ public class HttpHelloWorldServerHandler extends SimpleChannelUpstreamHandler {
private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }; private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Object msg = e.getMessage(); Object msg = e.getMessage();
Channel ch = e.getChannel(); Channel ch = e.getChannel();
if (msg instanceof HttpRequest) { if (msg instanceof HttpRequest) {
@ -66,8 +66,7 @@ public class HttpHelloWorldServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -20,19 +20,25 @@ import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpContentCompressor;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*; import static org.jboss.netty.channel.Channels.*;
public class HttpHelloWorldServerPipelineFactory implements ChannelPipelineFactory { public class HttpHelloWorldServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
private final SslContext sslCtx;
public HttpHelloWorldServerPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Uncomment the following line if you want HTTPS if (sslCtx != null) {
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); pipeline.addLast("ssl", sslCtx.newHandler());
//engine.setUseClientMode(false); }
//pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("decoder", new HttpRequestDecoder());
// Uncomment the following line if you don't want to handle HttpChunks. // Uncomment the following line if you don't want to handle HttpChunks.
//pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));

View File

@ -36,17 +36,14 @@ import java.util.concurrent.Executors;
* A simple HTTP client that prints out the content of the HTTP response to * A simple HTTP client that prints out the content of the HTTP response to
* {@link System#out} to test {@link HttpSnoopServer}. * {@link System#out} to test {@link HttpSnoopServer}.
*/ */
public class HttpSnoopClient { public final class HttpSnoopClient {
private final URI uri; static final String URL = System.getProperty("url", "http://127.0.0.1:8080/");
public HttpSnoopClient(URI uri) { public static void main(String[] args) throws Exception {
this.uri = uri; URI uri = new URI(URL);
}
public void run() throws Exception {
String scheme = uri.getScheme() == null? "http" : uri.getScheme(); String scheme = uri.getScheme() == null? "http" : uri.getScheme();
String host = uri.getHost() == null? "localhost" : uri.getHost(); String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
int port = uri.getPort(); int port = uri.getPort();
if (port == -1) { if (port == -1) {
if ("http".equalsIgnoreCase(scheme)) { if ("http".equalsIgnoreCase(scheme)) {
@ -76,52 +73,37 @@ public class HttpSnoopClient {
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the event pipeline factory. try {
bootstrap.setPipelineFactory(new HttpSnoopClientPipelineFactory(sslCtx)); // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new HttpSnoopClientPipelineFactory(sslCtx, host, port));
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails. // Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel(); Channel channel = future.sync().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace(); // Prepare the HTTP request.
HttpRequest request = new DefaultHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
request.headers().set(HttpHeaders.Names.HOST, host);
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
// Set some example cookies.
CookieEncoder httpCookieEncoder = new CookieEncoder(false);
httpCookieEncoder.addCookie("my-cookie", "foo");
httpCookieEncoder.addCookie("another-cookie", "bar");
request.headers().set(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode());
// Send the HTTP request.
channel.write(request);
// Wait for the server to close the connection.
channel.getCloseFuture().sync();
} finally {
// Shut down executor threads to exit.
bootstrap.releaseExternalResources(); bootstrap.releaseExternalResources();
return;
} }
// Prepare the HTTP request.
HttpRequest request = new DefaultHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
request.headers().set(HttpHeaders.Names.HOST, host);
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
// Set some example cookies.
CookieEncoder httpCookieEncoder = new CookieEncoder(false);
httpCookieEncoder.addCookie("my-cookie", "foo");
httpCookieEncoder.addCookie("another-cookie", "bar");
request.headers().set(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode());
// Send the HTTP request.
channel.write(request);
// Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly();
// Shut down executor threads to exit.
bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println(
"Usage: " + HttpSnoopClient.class.getSimpleName() +
" <URL>");
return;
}
URI uri = new URI(args[0]);
new HttpSnoopClient(uri).run();
} }
} }

View File

@ -28,42 +28,42 @@ public class HttpSnoopClientHandler extends SimpleChannelUpstreamHandler {
private boolean readingChunks; private boolean readingChunks;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
if (!readingChunks) { if (!readingChunks) {
HttpResponse response = (HttpResponse) e.getMessage(); HttpResponse response = (HttpResponse) e.getMessage();
System.out.println("STATUS: " + response.getStatus()); System.err.println("STATUS: " + response.getStatus());
System.out.println("VERSION: " + response.getProtocolVersion()); System.err.println("VERSION: " + response.getProtocolVersion());
System.out.println(); System.err.println();
if (!response.headers().names().isEmpty()) { if (!response.headers().names().isEmpty()) {
for (String name: response.headers().names()) { for (String name: response.headers().names()) {
for (String value: response.headers().getAll(name)) { for (String value: response.headers().getAll(name)) {
System.out.println("HEADER: " + name + " = " + value); System.err.println("HEADER: " + name + " = " + value);
} }
} }
System.out.println(); System.err.println();
} }
if (response.isChunked()) { if (response.isChunked()) {
readingChunks = true; readingChunks = true;
System.out.println("CHUNKED CONTENT {"); System.err.println("CHUNKED CONTENT {");
} else { } else {
ChannelBuffer content = response.getContent(); ChannelBuffer content = response.getContent();
if (content.readable()) { if (content.readable()) {
System.out.println("CONTENT {"); System.err.println("CONTENT {");
System.out.println(content.toString(CharsetUtil.UTF_8)); System.err.println(content.toString(CharsetUtil.UTF_8));
System.out.println("} END OF CONTENT"); System.err.println("} END OF CONTENT");
} }
} }
} else { } else {
HttpChunk chunk = (HttpChunk) e.getMessage(); HttpChunk chunk = (HttpChunk) e.getMessage();
if (chunk.isLast()) { if (chunk.isLast()) {
readingChunks = false; readingChunks = false;
System.out.println("} END OF CHUNKED CONTENT"); System.err.println("} END OF CHUNKED CONTENT");
} else { } else {
System.out.print(chunk.getContent().toString(CharsetUtil.UTF_8)); System.err.print(chunk.getContent().toString(CharsetUtil.UTF_8));
System.out.flush(); System.err.flush();
} }
} }
} }

View File

@ -26,18 +26,22 @@ import static org.jboss.netty.channel.Channels.*;
public class HttpSnoopClientPipelineFactory implements ChannelPipelineFactory { public class HttpSnoopClientPipelineFactory implements ChannelPipelineFactory {
private final SslContext sslCtx; private final SslContext sslCtx;
private final String host;
private final int port;
public HttpSnoopClientPipelineFactory(SslContext sslCtx) { public HttpSnoopClientPipelineFactory(SslContext sslCtx, String host, int port) {
this.sslCtx = sslCtx; this.sslCtx = sslCtx;
this.host = host;
this.port = port;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Enable HTTPS if necessary. // Enable HTTPS if necessary.
if (sslCtx != null) { if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler()); pipeline.addLast("ssl", sslCtx.newHandler(host, port));
} }
pipeline.addLast("codec", new HttpClientCodec()); pipeline.addLast("codec", new HttpClientCodec());

View File

@ -17,6 +17,8 @@ package org.jboss.netty.example.http.snoop;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -25,15 +27,21 @@ import java.util.concurrent.Executors;
* An HTTP server that sends back the content of the received HTTP request * An HTTP server that sends back the content of the received HTTP request
* in a pretty plaintext form. * in a pretty plaintext form.
*/ */
public class HttpSnoopServer { public final class HttpSnoopServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public HttpSnoopServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -44,20 +52,9 @@ public class HttpSnoopServer {
bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.tcpNoDelay", true);
// Set up the event pipeline factory. // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new HttpSnoopServerPipelineFactory()); bootstrap.setPipelineFactory(new HttpSnoopServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
} }
public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new HttpSnoopServer(port).run();
}
} }

View File

@ -15,16 +15,6 @@
*/ */
package org.jboss.netty.example.http.snoop; package org.jboss.netty.example.http.snoop;
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
@ -45,6 +35,16 @@ import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.QueryStringDecoder; import org.jboss.netty.handler.codec.http.QueryStringDecoder;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler { public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
private HttpRequest request; private HttpRequest request;
@ -53,7 +53,7 @@ public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
private final StringBuilder buf = new StringBuilder(); private final StringBuilder buf = new StringBuilder();
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
if (!readingChunks) { if (!readingChunks) {
HttpRequest request = this.request = (HttpRequest) e.getMessage(); HttpRequest request = this.request = (HttpRequest) e.getMessage();
@ -174,8 +174,7 @@ public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -15,24 +15,30 @@
*/ */
package org.jboss.netty.example.http.snoop; package org.jboss.netty.example.http.snoop;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpContentCompressor;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
public class HttpSnoopServerPipelineFactory implements ChannelPipelineFactory { public class HttpSnoopServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
private final SslContext sslCtx;
public HttpSnoopServerPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Uncomment the following line if you want HTTPS if (sslCtx != null) {
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); pipeline.addLast("ssl", sslCtx.newHandler());
//engine.setUseClientMode(false); }
//pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("decoder", new HttpRequestDecoder());
// Uncomment the following line if you don't want to handle HttpChunks. // Uncomment the following line if you don't want to handle HttpChunks.
//pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));

View File

@ -41,88 +41,81 @@ import java.util.concurrent.Executors;
* for the detailed instruction on how to deploy the server-side HTTP tunnel in * for the detailed instruction on how to deploy the server-side HTTP tunnel in
* your Servlet container. * your Servlet container.
*/ */
public class HttpTunnelingClientExample { public final class HttpTunnelingClientExample {
private final URI uri; static final String URL = System.getProperty("url", "http://localhost:8080/netty-tunnel");
public HttpTunnelingClientExample(URI uri) { public static void main(String[] args) throws Exception {
this.uri = uri; URI uri = new URI(URL);
}
public void run() throws Exception {
String scheme = uri.getScheme() == null? "http" : uri.getScheme(); String scheme = uri.getScheme() == null? "http" : uri.getScheme();
String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
int port = uri.getPort();
if (port == -1) {
if ("http".equalsIgnoreCase(scheme)) {
port = 80;
} else if ("https".equalsIgnoreCase(scheme)) {
port = 443;
}
}
if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
System.err.println("Only HTTP(S) is supported.");
return;
}
// Configure the client. // Configure the client.
ClientBootstrap b = new ClientBootstrap( ClientBootstrap b = new ClientBootstrap(
new HttpTunnelingClientSocketChannelFactory( new HttpTunnelingClientSocketChannelFactory(
new OioClientSocketChannelFactory(Executors.newCachedThreadPool()))); new OioClientSocketChannelFactory(Executors.newCachedThreadPool())));
b.setPipelineFactory(new ChannelPipelineFactory() { try {
public ChannelPipeline getPipeline() throws Exception { b.setPipelineFactory(new ChannelPipelineFactory() {
return Channels.pipeline( public ChannelPipeline getPipeline() {
new StringDecoder(), return Channels.pipeline(
new StringEncoder(), new StringDecoder(),
new LoggingHandler(InternalLogLevel.INFO)); new StringEncoder(),
} new LoggingHandler(InternalLogLevel.INFO));
}); }
});
// Set additional options required by the HTTP tunneling transport. // Set additional options required by the HTTP tunneling transport.
b.setOption("serverName", uri.getHost()); b.setOption("serverName", uri.getHost());
b.setOption("serverPath", uri.getRawPath()); b.setOption("serverPath", uri.getRawPath());
// Configure SSL if necessary // Configure SSL if necessary
if ("https".equals(scheme)) { if ("https".equals(scheme)) {
b.setOption("sslContext", new JdkSslClientContext(InsecureTrustManagerFactory.INSTANCE).context()); b.setOption("sslContext", new JdkSslClientContext(InsecureTrustManagerFactory.INSTANCE).context());
} else if (!"http".equals(scheme)) {
// Only HTTP and HTTPS are supported.
System.err.println("Only HTTP(S) is supported.");
return;
}
// Make the connection attempt.
ChannelFuture channelFuture = b.connect(
new InetSocketAddress(uri.getHost(), uri.getPort()));
channelFuture.awaitUninterruptibly();
// Read commands from the stdin.
System.out.println("Enter text ('quit' to exit)");
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (; ;) {
String line = in.readLine();
if (line == null || "quit".equalsIgnoreCase(line)) {
break;
} }
// Sends the received line to the server. // Make the connection attempt.
lastWriteFuture = channelFuture.getChannel().write(line); ChannelFuture channelFuture = b.connect(new InetSocketAddress(host, port));
channelFuture.sync();
// Read commands from the stdin.
System.err.println("Enter text ('quit' to exit)");
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null || "quit".equalsIgnoreCase(line)) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channelFuture.getChannel().write(line);
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
// Close the connection.
channelFuture.getChannel().close().sync();
} finally {
// Shut down all threads.
b.releaseExternalResources();
} }
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
channelFuture.getChannel().close();
// Wait until the connection is closed or the connection attempt fails.
channelFuture.getChannel().getCloseFuture().awaitUninterruptibly();
// Shut down all threads.
b.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println(
"Usage: " + HttpTunnelingClientExample.class.getSimpleName() +
" <URL>");
System.err.println(
"Example: " + HttpTunnelingClientExample.class.getSimpleName() +
" http://localhost:8080/netty-tunnel");
return;
}
URI uri = new URI(args[0]);
new HttpTunnelingClientExample(uri).run();
} }
} }

View File

@ -31,54 +31,38 @@ import org.jboss.netty.handler.codec.http.multipart.DiskAttribute;
import org.jboss.netty.handler.codec.http.multipart.DiskFileUpload; import org.jboss.netty.handler.codec.http.multipart.DiskFileUpload;
import org.jboss.netty.handler.codec.http.multipart.HttpDataFactory; import org.jboss.netty.handler.codec.http.multipart.HttpDataFactory;
import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestEncoder; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestEncoder.ErrorDataEncoderException;
import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData; import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData;
import org.jboss.netty.handler.ssl.SslContext; import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate; import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class HttpUploadClient { public final class HttpUploadClient {
private static final InternalLogger logger = static final String BASE_URL = System.getProperty("baseUrl", "http://127.0.0.1:8080/");
InternalLoggerFactory.getInstance(HttpUploadClient.class); static final String FILE = System.getProperty("file", "upload.txt");
private final String baseUri; public static void main(String[] args) throws Exception {
private final String filePath;
public HttpUploadClient(String baseUri, String filePath) {
this.baseUri = baseUri;
this.filePath = filePath;
}
public void run() throws Exception {
String postSimple, postFile, get; String postSimple, postFile, get;
if (baseUri.endsWith("/")) { if (BASE_URL.endsWith("/")) {
postSimple = baseUri + "formpost"; postSimple = BASE_URL + "formpost";
postFile = baseUri + "formpostmultipart"; postFile = BASE_URL + "formpostmultipart";
get = baseUri + "formget"; get = BASE_URL + "formget";
} else { } else {
postSimple = baseUri + "/formpost"; postSimple = BASE_URL + "/formpost";
postFile = baseUri + "/formpostmultipart"; postFile = BASE_URL + "/formpostmultipart";
get = baseUri + "/formget"; get = BASE_URL + "/formget";
}
URI uriSimple;
try {
uriSimple = new URI(postSimple);
} catch (URISyntaxException e) {
logger.error("Invalid URI syntax" + e.getCause());
return;
} }
URI uriSimple = new URI(postSimple);
String scheme = uriSimple.getScheme() == null? "http" : uriSimple.getScheme(); String scheme = uriSimple.getScheme() == null? "http" : uriSimple.getScheme();
String host = uriSimple.getHost() == null? "localhost" : uriSimple.getHost(); String host = uriSimple.getHost() == null? "127.0.0.1" : uriSimple.getHost();
int port = uriSimple.getPort(); int port = uriSimple.getPort();
if (port == -1) { if (port == -1) {
if ("http".equalsIgnoreCase(scheme)) { if ("http".equalsIgnoreCase(scheme)) {
@ -89,7 +73,7 @@ public class HttpUploadClient {
} }
if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
logger.error("Only HTTP(S) is supported."); System.err.println("Only HTTP(S) is supported.");
return; return;
} }
@ -102,17 +86,10 @@ public class HttpUploadClient {
sslCtx = null; sslCtx = null;
} }
URI uriFile; URI uriFile = new URI(postFile);
try { File file = new File(FILE);
uriFile = new URI(postFile); if (!file.canRead()) {
} catch (URISyntaxException e) { throw new FileNotFoundException(FILE);
logger.error("Error: " + e.getMessage());
return;
}
File file = new File(filePath);
if (! file.canRead()) {
logger.error("A correct path is needed");
return;
} }
// Configure the client. // Configure the client.
@ -121,58 +98,50 @@ public class HttpUploadClient {
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the event pipeline factory. // Set up the factory: here using a mixed memory/disk based on size threshold
bootstrap.setPipelineFactory(new HttpUploadClientPipelineFactory(sslCtx)); HttpDataFactory factory =
new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE
// setup the factory: here using a mixed memory/disk based on size threshold try {
HttpDataFactory factory = new DefaultHttpDataFactory( // Set up the event pipeline factory.
DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE bootstrap.setPipelineFactory(new HttpUploadClientPipelineFactory(sslCtx, host, port));
DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
DiskFileUpload.baseDirectory = null; // system temp directory
DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
DiskAttribute.baseDirectory = null; // system temp directory
// Simple Get form: no factory used (not usable) DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
List<Entry<String, String>> headers = DiskFileUpload.baseDirectory = null; // system temp directory
formget(bootstrap, host, port, get, uriSimple); DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
if (headers == null) { DiskAttribute.baseDirectory = null; // system temp directory
// Simple Get form: no factory used (not usable)
List<Entry<String, String>> headers = formget(bootstrap, host, port, get, uriSimple);
// Simple Post form: factory used for big attributes
List<InterfaceHttpData> bodylist = formpost(bootstrap, host, port, uriSimple, file, factory, headers);
// Multipart Post form: factory used
formpostmultipart(bootstrap, host, port, uriFile, factory, headers, bodylist);
} finally {
// Shut down executor threads to exit.
bootstrap.releaseExternalResources();
// Really clean all temporary files if they still exist
factory.cleanAllHttpDatas(); factory.cleanAllHttpDatas();
return;
} }
// Simple Post form: factory used for big attributes
List<InterfaceHttpData> bodylist =
formpost(bootstrap, host, port, uriSimple, file, factory, headers);
if (bodylist == null) {
factory.cleanAllHttpDatas();
return;
}
// Multipart Post form: factory used
formpostmultipart(bootstrap, host, port, uriFile, factory, headers, bodylist);
// Shut down executor threads to exit.
bootstrap.releaseExternalResources();
// Really clean all temporary files if they still exist
factory.cleanAllHttpDatas();
} }
/** /**
* Standard usage of HTTP API in Netty without file Upload (get is not able to achieve File upload * Standard usage of HTTP API in Netty without file Upload (get is not able to achieve File upload
* due to limitation on request size). * due to limitation on request size).
*
* @return the list of headers that will be used in every example after * @return the list of headers that will be used in every example after
**/ **/
private static List<Entry<String, String>> formget(ClientBootstrap bootstrap, String host, int port, String get, private static List<Entry<String, String>> formget(
URI uriSimple) { ClientBootstrap bootstrap, String host, int port, String get, URI uriSimple) throws Exception {
// XXX /formget // XXX /formget
// No use of HttpPostRequestEncoder since not a POST // No use of HttpPostRequestEncoder since not a POST
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails. // Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel(); Channel channel = future.sync().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return null;
}
// Prepare the HTTP request. // Prepare the HTTP request.
QueryStringEncoder encoder = new QueryStringEncoder(get); QueryStringEncoder encoder = new QueryStringEncoder(get);
@ -185,28 +154,22 @@ public class HttpUploadClient {
encoder.addParam("thirdinfo", "third value\r\ntest second line\r\n\r\nnew line\r\n"); encoder.addParam("thirdinfo", "third value\r\ntest second line\r\n\r\nnew line\r\n");
encoder.addParam("Send", "Send"); encoder.addParam("Send", "Send");
URI uriGet; URI uriGet = new URI(encoder.toString());
try { HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
uriGet = new URI(encoder.toString());
} catch (URISyntaxException e) {
logger.error("Error: " + e.getMessage());
bootstrap.releaseExternalResources();
return null;
}
HttpRequest request = new DefaultHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.HOST, host);
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ',' + request.headers().set(
HttpHeaders.Values.DEFLATE); HttpHeaders.Names.ACCEPT_ENCODING,
HttpHeaders.Values.GZIP + ',' + HttpHeaders.Values.DEFLATE);
request.headers().set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); request.headers().set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
request.headers().set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr"); request.headers().set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");
request.headers().set(HttpHeaders.Names.REFERER, uriSimple.toString()); request.headers().set(HttpHeaders.Names.REFERER, uriSimple.toString());
request.headers().set(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side"); request.headers().set(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side");
request.headers().set(HttpHeaders.Names.ACCEPT, request.headers().set(
HttpHeaders.Names.ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
//connection will not close but needed //connection will not close but needed
// request.headers().set("Connection","keep-alive"); // request.headers().set("Connection","keep-alive");
// request.headers().set("Keep-Alive","300"); // request.headers().set("Keep-Alive","300");
@ -221,7 +184,7 @@ public class HttpUploadClient {
channel.write(request); channel.write(request);
// Wait for the server to close the connection. // Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly(); channel.getCloseFuture().sync();
return headers; return headers;
} }
@ -231,24 +194,18 @@ public class HttpUploadClient {
* *
* @return the list of HttpData object (attribute and file) to be reused on next post * @return the list of HttpData object (attribute and file) to be reused on next post
*/ */
private static List<InterfaceHttpData> formpost(ClientBootstrap bootstrap, private static List<InterfaceHttpData> formpost(
String host, int port, ClientBootstrap bootstrap,
URI uriSimple, File file, HttpDataFactory factory, String host, int port, URI uriSimple, File file, HttpDataFactory factory,
List<Entry<String, String>> headers) throws ErrorDataEncoderException { List<Entry<String, String>> headers) throws Exception {
// XXX /formpost // XXX /formpost
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails. // Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel(); Channel channel = future.sync().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return null;
}
// Prepare the HTTP request. // Prepare the HTTP request.
HttpRequest request = new DefaultHttpRequest( HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());
HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());
// Use the PostBody encoder // Use the PostBody encoder
HttpPostRequestEncoder bodyRequestEncoder = HttpPostRequestEncoder bodyRequestEncoder =
@ -264,6 +221,7 @@ public class HttpUploadClient {
bodyRequestEncoder.addBodyAttribute("info", "first value"); bodyRequestEncoder.addBodyAttribute("info", "first value");
bodyRequestEncoder.addBodyAttribute("secondinfo", "secondvalue <20><><EFBFBD>&"); bodyRequestEncoder.addBodyAttribute("secondinfo", "secondvalue <20><><EFBFBD>&");
bodyRequestEncoder.addBodyAttribute("thirdinfo", textArea); bodyRequestEncoder.addBodyAttribute("thirdinfo", textArea);
bodyRequestEncoder.addBodyAttribute("fourthinfo", textAreaLong);
bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false); bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false);
// finalize request // finalize request
@ -278,7 +236,7 @@ public class HttpUploadClient {
// test if request was chunked and if so, finish the write // test if request was chunked and if so, finish the write
if (bodyRequestEncoder.isChunked()) { // could do either request.isChunked() if (bodyRequestEncoder.isChunked()) { // could do either request.isChunked()
// either do it through ChunkedWriteHandler // either do it through ChunkedWriteHandler
channel.write(bodyRequestEncoder).awaitUninterruptibly(); channel.write(bodyRequestEncoder).sync();
} }
// Do not clear here since we will reuse the InterfaceHttpData on the next request // Do not clear here since we will reuse the InterfaceHttpData on the next request
@ -289,30 +247,24 @@ public class HttpUploadClient {
// bodyRequestEncoder.cleanFiles(); // bodyRequestEncoder.cleanFiles();
// Wait for the server to close the connection. // Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly(); channel.getCloseFuture().sync();
return bodylist; return bodylist;
} }
/** /**
* Multipart example * Multipart example
*/ */
private static void formpostmultipart(ClientBootstrap bootstrap, String host, int port, private static void formpostmultipart(
URI uriFile, HttpDataFactory factory, ClientBootstrap bootstrap, String host, int port, URI uriFile, HttpDataFactory factory,
List<Entry<String, String>> headers, List<InterfaceHttpData> bodylist) throws ErrorDataEncoderException { List<Entry<String, String>> headers, List<InterfaceHttpData> bodylist) throws Exception {
// XXX /formpostmultipart // XXX /formpostmultipart
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails. // Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel(); Channel channel = future.sync().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return;
}
// Prepare the HTTP request. // Prepare the HTTP request.
HttpRequest request = new DefaultHttpRequest( HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString());
HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString());
// Use the PostBody encoder // Use the PostBody encoder
HttpPostRequestEncoder bodyRequestEncoder = HttpPostRequestEncoder bodyRequestEncoder =
@ -334,28 +286,14 @@ public class HttpUploadClient {
// test if request was chunked and if so, finish the write // test if request was chunked and if so, finish the write
if (bodyRequestEncoder.isChunked()) { if (bodyRequestEncoder.isChunked()) {
channel.write(bodyRequestEncoder).awaitUninterruptibly(); channel.write(bodyRequestEncoder).sync();
} }
// Now no more use of file representation (and list of HttpData) // Now no more use of file representation (and list of HttpData)
bodyRequestEncoder.cleanFiles(); bodyRequestEncoder.cleanFiles();
// Wait for the server to close the connection. // Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly(); channel.getCloseFuture().sync();
}
public static void main(String[] args) throws Exception {
if (args.length != 2) {
logger.error(
"Usage: " + HttpUploadClient.class.getSimpleName() +
" baseURI filePath");
return;
}
String baseUri = args[0];
String filePath = args[1];
new HttpUploadClient(baseUri, filePath).run();
} }
// use to simulate a small TEXTAREA field in a form // use to simulate a small TEXTAREA field in a form

View File

@ -22,58 +22,52 @@ import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpChunk;
import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
public class HttpUploadClientHandler extends SimpleChannelUpstreamHandler { public class HttpUploadClientHandler extends SimpleChannelUpstreamHandler {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(HttpUploadClientHandler.class);
private boolean readingChunks; private boolean readingChunks;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
if (!readingChunks) { if (!readingChunks) {
HttpResponse response = (HttpResponse) e.getMessage(); HttpResponse response = (HttpResponse) e.getMessage();
logger.info("STATUS: " + response.getStatus()); System.err.println("STATUS: " + response.getStatus());
logger.info("VERSION: " + response.getProtocolVersion()); System.err.println("VERSION: " + response.getProtocolVersion());
if (!response.headers().names().isEmpty()) { if (!response.headers().names().isEmpty()) {
for (String name: response.headers().names()) { for (String name: response.headers().names()) {
for (String value: response.headers().getAll(name)) { for (String value: response.headers().getAll(name)) {
logger.info("HEADER: " + name + " = " + value); System.err.println("HEADER: " + name + " = " + value);
} }
} }
} }
if (response.getStatus().getCode() == 200 && response.isChunked()) { if (response.getStatus().getCode() == 200 && response.isChunked()) {
readingChunks = true; readingChunks = true;
logger.info("CHUNKED CONTENT {"); System.err.println("CHUNKED CONTENT {");
} else { } else {
ChannelBuffer content = response.getContent(); ChannelBuffer content = response.getContent();
if (content.readable()) { if (content.readable()) {
logger.info("CONTENT {"); System.err.println("CONTENT {");
logger.info(content.toString(CharsetUtil.UTF_8)); System.err.println(content.toString(CharsetUtil.UTF_8));
logger.info("} END OF CONTENT"); System.err.println("} END OF CONTENT");
} }
} }
} else { } else {
HttpChunk chunk = (HttpChunk) e.getMessage(); HttpChunk chunk = (HttpChunk) e.getMessage();
if (chunk.isLast()) { if (chunk.isLast()) {
readingChunks = false; readingChunks = false;
logger.info("} END OF CHUNKED CONTENT"); System.err.println("} END OF CHUNKED CONTENT");
} else { } else {
logger.info(chunk.getContent().toString(CharsetUtil.UTF_8)); System.err.println(chunk.getContent().toString(CharsetUtil.UTF_8));
} }
} }
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -26,19 +26,24 @@ import org.jboss.netty.handler.stream.ChunkedWriteHandler;
import static org.jboss.netty.channel.Channels.*; import static org.jboss.netty.channel.Channels.*;
public class HttpUploadClientPipelineFactory implements ChannelPipelineFactory { public class HttpUploadClientPipelineFactory implements ChannelPipelineFactory {
private final SslContext sslCtx;
public HttpUploadClientPipelineFactory(SslContext sslCtx) { private final SslContext sslCtx;
private final String host;
private final int port;
public HttpUploadClientPipelineFactory(SslContext sslCtx, String host, int port) {
this.sslCtx = sslCtx; this.sslCtx = sslCtx;
this.host = host;
this.port = port;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Enable HTTPS if necessary. // Enable HTTPS if necessary.
if (sslCtx != null) { if (sslCtx != null) {
SslHandler handler = sslCtx.newHandler(); SslHandler handler = sslCtx.newHandler(host, port);
handler.setIssueHandshake(true); handler.setIssueHandshake(true);
pipeline.addLast("ssl", handler); pipeline.addLast("ssl", handler);
} }

View File

@ -23,19 +23,21 @@ import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class HttpUploadServer { public final class HttpUploadServer {
private static final boolean useSsl = false; // Set to true to enable SSL. static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
private final SslContext sslCtx; public static void main(String[] args) throws Exception {
private final int port; // Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public HttpUploadServer(SslContext sslCtx, int port) {
this.sslCtx = sslCtx;
this.port = port;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -46,25 +48,6 @@ public class HttpUploadServer {
bootstrap.setPipelineFactory(new HttpUploadServerPipelineFactory(sslCtx)); bootstrap.setPipelineFactory(new HttpUploadServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
SslContext sslCtx;
if (useSsl) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
new HttpUploadServer(sslCtx, port).run();
} }
} }

View File

@ -50,8 +50,6 @@ import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.Incom
import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException; import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData; import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData;
import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType; import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
import java.io.IOException; import java.io.IOException;
@ -64,19 +62,9 @@ import java.util.Set;
public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler { public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
private static final InternalLogger logger = private static final HttpDataFactory factory =
InternalLoggerFactory.getInstance(HttpUploadServerHandler.class); new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE
private HttpRequest request;
private boolean readingChunks;
private final StringBuilder responseContent = new StringBuilder();
private static final HttpDataFactory factory = new DefaultHttpDataFactory(
DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE
private HttpPostRequestDecoder decoder;
static { static {
//To limit to roughly 5MB each attribute, including fileupload //To limit to roughly 5MB each attribute, including fileupload
//factory.setMaxLimit(5000000); //factory.setMaxLimit(5000000);
@ -89,9 +77,13 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
DiskAttribute.baseDirectory = null; // system temp directory DiskAttribute.baseDirectory = null; // system temp directory
} }
private final StringBuilder responseContent = new StringBuilder();
private HttpPostRequestDecoder decoder;
private HttpRequest request;
private boolean readingChunks;
@Override @Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
throws Exception {
if (decoder != null) { if (decoder != null) {
decoder.cleanFiles(); decoder.cleanFiles();
} }
@ -116,18 +108,13 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
responseContent.setLength(0); responseContent.setLength(0);
responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
responseContent.append("===================================\r\n"); responseContent.append("===================================\r\n");
responseContent.append("VERSION: " + request.getProtocolVersion().getText() + "\r\n");
responseContent.append("VERSION: " + responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n");
request.getProtocolVersion().getText() + "\r\n");
responseContent.append("REQUEST_URI: " + request.getUri() +
"\r\n\r\n");
responseContent.append("\r\n\r\n"); responseContent.append("\r\n\r\n");
// new method // new method
for (Entry<String, String> entry: request.headers()) { for (Entry<String, String> entry: request.headers()) {
responseContent.append("HEADER: " + entry.getKey() + '=' + responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n");
entry.getValue() + "\r\n");
} }
responseContent.append("\r\n\r\n"); responseContent.append("\r\n\r\n");
@ -141,14 +128,12 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
cookies = decoder.decode(value); cookies = decoder.decode(value);
} }
for (Cookie cookie: cookies) { for (Cookie cookie: cookies) {
responseContent.append("COOKIE: " + cookie.toString() + "\r\n"); responseContent.append("COOKIE: " + cookie + "\r\n");
} }
responseContent.append("\r\n\r\n"); responseContent.append("\r\n\r\n");
QueryStringDecoder decoderQuery = new QueryStringDecoder(request QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri());
.getUri()); Map<String, List<String>> uriAttributes = decoderQuery.getParameters();
Map<String, List<String>> uriAttributes = decoderQuery
.getParameters();
for (Entry<String, List<String>> attr: uriAttributes.entrySet()) { for (Entry<String, List<String>> attr: uriAttributes.entrySet()) {
for (String attrVal: attr.getValue()) { for (String attrVal: attr.getValue()) {
responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n"); responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n");
@ -174,10 +159,8 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
return; return;
} }
responseContent.append("Is Chunked: " + request.isChunked() + responseContent.append("Is Chunked: " + request.isChunked() + "\r\n");
"\r\n"); responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n");
responseContent.append("IsMultipart: " + decoder.isMultipart() +
"\r\n");
if (request.isChunked()) { if (request.isChunked()) {
// Chunk version // Chunk version
responseContent.append("Chunks: "); responseContent.append("Chunks: ");
@ -185,8 +168,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
} else { } else {
// Not chunk version // Not chunk version
readHttpDataAllReceive(e.getChannel()); readHttpDataAllReceive(e.getChannel());
responseContent responseContent.append("\r\n\r\nEND OF NOT CHUNKED CONTENT\r\n");
.append("\r\n\r\nEND OF NOT CHUNKED CONTENT\r\n");
writeResponse(e.getChannel()); writeResponse(e.getChannel());
} }
} else { } else {
@ -249,8 +231,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
} }
} catch (EndOfDataDecoderException e1) { } catch (EndOfDataDecoderException e1) {
// end // end
responseContent responseContent.append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
.append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
} }
} }
@ -271,17 +252,14 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
} }
if (value.length() > 100) { if (value.length() > 100) {
responseContent.append("\r\nBODY Attribute: " + responseContent.append("\r\nBODY Attribute: " +
attribute.getHttpDataType().name() + ": " + attribute.getHttpDataType().name() + ": " + attribute.getName() + " data too long\r\n");
attribute.getName() + " data too long\r\n");
} else { } else {
responseContent.append("\r\nBODY Attribute: " + responseContent.append(
attribute.getHttpDataType().name() + ": " + "\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": " + attribute + "\r\n");
attribute.toString() + "\r\n");
} }
} else { } else {
responseContent.append("\r\nBODY FileUpload: " + responseContent.append(
data.getHttpDataType().name() + ": " + data.toString() + "\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data + "\r\n");
"\r\n");
if (data.getHttpDataType() == HttpDataType.FileUpload) { if (data.getHttpDataType() == HttpDataType.FileUpload) {
FileUpload fileUpload = (FileUpload) data; FileUpload fileUpload = (FileUpload) data;
if (fileUpload.isCompleted()) { if (fileUpload.isCompleted()) {
@ -295,9 +273,8 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
} }
responseContent.append("\r\n"); responseContent.append("\r\n");
} else { } else {
responseContent responseContent.append(
.append("\tFile too long to be printed out:" + "\tFile too long to be printed out:" + fileUpload.length() + "\r\n");
fileUpload.length() + "\r\n");
} }
// fileUpload.isInMemory();// tells if the file is in Memory // fileUpload.isInMemory();// tells if the file is in Memory
// or on File // or on File
@ -306,8 +283,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
// decoder.removeFileUploadFromClean(fileUpload); //remove // decoder.removeFileUploadFromClean(fileUpload); //remove
// the File of to delete file // the File of to delete file
} else { } else {
responseContent responseContent.append("\tFile to be continued but should not!\r\n");
.append("\tFile to be continued but should not!\r\n");
} }
} }
} }
@ -315,29 +291,24 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
private void writeResponse(Channel channel) { private void writeResponse(Channel channel) {
// Convert the response content to a ChannelBuffer. // Convert the response content to a ChannelBuffer.
ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
.toString(), CharsetUtil.UTF_8);
responseContent.setLength(0); responseContent.setLength(0);
// Decide whether to close the connection or not. // Decide whether to close the connection or not.
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(
.headers().get(HttpHeaders.Names.CONNECTION)) || request.headers().get(HttpHeaders.Names.CONNECTION)) ||
request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) &&
!HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(HttpHeaders.Names.CONNECTION));
.headers().get(HttpHeaders.Names.CONNECTION));
// Build the response object. // Build the response object.
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpResponseStatus.OK);
response.setContent(buf); response.setContent(buf);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8");
"text/plain; charset=UTF-8");
if (!close) { if (!close) {
// There's no need to add 'Content-Length' header // There's no need to add 'Content-Length' header
// if this is the last response. // if this is the last response.
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
.valueOf(buf.readableBytes()));
} }
Set<Cookie> cookies; Set<Cookie> cookies;
@ -353,8 +324,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
CookieEncoder cookieEncoder = new CookieEncoder(true); CookieEncoder cookieEncoder = new CookieEncoder(true);
for (Cookie cookie: cookies) { for (Cookie cookie: cookies) {
cookieEncoder.addCookie(cookie); cookieEncoder.addCookie(cookie);
response.headers().add(HttpHeaders.Names.SET_COOKIE, cookieEncoder response.headers().add(HttpHeaders.Names.SET_COOKIE, cookieEncoder.encode());
.encode());
cookieEncoder = new CookieEncoder(true); cookieEncoder = new CookieEncoder(true);
} }
} }
@ -376,8 +346,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
responseContent.append("<head>"); responseContent.append("<head>");
responseContent.append("<title>Netty Test Form</title>\r\n"); responseContent.append("<title>Netty Test Form</title>\r\n");
responseContent.append("</head>\r\n"); responseContent.append("</head>\r\n");
responseContent responseContent.append("<body bgcolor=white><style>td{font-size: 12pt;}</style>");
.append("<body bgcolor=white><style>td{font-size: 12pt;}</style>");
responseContent.append("<table border=\"0\">"); responseContent.append("<table border=\"0\">");
responseContent.append("<tr>"); responseContent.append("<tr>");
@ -389,98 +358,66 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
responseContent.append("</table>\r\n"); responseContent.append("</table>\r\n");
// GET // GET
responseContent responseContent.append("<CENTER>GET FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
.append("<CENTER>GET FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
responseContent.append("<FORM ACTION=\"/formget\" METHOD=\"GET\">"); responseContent.append("<FORM ACTION=\"/formget\" METHOD=\"GET\">");
responseContent responseContent.append("<input type=hidden name=getform value=\"GET\">");
.append("<input type=hidden name=getform value=\"GET\">");
responseContent.append("<table border=\"0\">"); responseContent.append("<table border=\"0\">");
responseContent responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"info\" size=10></td></tr>");
.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>"); responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"secondinfo\" size=20>");
responseContent responseContent.append("<tr><td>Fill with value:<br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
responseContent
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
responseContent.append("</td></tr>"); responseContent.append("</td></tr>");
responseContent responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>"); responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
responseContent
.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
responseContent.append("</table></FORM>\r\n"); responseContent.append("</table></FORM>\r\n");
responseContent responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
// POST // POST
responseContent responseContent.append("<CENTER>POST FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
.append("<CENTER>POST FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
responseContent.append("<FORM ACTION=\"/formpost\" METHOD=\"POST\">"); responseContent.append("<FORM ACTION=\"/formpost\" METHOD=\"POST\">");
responseContent responseContent.append("<input type=hidden name=getform value=\"POST\">");
.append("<input type=hidden name=getform value=\"POST\">");
responseContent.append("<table border=\"0\">"); responseContent.append("<table border=\"0\">");
responseContent responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"info\" size=10></td></tr>");
.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>"); responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"secondinfo\" size=20>");
responseContent responseContent.append("<tr><td>Fill with value:<br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>"); responseContent.append("<tr><td>Fill with file (only file name will be transmitted): <br> ");
responseContent responseContent.append("<input type=file name=\"myfile\">");
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
responseContent
.append("<tr><td>Fill with file (only file name will be transmitted): <br> " +
"<input type=file name=\"myfile\">");
responseContent.append("</td></tr>"); responseContent.append("</td></tr>");
responseContent responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>"); responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
responseContent
.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
responseContent.append("</table></FORM>\r\n"); responseContent.append("</table></FORM>\r\n");
responseContent responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
// POST with enctype="multipart/form-data" // POST with enctype="multipart/form-data"
responseContent responseContent.append("<CENTER>POST MULTIPART FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
.append("<CENTER>POST MULTIPART FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>"); responseContent.append("<FORM ACTION=\"/formpostmultipart\" ENCTYPE=\"multipart/form-data\" METHOD=\"POST\">");
responseContent responseContent.append("<input type=hidden name=getform value=\"POST\">");
.append("<FORM ACTION=\"/formpostmultipart\" ENCTYPE=\"multipart/form-data\" METHOD=\"POST\">");
responseContent
.append("<input type=hidden name=getform value=\"POST\">");
responseContent.append("<table border=\"0\">"); responseContent.append("<table border=\"0\">");
responseContent responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"info\" size=10></td></tr>");
.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>"); responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"secondinfo\" size=20>");
responseContent responseContent.append("<tr><td>Fill with value:<br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>"); responseContent.append("<tr><td>Fill with file: <br> <input type=file name=\"myfile\">");
responseContent
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
responseContent
.append("<tr><td>Fill with file: <br> <input type=file name=\"myfile\">");
responseContent.append("</td></tr>"); responseContent.append("</td></tr>");
responseContent responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>"); responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
responseContent
.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
responseContent.append("</table></FORM>\r\n"); responseContent.append("</table></FORM>\r\n");
responseContent responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
responseContent.append("</body>"); responseContent.append("</body>");
responseContent.append("</html>"); responseContent.append("</html>");
ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
.toString(), CharsetUtil.UTF_8);
// Build the response object. // Build the response object.
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpResponseStatus.OK);
response.setContent(buf); response.setContent(buf);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");
"text/html; charset=UTF-8"); response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf
.readableBytes()));
// Write the response. // Write the response.
e.getChannel().write(response); e.getChannel().write(response);
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception { e.getCause().printStackTrace();
logger.error(responseContent.toString(), e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -33,7 +33,7 @@ public class HttpUploadServerPipelineFactory implements ChannelPipelineFactory {
this.sslCtx = sslCtx; this.sslCtx = sslCtx;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();

View File

@ -15,25 +15,26 @@
*/ */
package org.jboss.netty.example.http.websocketx.autobahn; package org.jboss.netty.example.http.websocketx.autobahn;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* A Web Socket echo server for running the <a href="http://www.tavendo.de/autobahn/testsuite.html">autobahn</a> test * A Web Socket echo server for running the <a href="http://www.tavendo.de/autobahn/testsuite.html">autobahn</a> test
* suite * suite
*/ */
public class AutobahnServer { public final class AutobahnServer {
private final int port; public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 9000;
}
public AutobahnServer(int port) {
this.port = port;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
@ -46,16 +47,6 @@ public class AutobahnServer {
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(port));
System.out.println("Web Socket Server started at port " + port); System.err.println("Web Socket Server started at port " + port);
}
public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 9000;
}
new AutobahnServer(port).run();
} }
} }

View File

@ -15,11 +15,6 @@
*/ */
package org.jboss.netty.example.http.websocketx.autobahn; package org.jboss.netty.example.http.websocketx.autobahn;
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import static org.jboss.netty.handler.codec.http.HttpMethod.*;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelFutureListener;
@ -44,6 +39,11 @@ import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import static org.jboss.netty.handler.codec.http.HttpMethod.*;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
/** /**
* Handles handshakes and messages * Handles handshakes and messages
*/ */
@ -53,7 +53,7 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
private WebSocketServerHandshaker handshaker; private WebSocketServerHandshaker handshaker;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Object msg = e.getMessage(); Object msg = e.getMessage();
if (msg instanceof HttpRequest) { if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg); handleHttpRequest(ctx, (HttpRequest) msg);
@ -62,7 +62,7 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
} }
} }
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) {
// Allow only GET methods. // Allow only GET methods.
if (req.getMethod() != GET) { if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
@ -70,8 +70,8 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
} }
// Handshake // Handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( WebSocketServerHandshakerFactory wsFactory =
getWebSocketLocation(req), null, false); new WebSocketServerHandshakerFactory(getWebSocketLocation(req), null, false);
handshaker = wsFactory.newHandshaker(req); handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) { if (handshaker == null) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
@ -82,8 +82,8 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String logger.debug(String.format(
.format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName())); "Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName()));
} }
if (frame instanceof CloseWebSocketFrame) { if (frame instanceof CloseWebSocketFrame) {
@ -124,7 +124,7 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -15,18 +15,18 @@
*/ */
package org.jboss.netty.example.http.websocketx.autobahn; package org.jboss.netty.example.http.websocketx.autobahn;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import static org.jboss.netty.channel.Channels.*;
/** /**
*/ */
public class AutobahnServerPipelineFactory implements ChannelPipelineFactory { public class AutobahnServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("decoder", new HttpRequestDecoder());

View File

@ -36,11 +36,6 @@
//THE SOFTWARE. //THE SOFTWARE.
package org.jboss.netty.example.http.websocketx.client; package org.jboss.netty.example.http.websocketx.client;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.HashMap;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
@ -57,16 +52,53 @@ import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketVersion; import org.jboss.netty.handler.codec.http.websocketx.WebSocketVersion;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
public class WebSocketClient { import java.net.InetSocketAddress;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
private final URI uri; public final class WebSocketClient {
public WebSocketClient(URI uri) { static final String URL = System.getProperty("url", "ws://127.0.0.1:8080/websocket");
this.uri = uri;
} 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 {
port = uri.getPort();
}
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;
}
Map<String, String> customHeaders = new HashMap<String, String>();
customHeaders.put("MyHeader", "MyValue");
public void run() throws Exception {
ClientBootstrap bootstrap = ClientBootstrap bootstrap =
new ClientBootstrap( new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
@ -74,16 +106,7 @@ public class WebSocketClient {
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
Channel ch = null; Channel ch = null;
try { try {
String protocol = uri.getScheme();
if (!"ws".equals(protocol)) {
throw new IllegalArgumentException("Unsupported protocol: " + protocol);
}
HashMap<String, String> customHeaders = new HashMap<String, String>();
customHeaders.put("MyHeader", "MyValue");
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00. // 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 // If you change it to V00, ping is not supported and remember to change
// HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline. // HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline.
@ -92,9 +115,12 @@ public class WebSocketClient {
uri, WebSocketVersion.V13, null, false, customHeaders); uri, WebSocketVersion.V13, null, false, customHeaders);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline(); ChannelPipeline pipeline = Channels.pipeline();
if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler(host, port));
}
pipeline.addLast("decoder", new HttpResponseDecoder()); pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("encoder", new HttpRequestEncoder()); pipeline.addLast("encoder", new HttpRequestEncoder());
pipeline.addLast("ws-handler", new WebSocketClientHandler(handshaker)); pipeline.addLast("ws-handler", new WebSocketClientHandler(handshaker));
@ -102,33 +128,26 @@ public class WebSocketClient {
} }
}); });
// Connect // Connect.
System.out.println("WebSocket Client connecting"); ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
ChannelFuture future = ch = future.sync().getChannel();
bootstrap.connect(
new InetSocketAddress(uri.getHost(), uri.getPort()));
future.syncUninterruptibly();
ch = future.getChannel(); handshaker.handshake(ch).sync();
handshaker.handshake(ch).syncUninterruptibly();
// Send 10 messages and wait for responses // Send 10 messages and wait for responses
System.out.println("WebSocket Client sending message");
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
ch.write(new TextWebSocketFrame("Message #" + i)); ch.write(new TextWebSocketFrame("Message #" + i));
} }
// Ping // Ping
System.out.println("WebSocket Client sending ping"); ch.write(new PingWebSocketFrame(ChannelBuffers.wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 })));
ch.write(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6})));
// Close // Close
System.out.println("WebSocket Client sending close");
ch.write(new CloseWebSocketFrame()); ch.write(new CloseWebSocketFrame());
// WebSocketClientHandler will close the connection when the server // WebSocketClientHandler will close the connection when the server
// responds to the CloseWebSocketFrame. // responds to the CloseWebSocketFrame.
ch.getCloseFuture().awaitUninterruptibly(); ch.getCloseFuture().sync();
} finally { } finally {
if (ch != null) { if (ch != null) {
ch.close(); ch.close();
@ -136,14 +155,4 @@ public class WebSocketClient {
bootstrap.releaseExternalResources(); bootstrap.releaseExternalResources();
} }
} }
public static void main(String[] args) throws Exception {
URI uri;
if (args.length > 0) {
uri = new URI(args[0]);
} else {
uri = new URI("ws://localhost:8080/websocket");
}
new WebSocketClient(uri).run();
}
} }

View File

@ -61,44 +61,44 @@ public class WebSocketClientHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
System.out.println("WebSocket Client disconnected!"); System.err.println("WebSocket Client disconnected!");
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = ctx.getChannel(); Channel ch = ctx.getChannel();
if (!handshaker.isHandshakeComplete()) { if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (HttpResponse) e.getMessage()); handshaker.finishHandshake(ch, (HttpResponse) e.getMessage());
System.out.println("WebSocket Client connected!"); System.err.println("WebSocket Client connected!");
return; return;
} }
if (e.getMessage() instanceof HttpResponse) { if (e.getMessage() instanceof HttpResponse) {
HttpResponse response = (HttpResponse) e.getMessage(); HttpResponse response = (HttpResponse) e.getMessage();
throw new Exception("Unexpected HttpResponse (status=" + response.getStatus() + ", content=" throw new IllegalStateException(
+ response.getContent().toString(CharsetUtil.UTF_8) + ')'); "unexpected response (status=" + response.getStatus() +
", content=" + response.getContent().toString(CharsetUtil.UTF_8) + ')');
} }
WebSocketFrame frame = (WebSocketFrame) e.getMessage(); WebSocketFrame frame = (WebSocketFrame) e.getMessage();
if (frame instanceof TextWebSocketFrame) { if (frame instanceof TextWebSocketFrame) {
TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
System.out.println("WebSocket Client received message: " + textFrame.getText()); System.err.println("WebSocket Client received message: " + textFrame.getText());
} else if (frame instanceof PongWebSocketFrame) { } else if (frame instanceof PongWebSocketFrame) {
System.out.println("WebSocket Client received pong"); System.err.println("WebSocket Client received pong");
} else if (frame instanceof CloseWebSocketFrame) { } else if (frame instanceof CloseWebSocketFrame) {
System.out.println("WebSocket Client received closing"); System.err.println("WebSocket Client received closing");
ch.close(); ch.close();
} else if (frame instanceof PingWebSocketFrame) { } else if (frame instanceof PingWebSocketFrame) {
System.out.println("WebSocket Client received ping, response with pong"); System.err.println("WebSocket Client received ping, response with pong");
ch.write(new PongWebSocketFrame(frame.getBinaryData())); ch.write(new PongWebSocketFrame(frame.getBinaryData()));
} }
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
final Throwable t = e.getCause(); e.getCause().printStackTrace();
t.printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -1,33 +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 org.jboss.netty.example.http.websocketx.html5;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
public class CustomTextFrameHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (e.getMessage() instanceof TextWebSocketFrame) {
TextWebSocketFrame frame = (TextWebSocketFrame) e.getMessage();
ctx.getChannel().write(new TextWebSocketFrame(frame.getText().toUpperCase()));
}
}
}

View File

@ -1,79 +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 org.jboss.netty.example.http.websocketx.html5;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.example.http.websocketx.server.WebSocketServerPipelineFactory;
/**
* 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>
* netty/src/test/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 status 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() {
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
// Set up the event pipeline factory.
bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port));
System.out.println("Web socket server started at port " + port + '.');
}
public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new WebSocketServer(port).run();
}
}

View File

@ -1,38 +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 org.jboss.netty.example.http.websocketx.html5;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", new WebSocketServerProtocolHandler("/websocket"));
pipeline.addLast("testFramehandler", new CustomTextFrameHandler());
return pipeline;
}
}

View File

@ -15,11 +15,13 @@
*/ */
package org.jboss.netty.example.http.websocketx.server; package org.jboss.netty.example.http.websocketx.server;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* A HTTP server which serves Web Socket requests at: * A HTTP server which serves Web Socket requests at:
@ -42,34 +44,30 @@ import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
*/ */
public class WebSocketServer { public class WebSocketServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public WebSocketServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
// Set up the event pipeline factory. // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory()); bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
System.out.println("Web socket server started at port " + port + '.'); System.err.println("Web socket server started at port " + PORT + '.');
System.out.println("Open your browser and navigate to http://localhost:" + port + '/'); System.err.println("Open your browser and navigate to http://localhost:" + PORT + '/');
}
public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new WebSocketServer(port).run();
} }
} }

View File

@ -33,8 +33,6 @@ import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
@ -47,14 +45,13 @@ import static org.jboss.netty.handler.codec.http.HttpVersion.*;
* Handles handshakes and messages * Handles handshakes and messages
*/ */
public class WebSocketServerHandler extends SimpleChannelUpstreamHandler { public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandler.class);
private static final String WEBSOCKET_PATH = "/websocket"; private static final String WEBSOCKET_PATH = "/websocket";
private WebSocketServerHandshaker handshaker; private WebSocketServerHandshaker handshaker;
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Object msg = e.getMessage(); Object msg = e.getMessage();
if (msg instanceof HttpRequest) { if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg); handleHttpRequest(ctx, (HttpRequest) msg);
@ -63,7 +60,7 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
} }
} }
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) {
// Allow only GET methods. // Allow only GET methods.
if (req.getMethod() != GET) { if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
@ -101,7 +98,6 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
} }
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
// Check for closing frame // Check for closing frame
if (frame instanceof CloseWebSocketFrame) { if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
@ -112,15 +108,13 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
return; return;
} }
if (!(frame instanceof TextWebSocketFrame)) { if (!(frame instanceof TextWebSocketFrame)) {
throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() throw new UnsupportedOperationException(
.getName())); String.format("%s frame types not supported", frame.getClass().getName()));
} }
// Send the uppercase string back. // Send the uppercase string back.
String request = ((TextWebSocketFrame) frame).getText(); String request = ((TextWebSocketFrame) frame).getText();
if (logger.isDebugEnabled()) { System.err.println(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
}
ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
} }
@ -139,7 +133,7 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -15,20 +15,29 @@
*/ */
package org.jboss.netty.example.http.websocketx.server; package org.jboss.netty.example.http.websocketx.server;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator; import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder; import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder; import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.ssl.SslContext;
/** /**
*/ */
public class WebSocketServerPipelineFactory implements ChannelPipelineFactory { public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation. private final SslContext sslCtx;
ChannelPipeline pipeline = pipeline();
public WebSocketServerPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler());
}
pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("encoder", new HttpResponseEncoder());

View File

@ -1,87 +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 org.jboss.netty.example.http.websocketx.sslserver;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
/**
* 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() {
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
// Set up the event pipeline factory.
bootstrap.setPipelineFactory(new WebSocketSslServerPipelineFactory());
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port));
System.out.println("Web socket server started at port " + port + '.');
System.out.println("Open your browser and navigate to https://localhost:" + port + '/');
}
public static void main(String[] args) {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8443;
}
String keyStoreFilePath = System.getProperty("keystore.file.path");
if (keyStoreFilePath == null || keyStoreFilePath.length() == 0) {
System.out.println("ERROR: System property keystore.file.path not set. Exiting now!");
System.exit(1);
}
String keyStoreFilePassword = System.getProperty("keystore.file.password");
if (keyStoreFilePassword == null || keyStoreFilePassword.length() == 0) {
System.out.println("ERROR: System property keystore.file.password not set. Exiting now!");
System.exit(1);
}
new WebSocketSslServer(port).run();
}
}

View File

@ -1,152 +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 org.jboss.netty.example.http.websocketx.sslserver;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.example.http.websocketx.server.WebSocketServerIndexPage;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.CharsetUtil;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import static org.jboss.netty.handler.codec.http.HttpMethod.*;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
/**
* Handles handshakes and messages
*/
public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerHandler.class);
private static final String WEBSOCKET_PATH = "/websocket";
private WebSocketServerHandshaker handshaker;
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Object msg = e.getMessage();
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the demo page and favicon.ico
if ("/".equals(req.getUri())) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
setContentLength(res, content.readableBytes());
res.setContent(content);
sendHttpResponse(ctx, req, res);
return;
}
if ("/favicon.ico".equals(req.getUri())) {
HttpResponse res = new DefaultHttpResponse(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) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
} else {
handshaker.handshake(ctx.getChannel(), req).addListener(WebSocketServerHandshaker.HANDSHAKE_LISTENER);
}
}
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
// Check for closing frame
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
return;
}
if (frame instanceof PingWebSocketFrame) {
ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));
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).getText();
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
}
ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
// Generate an error page if response status code is not OK (200).
if (res.getStatus().getCode() != 200) {
res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.getContent().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.getChannel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
e.getCause().printStackTrace();
e.getChannel().close();
}
private static String getWebSocketLocation(HttpRequest req) {
return "wss://" + req.headers().get(HOST) + WEBSOCKET_PATH;
}
}

View File

@ -1,46 +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 org.jboss.netty.example.http.websocketx.sslserver;
import static org.jboss.netty.channel.Channels.*;
import javax.net.ssl.SSLEngine;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.ssl.SslHandler;
/**
*/
public class WebSocketSslServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
SSLEngine engine = WebSocketSslServerSslContext.getInstance().getServerContext().createSSLEngine();
engine.setUseClientMode(false);
pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", new WebSocketSslServerHandler());
return pipeline;
}
}

View File

@ -1,102 +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 org.jboss.netty.example.http.websocketx.sslserver;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.Security;
/**
* Creates a {@link SSLContext} for just server certificates.
*/
public final class WebSocketSslServerSslContext {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerSslContext.class);
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 = Security.getProperty("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
try {
String keyStoreFilePath = System.getProperty("keystore.file.path");
String keyStoreFilePassword = System.getProperty("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) {
if (logger.isErrorEnabled()) {
logger.error("Error initializing SslContextManager. " + ex.getMessage(), ex);
}
System.exit(1);
} finally {
_serverContext = serverContext;
}
}
/**
* Returns the server context with server side key store
*/
public SSLContext getServerContext() {
return _serverContext;
}
}

View File

@ -1,36 +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 org.jboss.netty.example.http.websocketx.sslserver;

View File

@ -15,10 +15,6 @@
*/ */
package org.jboss.netty.example.local; package org.jboss.netty.example.local;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
@ -34,76 +30,69 @@ import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.logging.LoggingHandler; import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.logging.InternalLogLevel; import org.jboss.netty.logging.InternalLogLevel;
public class LocalExample { import java.io.BufferedReader;
import java.io.InputStreamReader;
private final String port; public final class LocalExample {
public LocalExample(String port) { static final String PORT = System.getProperty("port", "test_port");
this.port = port;
}
public void run() throws IOException {
// Address to bind on / connect to.
LocalAddress socketAddress = new LocalAddress(port);
// Configure the server.
ServerBootstrap sb = new ServerBootstrap(
new DefaultLocalServerChannelFactory());
// Set up the default server-side event pipeline.
EchoServerHandler handler = new EchoServerHandler();
sb.getPipeline().addLast("handler", handler);
// Start up the server.
sb.bind(socketAddress);
// Configure the client.
ClientBootstrap cb = new ClientBootstrap(
new DefaultLocalClientChannelFactory());
// Set up the client-side pipeline factory.
cb.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new StringDecoder(),
new StringEncoder(),
new LoggingHandler(InternalLogLevel.INFO));
}
});
// Make the connection attempt to the server.
ChannelFuture channelFuture = cb.connect(socketAddress);
channelFuture.awaitUninterruptibly();
// Read commands from the stdin.
System.out.println("Enter text (quit to end)");
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (; ;) {
String line = in.readLine();
if (line == null || "quit".equalsIgnoreCase(line)) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channelFuture.getChannel().write(line);
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
channelFuture.getChannel().close();
// Wait until the connection is closed or the connection attempt fails.
channelFuture.getChannel().getCloseFuture().awaitUninterruptibly();
// Release all resources used by the local transport.
cb.releaseExternalResources();
sb.releaseExternalResources();
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new LocalExample("1").run(); // Address to bind on / connect to.
LocalAddress socketAddress = new LocalAddress(PORT);
// Create the bootstraps for both client and server side.
ServerBootstrap sb = new ServerBootstrap(new DefaultLocalServerChannelFactory());
ClientBootstrap cb = new ClientBootstrap(new DefaultLocalClientChannelFactory());
try {
// Set up the default server-side event pipeline.
EchoServerHandler handler = new EchoServerHandler();
sb.getPipeline().addLast("handler", handler);
// Start up the server.
sb.bind(socketAddress);
// Set up the client-side pipeline factory.
cb.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
return Channels.pipeline(
new StringDecoder(),
new StringEncoder(),
new LoggingHandler(InternalLogLevel.INFO));
}
});
// Make the connection attempt to the server.
ChannelFuture channelFuture = cb.connect(socketAddress);
channelFuture.sync();
// Read commands from the stdin.
System.err.println("Enter text (quit to end)");
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null || "quit".equalsIgnoreCase(line)) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channelFuture.getChannel().write(line);
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
channelFuture.getChannel().close();
// Wait until the connection is closed or the connection attempt fails.
channelFuture.getChannel().getCloseFuture().sync();
} finally {
// Release all resources used by the local transport.
cb.releaseExternalResources();
sb.releaseExternalResources();
}
} }
} }

View File

@ -1,105 +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 org.jboss.netty.example.local;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.local.DefaultLocalClientChannelFactory;
import org.jboss.netty.channel.local.DefaultLocalServerChannelFactory;
import org.jboss.netty.channel.local.LocalAddress;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.logging.InternalLogLevel;
public class LocalExampleMultithreaded {
private final String port;
public LocalExampleMultithreaded(String port) {
this.port = port;
}
public void run() {
LocalAddress socketAddress = new LocalAddress(port);
OrderedMemoryAwareThreadPoolExecutor eventExecutor =
new OrderedMemoryAwareThreadPoolExecutor(
5, 1000000, 10000000, 100,
TimeUnit.MILLISECONDS);
ServerBootstrap sb = new ServerBootstrap(
new DefaultLocalServerChannelFactory());
sb.setPipelineFactory(new LocalServerPipelineFactory(eventExecutor));
sb.bind(socketAddress);
ClientBootstrap cb = new ClientBootstrap(
new DefaultLocalClientChannelFactory());
cb.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new StringDecoder(),
new StringEncoder(),
new LoggingHandler(InternalLogLevel.INFO));
}
});
// Read commands from array
String[] commands = { "First", "Second", "Third", "quit" };
for (int j = 0; j < 5 ; j++) {
System.err.println("Start " + j);
ChannelFuture channelFuture = cb.connect(socketAddress);
channelFuture.awaitUninterruptibly();
if (! channelFuture.isSuccess()) {
System.err.println("CANNOT CONNECT");
channelFuture.getCause().printStackTrace();
break;
}
ChannelFuture lastWriteFuture = null;
for (String line: commands) {
// Sends the received line to the server.
lastWriteFuture = channelFuture.getChannel().write(line);
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
channelFuture.getChannel().close();
// Wait until the connection is closed or the connection attempt fails.
channelFuture.getChannel().getCloseFuture().awaitUninterruptibly();
System.err.println("End " + j);
}
// Release all resources
cb.releaseExternalResources();
sb.releaseExternalResources();
eventExecutor.shutdownNow();
}
public static void main(String[] args) throws Exception {
new LocalExampleMultithreaded("1").run();
}
}

View File

@ -1,78 +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 org.jboss.netty.example.local;
import org.jboss.netty.channel.ChannelDownstreamHandler;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelUpstreamHandler;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.execution.ExecutionHandler;
import java.util.concurrent.Executor;
public class LocalServerPipelineFactory implements ChannelPipelineFactory {
private final ExecutionHandler executionHandler;
public LocalServerPipelineFactory(Executor eventExecutor) {
executionHandler = new ExecutionHandler(eventExecutor);
}
public ChannelPipeline getPipeline() throws Exception {
final ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("executor", executionHandler);
pipeline.addLast("handler", new EchoCloseServerHandler());
return pipeline;
}
static class EchoCloseServerHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler {
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)
throws Exception {
if (e instanceof MessageEvent) {
final MessageEvent evt = (MessageEvent) e;
String msg = (String) evt.getMessage();
if ("quit".equalsIgnoreCase(msg)) {
Channels.close(e.getChannel());
return;
}
}
ctx.sendUpstream(e);
}
public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) {
if (e instanceof MessageEvent) {
final MessageEvent evt = (MessageEvent) e;
String msg = (String) evt.getMessage();
if ("quit".equalsIgnoreCase(msg)) {
Channels.close(e.getChannel());
return;
}
System.err.println("SERVER:" + msg);
// Write back
Channels.write(e.getChannel(), msg);
}
ctx.sendDownstream(e);
}
}
}

View File

@ -19,108 +19,65 @@ import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.regex.Pattern;
/** /**
* Sends a list of continent/city pairs to a {@link LocalTimeServer} to * Sends a list of continent/city pairs to a {@link LocalTimeServer} to
* get the local times of the specified cities. * get the local times of the specified cities.
*/ */
public class LocalTimeClient { public final class LocalTimeClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final Collection<String> cities; static final int PORT = Integer.parseInt(System.getProperty("port", "8463"));
static final List<String> CITIES = Arrays.asList(System.getProperty(
"cities", "Asia/Seoul,Europe/Berlin,America/Los_Angeles").split(","));
public LocalTimeClient(String host, int port, Collection<String> cities) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.cities = new ArrayList<String>(); if (SSL) {
this.cities.addAll(cities); sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} } else {
sslCtx = null;
}
public void run() {
// Set up.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
try {
// Configure the event pipeline factory.
bootstrap.setPipelineFactory(new LocalTimeClientPipelineFactory(sslCtx));
// Configure the event pipeline factory. // Make a new connection.
bootstrap.setPipelineFactory(new LocalTimeClientPipelineFactory()); ChannelFuture connectFuture = bootstrap.connect(new InetSocketAddress(HOST, PORT));
// Make a new connection. // Wait until the connection is made successfully.
ChannelFuture connectFuture = Channel channel = connectFuture.sync().getChannel();
bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection is made successfully. // Get the handler instance to initiate the request.
Channel channel = connectFuture.awaitUninterruptibly().getChannel(); LocalTimeClientHandler handler = channel.getPipeline().get(LocalTimeClientHandler.class);
// Get the handler instance to initiate the request. // Request and get the response.
LocalTimeClientHandler handler = List<String> response = handler.getLocalTimes(CITIES);
channel.getPipeline().get(LocalTimeClientHandler.class);
// Request and get the response. // Close the connection.
List<String> response = handler.getLocalTimes(cities); channel.close().sync();
// Close the connection.
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit. // Print the response at last but not least.
bootstrap.releaseExternalResources(); for (int i = 0; i < CITIES.size(); i ++) {
System.out.format("%28s: %s%n", CITIES.get(i), response.get(i));
// Print the response at last but not least.
Iterator<String> i1 = cities.iterator();
Iterator<String> i2 = response.iterator();
while (i1.hasNext()) {
System.out.format("%28s: %s%n", i1.next(), i2.next());
}
}
public static void main(String[] args) throws Exception {
// Print usage if necessary.
if (args.length < 3) {
printUsage();
return;
}
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
Collection<String> cities = parseCities(args, 2);
if (cities == null) {
return;
}
new LocalTimeClient(host, port, cities).run();
}
private static void printUsage() {
System.err.println(
"Usage: " + LocalTimeClient.class.getSimpleName() +
" <host> <port> <continent/city_name> ...");
System.err.println(
"Example: " + LocalTimeClient.class.getSimpleName() +
" localhost 8080 America/New_York Asia/Seoul");
}
private static final Pattern CITY_PATTERN = Pattern.compile("^[_A-Za-z]+/[_A-Za-z]+$");
private static List<String> parseCities(String[] args, int offset) {
List<String> cities = new ArrayList<String>();
for (int i = offset; i < args.length; i ++) {
if (!CITY_PATTERN.matcher(args[i]).matches()) {
System.err.println("Syntax error: '" + args[i] + '\'');
printUsage();
return null;
} }
cities.add(args[i].trim()); } finally {
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources();
} }
return cities;
} }
} }

View File

@ -34,15 +34,10 @@ import java.util.Formatter;
import java.util.List; import java.util.List;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler { public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
LocalTimeClientHandler.class.getName());
private static final Pattern DELIM = Pattern.compile("/"); private static final Pattern DELIM = Pattern.compile("/");
// Stateful properties // Stateful properties
@ -94,35 +89,27 @@ public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
throws Exception {
channel = e.getChannel(); channel = e.getChannel();
super.channelOpen(ctx, e); super.channelOpen(ctx, e);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) {
ChannelHandlerContext ctx, final MessageEvent e) { answer.add((LocalTimes) e.getMessage());
boolean offered = answer.offer((LocalTimes) e.getMessage());
assert offered;
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,19 +15,29 @@
*/ */
package org.jboss.netty.example.localtime; package org.jboss.netty.example.localtime;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
public class LocalTimeClientPipelineFactory implements ChannelPipelineFactory { public class LocalTimeClientPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception { private final SslContext sslCtx;
public LocalTimeClientPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
ChannelPipeline p = pipeline(); ChannelPipeline p = pipeline();
if (sslCtx != null) {
p.addLast("ssl", sslCtx.newHandler(LocalTimeClient.HOST, LocalTimeClient.PORT));
}
p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder());
p.addLast("protobufDecoder", new ProtobufDecoder(LocalTimeProtocol.LocalTimes.getDefaultInstance())); p.addLast("protobufDecoder", new ProtobufDecoder(LocalTimeProtocol.LocalTimes.getDefaultInstance()));

View File

@ -15,25 +15,33 @@
*/ */
package org.jboss.netty.example.localtime; package org.jboss.netty.example.localtime;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Receives a list of continent/city pairs from a {@link LocalTimeClient} to * Receives a list of continent/city pairs from a {@link LocalTimeClient} to
* get the local times of the specified cities. * get the local times of the specified cities.
*/ */
public class LocalTimeServer { public final class LocalTimeServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8463"));
public LocalTimeServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -41,19 +49,9 @@ public class LocalTimeServer {
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the event pipeline factory. // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new LocalTimeServerPipelineFactory()); bootstrap.setPipelineFactory(new LocalTimeServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new LocalTimeServer(port).run();
} }
} }

View File

@ -30,36 +30,28 @@ import org.jboss.netty.example.localtime.LocalTimeProtocol.Locations;
import java.util.Calendar; import java.util.Calendar;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.Calendar.*; import static java.util.Calendar.*;
public class LocalTimeServerHandler extends SimpleChannelUpstreamHandler { public class LocalTimeServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
LocalTimeServerHandler.class.getName());
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
Locations locations = (Locations) e.getMessage(); Locations locations = (Locations) e.getMessage();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
LocalTimes.Builder builder = LocalTimes.newBuilder(); LocalTimes.Builder builder = LocalTimes.newBuilder();
for (Location l: locations.getLocationList()) { for (Location l: locations.getLocationList()) {
TimeZone tz = TimeZone.getTimeZone( TimeZone tz = TimeZone.getTimeZone(toString(l.getContinent()) + '/' + l.getCity());
toString(l.getContinent()) + '/' + l.getCity());
Calendar calendar = getInstance(tz); Calendar calendar = getInstance(tz);
calendar.setTimeInMillis(currentTime); calendar.setTimeInMillis(currentTime);
@ -77,12 +69,8 @@ public class LocalTimeServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -15,19 +15,29 @@
*/ */
package org.jboss.netty.example.localtime; package org.jboss.netty.example.localtime;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
public class LocalTimeServerPipelineFactory implements ChannelPipelineFactory { public class LocalTimeServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception { private final SslContext sslCtx;
public LocalTimeServerPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
ChannelPipeline p = pipeline(); ChannelPipeline p = pipeline();
if (sslCtx != null) {
p.addLast("ssl", sslCtx.newHandler());
}
p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder());
p.addLast("protobufDecoder", new ProtobufDecoder(LocalTimeProtocol.Locations.getDefaultInstance())); p.addLast("protobufDecoder", new ProtobufDecoder(LocalTimeProtocol.Locations.getDefaultInstance()));

View File

@ -15,10 +15,8 @@
*/ */
package org.jboss.netty.example.objectecho; package org.jboss.netty.example.objectecho;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
@ -27,64 +25,61 @@ import org.jboss.netty.example.echo.EchoClient;
import org.jboss.netty.handler.codec.serialization.ClassResolvers; import org.jboss.netty.handler.codec.serialization.ClassResolvers;
import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectDecoder;
import org.jboss.netty.handler.codec.serialization.ObjectEncoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Modification of {@link EchoClient} which utilizes Java object serialization. * Modification of {@link EchoClient} which utilizes Java object serialization.
*/ */
public class ObjectEchoClient { public final class ObjectEchoClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
private final int firstMessageSize; static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public ObjectEchoClient(String host, int port, int firstMessageSize) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
this.firstMessageSize = firstMessageSize; if (SSL) {
} sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() {
// Configure the client. // Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Set up the pipeline factory. try {
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { // Set up the pipeline factory.
public ChannelPipeline getPipeline() throws Exception { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
return Channels.pipeline( public ChannelPipeline getPipeline() {
new ObjectEncoder(), ChannelPipeline p = Channels.pipeline(
new ObjectDecoder( new ObjectEncoder(),
ClassResolvers.cacheDisabled(getClass().getClassLoader())), new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())),
new ObjectEchoClientHandler(firstMessageSize)); new ObjectEchoClientHandler(SIZE)
} );
});
// Start the connection attempt. if (sslCtx != null) {
bootstrap.connect(new InetSocketAddress(host, port)); p.addFirst("ssl", sslCtx.newHandler(HOST, PORT));
} }
return p;
}
});
public static void main(String[] args) throws Exception { // Start the connection attempt.
// Print usage if no argument is specified. ChannelFuture f = bootstrap.connect(new InetSocketAddress(HOST, PORT));
if (args.length < 2 || args.length > 3) {
System.err.println( // Wait until the connection attempt is finished and then the connection is closed.
"Usage: " + ObjectEchoClient.class.getSimpleName() + f.sync().getChannel().getCloseFuture().sync();
" <host> <port> [<first message size>]"); } finally {
return; bootstrap.releaseExternalResources();
} }
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
if (args.length == 3) {
firstMessageSize = Integer.parseInt(args[2]);
} else {
firstMessageSize = 256;
}
new ObjectEchoClient(host, port, firstMessageSize).run();
} }
} }

View File

@ -15,12 +15,6 @@
*/ */
package org.jboss.netty.example.objectecho; package org.jboss.netty.example.objectecho;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelState;
@ -29,6 +23,10 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Handler implementation for the object echo client. It initiates the * Handler implementation for the object echo client. It initiates the
* ping-pong traffic between the object echo client and server by sending the * ping-pong traffic between the object echo client and server by sending the
@ -36,9 +34,6 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
*/ */
public class ObjectEchoClientHandler extends SimpleChannelUpstreamHandler { public class ObjectEchoClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
ObjectEchoClientHandler.class.getName());
private final List<Integer> firstMessage; private final List<Integer> firstMessage;
private final AtomicLong transferredMessages = new AtomicLong(); private final AtomicLong transferredMessages = new AtomicLong();
@ -47,8 +42,7 @@ public class ObjectEchoClientHandler extends SimpleChannelUpstreamHandler {
*/ */
public ObjectEchoClientHandler(int firstMessageSize) { public ObjectEchoClientHandler(int firstMessageSize) {
if (firstMessageSize <= 0) { if (firstMessageSize <= 0) {
throw new IllegalArgumentException( throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);
"firstMessageSize: " + firstMessageSize);
} }
firstMessage = new ArrayList<Integer>(firstMessageSize); firstMessage = new ArrayList<Integer>(firstMessageSize);
for (int i = 0; i < firstMessageSize; i ++) { for (int i = 0; i < firstMessageSize; i ++) {
@ -61,37 +55,30 @@ public class ObjectEchoClientHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent && if (e instanceof ChannelStateEvent &&
((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) { ((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void channelConnected( public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelHandlerContext ctx, ChannelStateEvent e) {
// Send the first message if this handler is a client-side handler. // Send the first message if this handler is a client-side handler.
e.getChannel().write(firstMessage); e.getChannel().write(firstMessage);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Echo back the received object to the server. // Echo back the received object to the server.
transferredMessages.incrementAndGet(); transferredMessages.incrementAndGet();
e.getChannel().write(e.getMessage()); e.getChannel().write(e.getMessage());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,9 +15,6 @@
*/ */
package org.jboss.netty.example.objectecho; package org.jboss.netty.example.objectecho;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
@ -27,19 +24,30 @@ import org.jboss.netty.example.echo.EchoServer;
import org.jboss.netty.handler.codec.serialization.ClassResolvers; import org.jboss.netty.handler.codec.serialization.ClassResolvers;
import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectDecoder;
import org.jboss.netty.handler.codec.serialization.ObjectEncoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Modification of {@link EchoServer} which utilizes Java object serialization. * Modification of {@link EchoServer} which utilizes Java object serialization.
*/ */
public class ObjectEchoServer { public final class ObjectEchoServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public ObjectEchoServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -48,26 +56,19 @@ public class ObjectEchoServer {
// Set up the pipeline factory. // Set up the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline( ChannelPipeline p = Channels.pipeline(
new ObjectEncoder(), new ObjectEncoder(),
new ObjectDecoder( new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())),
ClassResolvers.cacheDisabled(getClass().getClassLoader())),
new ObjectEchoServerHandler()); new ObjectEchoServerHandler());
if (sslCtx != null) {
p.addFirst("ssl", sslCtx.newHandler());
}
return p;
} }
}); });
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new ObjectEchoServer(port).run();
} }
} }

View File

@ -15,10 +15,6 @@
*/ */
package org.jboss.netty.example.objectecho; package org.jboss.netty.example.objectecho;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelState; import org.jboss.netty.channel.ChannelState;
@ -27,15 +23,14 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Handles both client-side and server-side handler depending on which * Handles both client-side and server-side handler depending on which
* constructor was called. * constructor was called.
*/ */
public class ObjectEchoServerHandler extends SimpleChannelUpstreamHandler { public class ObjectEchoServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
ObjectEchoServerHandler.class.getName());
private final AtomicLong transferredMessages = new AtomicLong(); private final AtomicLong transferredMessages = new AtomicLong();
public long getTransferredMessages() { public long getTransferredMessages() {
@ -43,30 +38,23 @@ public class ObjectEchoServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent && ((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) {
if (e instanceof ChannelStateEvent && System.err.println(e);
((ChannelStateEvent) e).getState() != ChannelState.INTEREST_OPS) {
logger.info(e.toString());
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Echo back the received object to the client. // Echo back the received object to the client.
transferredMessages.incrementAndGet(); transferredMessages.incrementAndGet();
e.getChannel().write(e.getMessage()); e.getChannel().write(e.getMessage());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -33,17 +33,15 @@ import java.util.concurrent.Executors;
* Because SSL and GZIP are enabled on demand, 5 combinations per protocol * Because SSL and GZIP are enabled on demand, 5 combinations per protocol
* are possible: none, SSL only, GZIP only, SSL + GZIP, and GZIP + SSL. * are possible: none, SSL only, GZIP only, SSL + GZIP, and GZIP + SSL.
*/ */
public class PortUnificationServer { public final class PortUnificationServer {
private final SslContext sslCtx; static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
private final int port;
public PortUnificationServer(SslContext sslCtx, int port) { public static void main(String[] args) throws Exception {
this.sslCtx = sslCtx; // Configure SSL context
this.port = port; SelfSignedCertificate ssc = new SelfSignedCertificate();
} final SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -52,28 +50,12 @@ public class PortUnificationServer {
// Set up the event pipeline factory. // Set up the event pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline(new PortUnificationServerHandler(sslCtx)); return Channels.pipeline(new PortUnificationServerHandler(sslCtx));
} }
}); });
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
// Configure SSL context
SelfSignedCertificate ssc = new SelfSignedCertificate();
final SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
// Start the server.
new PortUnificationServer(sslCtx, port).run();
} }
} }

View File

@ -54,7 +54,7 @@ public class PortUnificationServerHandler extends FrameDecoder {
} }
@Override @Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) {
// Will use the first 5 bytes to detect a protocol. // Will use the first 5 bytes to detect a protocol.
if (buffer.readableBytes() < 5) { if (buffer.readableBytes() < 5) {
return null; return null;

View File

@ -15,62 +15,34 @@
*/ */
package org.jboss.netty.example.proxy; package org.jboss.netty.example.proxy;
import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
public class HexDumpProxy { import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
private final int localPort; public final class HexDumpProxy {
private final String remoteHost;
private final int remotePort;
public HexDumpProxy(int localPort, String remoteHost, int remotePort) { static final int LOCAL_PORT = Integer.parseInt(System.getProperty("localPort", "8443"));
this.localPort = localPort; static final String REMOTE_HOST = System.getProperty("remoteHost", "www.google.com");
this.remoteHost = remoteHost; static final int REMOTE_PORT = Integer.parseInt(System.getProperty("remotePort", "443"));
this.remotePort = remotePort;
}
public void run() { public static void main(String[] args) {
System.err.println( System.err.println("Proxying *:" + LOCAL_PORT + " to " + REMOTE_HOST + ':' + REMOTE_PORT + " ...");
"Proxying *:" + localPort + " to " +
remoteHost + ':' + remotePort + " ...");
// Configure the bootstrap. // Configure the bootstrap.
Executor executor = Executors.newCachedThreadPool(); Executor executor = Executors.newCachedThreadPool();
ServerBootstrap sb = new ServerBootstrap( ServerBootstrap sb = new ServerBootstrap(new NioServerSocketChannelFactory(executor, executor));
new NioServerSocketChannelFactory(executor, executor));
// Set up the event pipeline factory. // Set up the event pipeline factory.
ClientSocketChannelFactory cf = ClientSocketChannelFactory cf = new NioClientSocketChannelFactory(executor, executor);
new NioClientSocketChannelFactory(executor, executor);
sb.setPipelineFactory( sb.setPipelineFactory(new HexDumpProxyPipelineFactory(cf));
new HexDumpProxyPipelineFactory(cf, remoteHost, remotePort));
// Start up the server. // Start up the server.
sb.bind(new InetSocketAddress(localPort)); sb.bind(new InetSocketAddress(LOCAL_PORT));
}
public static void main(String[] args) throws Exception {
// Validate command line options.
if (args.length != 3) {
System.err.println(
"Usage: " + HexDumpProxy.class.getSimpleName() +
" <local port> <remote host> <remote port>");
return;
}
// Parse command line options.
int localPort = Integer.parseInt(args[0]);
String remoteHost = args[1];
int remotePort = Integer.parseInt(args[2]);
new HexDumpProxy(localPort, remoteHost, remotePort).run();
} }
} }

View File

@ -15,8 +15,6 @@
*/ */
package org.jboss.netty.example.proxy; package org.jboss.netty.example.proxy;
import java.net.InetSocketAddress;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBuffers;
@ -30,11 +28,11 @@ import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import java.net.InetSocketAddress;
public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler { public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
private final ClientSocketChannelFactory cf; private final ClientSocketChannelFactory cf;
private final String remoteHost;
private final int remotePort;
// This lock guards against the race condition that overrides the // This lock guards against the race condition that overrides the
// OP_READ flag incorrectly. // OP_READ flag incorrectly.
@ -43,16 +41,12 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
private volatile Channel outboundChannel; private volatile Channel outboundChannel;
public HexDumpProxyInboundHandler( public HexDumpProxyInboundHandler(ClientSocketChannelFactory cf) {
ClientSocketChannelFactory cf, String remoteHost, int remotePort) {
this.cf = cf; this.cf = cf;
this.remoteHost = remoteHost;
this.remotePort = remotePort;
} }
@Override @Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
throws Exception {
// Suspend incoming traffic until connected to the remote host. // Suspend incoming traffic until connected to the remote host.
final Channel inboundChannel = e.getChannel(); final Channel inboundChannel = e.getChannel();
inboundChannel.setReadable(false); inboundChannel.setReadable(false);
@ -60,11 +54,11 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
// Start the connection attempt. // Start the connection attempt.
ClientBootstrap cb = new ClientBootstrap(cf); ClientBootstrap cb = new ClientBootstrap(cf);
cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel())); cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel()));
ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort)); ChannelFuture f = cb.connect(new InetSocketAddress(HexDumpProxy.REMOTE_HOST, HexDumpProxy.REMOTE_PORT));
outboundChannel = f.getChannel(); outboundChannel = f.getChannel();
f.addListener(new ChannelFutureListener() { f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { if (future.isSuccess()) {
// Connection attempt succeeded: // Connection attempt succeeded:
// Begin to accept incoming traffic. // Begin to accept incoming traffic.
@ -78,10 +72,9 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) {
throws Exception {
ChannelBuffer msg = (ChannelBuffer) e.getMessage(); ChannelBuffer msg = (ChannelBuffer) e.getMessage();
//System.out.println(">>> " + ChannelBuffers.hexDump(msg)); //System.err.println(">>> " + ChannelBuffers.hexDump(msg));
synchronized (trafficLock) { synchronized (trafficLock) {
outboundChannel.write(msg); outboundChannel.write(msg);
// If outboundChannel is saturated, do not read until notified in // If outboundChannel is saturated, do not read until notified in
@ -93,8 +86,7 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelInterestChanged(ChannelHandlerContext ctx, public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelStateEvent e) throws Exception {
// If inboundChannel is not saturated anymore, continue accepting // If inboundChannel is not saturated anymore, continue accepting
// the incoming traffic from the outboundChannel. // the incoming traffic from the outboundChannel.
synchronized (trafficLock) { synchronized (trafficLock) {
@ -107,16 +99,14 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
throws Exception {
if (outboundChannel != null) { if (outboundChannel != null) {
closeOnFlush(outboundChannel); closeOnFlush(outboundChannel);
} }
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
closeOnFlush(e.getChannel()); closeOnFlush(e.getChannel());
} }
@ -130,10 +120,9 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) {
throws Exception {
ChannelBuffer msg = (ChannelBuffer) e.getMessage(); ChannelBuffer msg = (ChannelBuffer) e.getMessage();
//System.out.println("<<< " + ChannelBuffers.hexDump(msg)); //System.err.println("<<< " + ChannelBuffers.hexDump(msg));
synchronized (trafficLock) { synchronized (trafficLock) {
inboundChannel.write(msg); inboundChannel.write(msg);
// If inboundChannel is saturated, do not read until notified in // If inboundChannel is saturated, do not read until notified in
@ -145,8 +134,7 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelInterestChanged(ChannelHandlerContext ctx, public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelStateEvent e) throws Exception {
// If outboundChannel is not saturated anymore, continue accepting // If outboundChannel is not saturated anymore, continue accepting
// the incoming traffic from the inboundChannel. // the incoming traffic from the inboundChannel.
synchronized (trafficLock) { synchronized (trafficLock) {
@ -157,14 +145,12 @@ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
throws Exception {
closeOnFlush(inboundChannel); closeOnFlush(inboundChannel);
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
closeOnFlush(e.getChannel()); closeOnFlush(e.getChannel());
} }

View File

@ -15,28 +15,23 @@
*/ */
package org.jboss.netty.example.proxy; package org.jboss.netty.example.proxy;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import static org.jboss.netty.channel.Channels.*;
public class HexDumpProxyPipelineFactory implements ChannelPipelineFactory { public class HexDumpProxyPipelineFactory implements ChannelPipelineFactory {
private final ClientSocketChannelFactory cf; private final ClientSocketChannelFactory cf;
private final String remoteHost;
private final int remotePort;
public HexDumpProxyPipelineFactory( public HexDumpProxyPipelineFactory(ClientSocketChannelFactory cf) {
ClientSocketChannelFactory cf, String remoteHost, int remotePort) {
this.cf = cf; this.cf = cf;
this.remoteHost = remoteHost;
this.remotePort = remotePort;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
ChannelPipeline p = pipeline(); // Note the static import. ChannelPipeline p = pipeline(); // Note the static import.
p.addLast("handler", new HexDumpProxyInboundHandler(cf, remoteHost, remotePort)); p.addLast("handler", new HexDumpProxyInboundHandler(cf));
return p; return p;
} }
} }

View File

@ -15,91 +15,76 @@
*/ */
package org.jboss.netty.example.qotm; package org.jboss.netty.example.qotm;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.socket.DatagramChannel; import org.jboss.netty.channel.socket.DatagramChannel;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* A UDP broadcast client that asks for a quote of the moment (QOTM) to * A UDP broadcast client that asks for a quote of the moment (QOTM) to {@link QuoteOfTheMomentServer}.
* {@link QuoteOfTheMomentServer}.
* *
* Inspired by <a href="http://goo.gl/BsXVR">the official Java tutorial</a>. * Inspired by <a href="http://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html">the official
* Java tutorial</a>.
*/ */
public class QuoteOfTheMomentClient { public final class QuoteOfTheMomentClient {
private final int port; static final int PORT = Integer.parseInt(System.getProperty("port", "7686"));
public QuoteOfTheMomentClient(int port) {
this.port = port;
}
public void run() {
DatagramChannelFactory f =
new NioDatagramChannelFactory(Executors.newCachedThreadPool());
ConnectionlessBootstrap b = new ConnectionlessBootstrap(f);
// Configure the pipeline factory.
b.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new StringEncoder(CharsetUtil.ISO_8859_1),
new StringDecoder(CharsetUtil.ISO_8859_1),
new QuoteOfTheMomentClientHandler());
}
});
// Enable broadcast
b.setOption("broadcast", "true");
// Allow packets as large as up to 1024 bytes (default is 768).
// You could increase or decrease this value to avoid truncated packets
// or to improve memory footprint respectively.
//
// Please also note that a large UDP packet might be truncated or
// dropped by your router no matter how you configured this option.
// In UDP, a packet is truncated or dropped if it is larger than a
// certain size, depending on router configuration. IPv4 routers
// truncate and IPv6 routers drop a large packet. That's why it is
// safe to send small packets in UDP.
b.setOption(
"receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(1024));
DatagramChannel c = (DatagramChannel) b.bind(new InetSocketAddress(0));
// Broadcast the QOTM request to port 8080.
c.write("QOTM?", new InetSocketAddress("255.255.255.255", port));
// QuoteOfTheMomentClientHandler will close the DatagramChannel when a
// response is received. If the channel is not closed within 5 seconds,
// print an error message and quit.
if (!c.getCloseFuture().awaitUninterruptibly(5000)) {
System.err.println("QOTM request timed out.");
c.close().awaitUninterruptibly();
}
f.releaseExternalResources();
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
int port; ConnectionlessBootstrap b = new ConnectionlessBootstrap(
if (args.length > 0) { new NioDatagramChannelFactory(Executors.newCachedThreadPool()));
port = Integer.parseInt(args[0]);
} else { try {
port = 8080; // Configure the pipeline factory.
b.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
return Channels.pipeline(
new StringEncoder(CharsetUtil.ISO_8859_1),
new StringDecoder(CharsetUtil.ISO_8859_1),
new QuoteOfTheMomentClientHandler());
}
});
// Enable broadcast
b.setOption("broadcast", "true");
// Allow packets as large as up to 1024 bytes (default is 768).
// You could increase or decrease this value to avoid truncated packets
// or to improve memory footprint respectively.
//
// Please also note that a large UDP packet might be truncated or
// dropped by your router no matter how you configured this option.
// In UDP, a packet is truncated or dropped if it is larger than a
// certain size, depending on router configuration. IPv4 routers
// truncate and IPv6 routers drop a large packet. That's why it is
// safe to send small packets in UDP.
b.setOption(
"receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(1024));
DatagramChannel c = (DatagramChannel) b.bind(new InetSocketAddress(0));
// Broadcast the QOTM request to port 8080.
c.write("QOTM?", new InetSocketAddress("255.255.255.255", PORT));
// QuoteOfTheMomentClientHandler will close the DatagramChannel when a
// response is received. If the channel is not closed within 5 seconds,
// print an error message and quit.
if (!c.getCloseFuture().await(5000)) {
System.err.println("QOTM request timed out.");
c.close().sync();
}
} finally {
b.releaseExternalResources();
} }
new QuoteOfTheMomentClient(port).run();
} }
} }

View File

@ -23,8 +23,7 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler { public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler {
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
throws Exception {
String msg = (String) e.getMessage(); String msg = (String) e.getMessage();
if (msg.startsWith("QOTM: ")) { if (msg.startsWith("QOTM: ")) {
System.out.println("Quote of the Moment: " + msg.substring(6)); System.out.println("Quote of the Moment: " + msg.substring(6));
@ -33,8 +32,7 @@ public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
e.getChannel().close(); e.getChannel().close();
} }

View File

@ -15,40 +15,34 @@
*/ */
package org.jboss.netty.example.qotm; package org.jboss.netty.example.qotm;
import java.net.InetSocketAddress;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory; import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.util.CharsetUtil; import org.jboss.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
/** /**
* A UDP server that responds to the QOTM (quote of the moment) request to a * A UDP server that responds to the QOTM (quote of the moment) request to a {@link QuoteOfTheMomentClient}.
* {@link QuoteOfTheMomentClient}.
* *
* Inspired by <a href="http://goo.gl/BsXVR">the official Java tutorial</a>. * Inspired by <a href="http://docs.oracle.com/javase/tutorial/networking/datagrams/clientServer.html">the official
* Java tutorial</a>.
*/ */
public class QuoteOfTheMomentServer { public final class QuoteOfTheMomentServer {
private final int port; private static final int PORT = Integer.parseInt(System.getProperty("port", "7686"));
public QuoteOfTheMomentServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; ConnectionlessBootstrap b = new ConnectionlessBootstrap(new NioDatagramChannelFactory());
}
public void run() {
DatagramChannelFactory f = new NioDatagramChannelFactory();
ConnectionlessBootstrap b = new ConnectionlessBootstrap(f);
// Configure the pipeline factory. // Configure the pipeline factory.
b.setPipelineFactory(new ChannelPipelineFactory() { b.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline( return Channels.pipeline(
new StringEncoder(CharsetUtil.ISO_8859_1), new StringEncoder(CharsetUtil.ISO_8859_1),
new StringDecoder(CharsetUtil.ISO_8859_1), new StringDecoder(CharsetUtil.ISO_8859_1),
@ -74,16 +68,6 @@ public class QuoteOfTheMomentServer {
new FixedReceiveBufferSizePredictorFactory(1024)); new FixedReceiveBufferSizePredictorFactory(1024));
// Bind to the port and start the service. // Bind to the port and start the service.
b.bind(new InetSocketAddress(port)); b.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new QuoteOfTheMomentServer(port).run();
} }
} }

View File

@ -15,13 +15,13 @@
*/ */
package org.jboss.netty.example.qotm; package org.jboss.netty.example.qotm;
import java.util.Random;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.util.Random;
public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler { public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler {
private static final Random random = new Random(); private static final Random random = new Random();
@ -43,8 +43,7 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler
} }
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
throws Exception {
String msg = (String) e.getMessage(); String msg = (String) e.getMessage();
if ("QOTM?".equals(msg)) { if ("QOTM?".equals(msg)) {
e.getChannel().write("QOTM: " + nextQuote(), e.getRemoteAddress()); e.getChannel().write("QOTM: " + nextQuote(), e.getRemoteAddress());
@ -52,8 +51,7 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
throws Exception {
e.getCause().printStackTrace(); e.getCause().printStackTrace();
// We don't close the channel because we can keep serving requests. // We don't close the channel because we can keep serving requests.
} }

View File

@ -24,7 +24,6 @@ import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory; import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -32,88 +31,63 @@ import java.util.concurrent.Executors;
/** /**
* Simple SSL chat client modified from {@link TelnetClient}. * Simple SSL chat client modified from {@link TelnetClient}.
*/ */
public class SecureChatClient { public final class SecureChatClient {
private final SslContext sslCtx; static final String HOST = System.getProperty("host", "127.0.0.1");
private final String host; static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
private final int port;
public SecureChatClient(SslContext sslCtx, String host, int port) { public static void main(String[] args) throws Exception {
this.sslCtx = sslCtx;
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
}
public void run() throws IOException {
// Configure the client. // Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Configure the pipeline factory. try {
bootstrap.setPipelineFactory(new SecureChatClientPipelineFactory(sslCtx)); // Configure the pipeline factory.
bootstrap.setPipelineFactory(new SecureChatClientPipelineFactory(sslCtx));
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(HOST, PORT));
// Wait until the connection attempt succeeds or fails. // Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel(); Channel channel = future.sync().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace(); // Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channel.write(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
channel.getCloseFuture().sync();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
// Close the connection. Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().sync();
} finally {
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources(); bootstrap.releaseExternalResources();
return;
} }
// Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channel.write(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
channel.getCloseFuture().awaitUninterruptibly();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
// Close the connection. Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources();
}
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 the SSL context.
SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
new SecureChatClient(sslCtx, host, port).run();
} }
} }

View File

@ -15,58 +15,34 @@
*/ */
package org.jboss.netty.example.securechat; package org.jboss.netty.example.securechat;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.ssl.SslHandler;
/** /**
* Handles a client-side channel. * Handles a client-side channel.
*/ */
public class SecureChatClientHandler extends SimpleChannelUpstreamHandler { public class SecureChatClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
SecureChatClientHandler.class.getName());
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void channelConnected( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Get the SslHandler from the pipeline
// which were added in SecureChatPipelineFactory.
SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
// Begin handshake.
sslHandler.handshake();
}
@Override
public void messageReceived(
ChannelHandlerContext ctx, MessageEvent e) {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -36,7 +36,7 @@ public class SecureChatClientPipelineFactory implements ChannelPipelineFactory {
this.sslCtx = sslCtx; this.sslCtx = sslCtx;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Add SSL handler first to encrypt and decrypt everything. // Add SSL handler first to encrypt and decrypt everything.
@ -44,11 +44,10 @@ public class SecureChatClientPipelineFactory implements ChannelPipelineFactory {
// and accept any invalid certificates in the client side. // and accept any invalid certificates in the client side.
// You will need something more complicated to identify both // You will need something more complicated to identify both
// and server in the real world. // and server in the real world.
pipeline.addLast("ssl", sslCtx.newHandler()); pipeline.addLast("ssl", sslCtx.newHandler(SecureChatClient.HOST, SecureChatClient.PORT));
// On top of the SSL handler, add the text line codec. // On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder( pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("encoder", new StringEncoder());

View File

@ -27,17 +27,14 @@ import java.util.concurrent.Executors;
/** /**
* Simple SSL chat server modified from {@link TelnetServer}. * Simple SSL chat server modified from {@link TelnetServer}.
*/ */
public class SecureChatServer { public final class SecureChatServer {
private final SslContext sslCtx; static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
private final int port;
public SecureChatServer(SslContext sslCtx, int port) { public static void main(String[] args) throws Exception {
this.sslCtx = sslCtx; SelfSignedCertificate ssc = new SelfSignedCertificate();
this.port = port; SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -48,19 +45,6 @@ public class SecureChatServer {
bootstrap.setPipelineFactory(new SecureChatServerPipelineFactory(sslCtx)); bootstrap.setPipelineFactory(new SecureChatServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8443;
}
SelfSignedCertificate ssc = new SelfSignedCertificate();
SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
new SecureChatServer(sslCtx, port).run();
} }
} }

View File

@ -29,32 +29,24 @@ import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.ssl.SslHandler;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Handles a server-side channel. * Handles a server-side channel.
*/ */
public class SecureChatServerHandler extends SimpleChannelUpstreamHandler { public class SecureChatServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
SecureChatServerHandler.class.getName());
static final ChannelGroup channels = new DefaultChannelGroup(); static final ChannelGroup channels = new DefaultChannelGroup();
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void channelConnected( public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Get the SslHandler in the current pipeline. // Get the SslHandler in the current pipeline.
// We added it in SecureChatPipelineFactory. // We added it in SecureChatPipelineFactory.
final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
@ -65,16 +57,14 @@ public class SecureChatServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void channelDisconnected( public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Unregister the channel from the global channel list // Unregister the channel from the global channel list
// so the channel does not receive messages anymore. // so the channel does not receive messages anymore.
channels.remove(e.getChannel()); channels.remove(e.getChannel());
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Convert to a String first. // Convert to a String first.
String request = (String) e.getMessage(); String request = (String) e.getMessage();
@ -96,12 +86,8 @@ public class SecureChatServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
@ -117,11 +103,9 @@ public class SecureChatServerHandler extends SimpleChannelUpstreamHandler {
if (future.isSuccess()) { if (future.isSuccess()) {
// Once session is secured, send a greeting. // Once session is secured, send a greeting.
future.getChannel().write( future.getChannel().write(
"Welcome to " + InetAddress.getLocalHost().getHostName() + "Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n");
" secure chat service!\n");
future.getChannel().write( future.getChannel().write(
"Your session is protected by " + "Your session is protected by " + sslHandler.getEngine().getSession().getCipherSuite() +
sslHandler.getEngine().getSession().getCipherSuite() +
" cipher suite.\n"); " cipher suite.\n");
// Register the channel to the global channel list // Register the channel to the global channel list

View File

@ -36,7 +36,7 @@ public class SecureChatServerPipelineFactory implements ChannelPipelineFactory {
this.sslCtx = sslCtx; this.sslCtx = sslCtx;
} }
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
// Add SSL handler first to encrypt and decrypt everything. // Add SSL handler first to encrypt and decrypt everything.
@ -47,8 +47,7 @@ public class SecureChatServerPipelineFactory implements ChannelPipelineFactory {
pipeline.addLast("ssl", sslCtx.newHandler()); pipeline.addLast("ssl", sslCtx.newHandler());
// On top of the SSL handler, add the text line codec. // On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder( pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("encoder", new StringEncoder());

View File

@ -15,97 +15,83 @@
*/ */
package org.jboss.netty.example.telnet; package org.jboss.netty.example.telnet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.InsecureTrustManagerFactory;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Simplistic telnet client. * Simplistic telnet client.
*/ */
public class TelnetClient { public final class TelnetClient {
private final String host; static final boolean SSL = System.getProperty("ssl") != null;
private final int port; static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8023"));
public TelnetClient(String host, int port) { public static void main(String[] args) throws Exception {
this.host = host; // Configure SSL.
this.port = port; final SslContext sslCtx;
} if (SSL) {
sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
} else {
sslCtx = null;
}
public void run() throws IOException {
// Configure the client. // Configure the client.
ClientBootstrap bootstrap = new ClientBootstrap( ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory( new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Configure the pipeline factory. try {
bootstrap.setPipelineFactory(new TelnetClientPipelineFactory()); // Configure the pipeline factory.
bootstrap.setPipelineFactory(new TelnetClientPipelineFactory(sslCtx));
// Start the connection attempt. // Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); ChannelFuture future = bootstrap.connect(new InetSocketAddress(HOST, PORT));
// Wait until the connection attempt succeeds or fails. // Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel(); Channel channel = future.sync().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace(); // Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channel.write(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
channel.getCloseFuture().sync();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
// Close the connection. Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().sync();
} finally {
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources(); bootstrap.releaseExternalResources();
return;
} }
// Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
// Sends the received line to the server.
lastWriteFuture = channel.write(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
channel.getCloseFuture().awaitUninterruptibly();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
}
// Close the connection. Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
bootstrap.releaseExternalResources();
}
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length != 2) {
System.err.println(
"Usage: " + TelnetClient.class.getSimpleName() +
" <host> <port>");
return;
}
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
new TelnetClient(host, port).run();
} }
} }

View File

@ -15,9 +15,6 @@
*/ */
package org.jboss.netty.example.telnet; package org.jboss.netty.example.telnet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelStateEvent;
@ -30,32 +27,23 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
*/ */
public class TelnetClientHandler extends SimpleChannelUpstreamHandler { public class TelnetClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
TelnetClientHandler.class.getName());
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Print out the line received from the server. // Print out the line received from the server.
System.err.println(e.getMessage()); System.err.println(e.getMessage());
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,25 +15,35 @@
*/ */
package org.jboss.netty.example.telnet; package org.jboss.netty.example.telnet;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
/** /**
* Creates a newly configured {@link ChannelPipeline} for a new channel. * Creates a newly configured {@link ChannelPipeline} for a new channel.
*/ */
public class TelnetClientPipelineFactory implements public class TelnetClientPipelineFactory implements ChannelPipelineFactory {
ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception { private final SslContext sslCtx;
public TelnetClientPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler());
}
// Add the text line codec combination first, // Add the text line codec combination first,
pipeline.addLast("framer", new DelimiterBasedFrameDecoder( pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
8192, Delimiters.lineDelimiter())); 8192, Delimiters.lineDelimiter()));

View File

@ -15,24 +15,32 @@
*/ */
package org.jboss.netty.example.telnet; package org.jboss.netty.example.telnet;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.util.SelfSignedCertificate;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Simplistic telnet server. * Simplistic telnet server.
*/ */
public class TelnetServer { public final class TelnetServer {
private final int port; static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8023"));
public TelnetServer(int port) { public static void main(String[] args) throws Exception {
this.port = port; // Configure SSL.
} final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
public void run() {
// Configure the server. // Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap( ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( new NioServerSocketChannelFactory(
@ -40,19 +48,9 @@ public class TelnetServer {
Executors.newCachedThreadPool())); Executors.newCachedThreadPool()));
// Configure the pipeline factory. // Configure the pipeline factory.
bootstrap.setPipelineFactory(new TelnetServerPipelineFactory()); bootstrap.setPipelineFactory(new TelnetServerPipelineFactory(sslCtx));
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port)); bootstrap.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new TelnetServer(port).run();
} }
} }

View File

@ -15,11 +15,6 @@
*/ */
package org.jboss.netty.example.telnet; package org.jboss.netty.example.telnet;
import java.net.InetAddress;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelFutureListener;
@ -29,35 +24,31 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import java.net.InetAddress;
import java.util.Date;
/** /**
* Handles a server-side channel. * Handles a server-side channel.
*/ */
public class TelnetServerHandler extends SimpleChannelUpstreamHandler { public class TelnetServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(
TelnetServerHandler.class.getName());
@Override @Override
public void handleUpstream( public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) { if (e instanceof ChannelStateEvent) {
logger.info(e.toString()); System.err.println(e);
} }
super.handleUpstream(ctx, e); super.handleUpstream(ctx, e);
} }
@Override @Override
public void channelConnected( public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Send greeting for a new connection. // Send greeting for a new connection.
e.getChannel().write( e.getChannel().write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
"Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
e.getChannel().write("It is " + new Date() + " now.\r\n"); e.getChannel().write("It is " + new Date() + " now.\r\n");
} }
@Override @Override
public void messageReceived( public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelHandlerContext ctx, MessageEvent e) {
// Cast to a String first. // Cast to a String first.
// We know it is a String because we put some codec in TelnetPipelineFactory. // We know it is a String because we put some codec in TelnetPipelineFactory.
@ -87,12 +78,8 @@ public class TelnetServerHandler extends SimpleChannelUpstreamHandler {
} }
@Override @Override
public void exceptionCaught( public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace();
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close(); e.getChannel().close();
} }
} }

View File

@ -15,25 +15,35 @@
*/ */
package org.jboss.netty.example.telnet; package org.jboss.netty.example.telnet;
import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.ssl.SslContext;
import static org.jboss.netty.channel.Channels.*;
/** /**
* Creates a newly configured {@link ChannelPipeline} for a new channel. * Creates a newly configured {@link ChannelPipeline} for a new channel.
*/ */
public class TelnetServerPipelineFactory implements public class TelnetServerPipelineFactory implements ChannelPipelineFactory {
ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception { private final SslContext sslCtx;
public TelnetServerPipelineFactory(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
public ChannelPipeline getPipeline() {
// Create a default pipeline implementation. // Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline(); ChannelPipeline pipeline = pipeline();
if (sslCtx != null) {
pipeline.addLast("ssl", sslCtx.newHandler());
}
// Add the text line codec combination first, // Add the text line codec combination first,
pipeline.addLast("framer", new DelimiterBasedFrameDecoder( pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
8192, Delimiters.lineDelimiter())); 8192, Delimiters.lineDelimiter()));

View File

@ -15,9 +15,6 @@
*/ */
package org.jboss.netty.example.uptime; package org.jboss.netty.example.uptime;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
@ -28,29 +25,25 @@ import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer; import org.jboss.netty.util.Timer;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/** /**
* Connects to a server periodically to measure and print the uptime of the * Connects to a server periodically to measure and print the uptime of the
* server. This example demonstrates how to implement reliable reconnection * server. This example demonstrates how to implement reliable reconnection
* mechanism in Netty. * mechanism in Netty.
*/ */
public class UptimeClient { public final class UptimeClient {
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
// Sleep 5 seconds before a reconnection attempt. // Sleep 5 seconds before a reconnection attempt.
static final int RECONNECT_DELAY = 5; static final int RECONNECT_DELAY = Integer.parseInt(System.getProperty("reconnectDelay", "5"));
// Reconnect when the server sends nothing for 10 seconds. // Reconnect when the server sends nothing for 10 seconds.
private static final int READ_TIMEOUT = 10; static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("readTimeout", "10"));
private final String host; public static void main(String[] args) throws Exception {
private final int port;
public UptimeClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() {
// Initialize the timer that schedules subsequent reconnection attempts. // Initialize the timer that schedules subsequent reconnection attempts.
final Timer timer = new HashedWheelTimer(); final Timer timer = new HashedWheelTimer();
@ -63,38 +56,18 @@ public class UptimeClient {
// Configure the pipeline factory. // Configure the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() { bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
private final ChannelHandler timeoutHandler = private final ChannelHandler timeoutHandler = new ReadTimeoutHandler(timer, READ_TIMEOUT);
new ReadTimeoutHandler(timer, READ_TIMEOUT); private final ChannelHandler uptimeHandler = new UptimeClientHandler(bootstrap, timer);
private final ChannelHandler uptimeHandler =
new UptimeClientHandler(bootstrap, timer);
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() {
return Channels.pipeline( return Channels.pipeline(timeoutHandler, uptimeHandler);
timeoutHandler, uptimeHandler);
} }
}); });
bootstrap.setOption( bootstrap.setOption("remoteAddress", new InetSocketAddress(HOST, PORT));
"remoteAddress", new InetSocketAddress(host, port));
// Initiate the first connection attempt - the rest is handled by // Initiate the first connection attempt - the rest is handled by
// UptimeClientHandler. // UptimeClientHandler.
bootstrap.connect(); bootstrap.connect();
} }
public static void main(String[] args) throws Exception {
// Print usage if no argument is specified.
if (args.length != 2) {
System.err.println(
"Usage: " + UptimeClient.class.getSimpleName() +
" <host> <port>");
return;
}
// Parse options.
String host = args[0];
int port = Integer.parseInt(args[1]);
new UptimeClient(host, port).run();
}
} }

View File

@ -15,10 +15,6 @@
*/ */
package org.jboss.netty.example.uptime; package org.jboss.netty.example.uptime;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelStateEvent;
@ -29,6 +25,10 @@ import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.Timer; import org.jboss.netty.util.Timer;
import org.jboss.netty.util.TimerTask; import org.jboss.netty.util.TimerTask;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
/** /**
* Keep reconnecting to the server while printing out the current uptime and * Keep reconnecting to the server while printing out the current uptime and
* connection attempt status. * connection attempt status.
@ -57,7 +57,7 @@ public class UptimeClientHandler extends SimpleChannelUpstreamHandler {
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) { public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + 's'); println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + 's');
timer.newTimeout(new TimerTask() { timer.newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception { public void run(Timeout timeout) {
println("Reconnecting to: " + getRemoteAddress()); println("Reconnecting to: " + getRemoteAddress());
bootstrap.connect(); bootstrap.connect();
} }
@ -89,7 +89,7 @@ public class UptimeClientHandler extends SimpleChannelUpstreamHandler {
ctx.getChannel().close(); ctx.getChannel().close();
} }
void println(String msg) { private void println(String msg) {
if (startTime < 0) { if (startTime < 0) {
System.err.format("[SERVER IS DOWN] %s%n", msg); System.err.format("[SERVER IS DOWN] %s%n", msg);
} else { } else {

View File

@ -1,4 +0,0 @@
textarea {
width: 500px;
height: 300px;
}

View File

@ -1,53 +0,0 @@
(function() {
var Sock = function() {
var socket;
if (!window.WebSocket) {
window.WebSocket = window.MozWebSocket;
}
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:8080/websocket");
socket.onopen = onopen;
socket.onmessage = onmessage;
socket.onclose = onclose;
} else {
alert("Your browser does not support Web Socket.");
}
function onopen(event) {
getTextAreaElement().value = "Web Socket opened!";
}
function onmessage(event) {
appendTextArea(event.data);
}
function onclose(event) {
appendTextArea("Web Socket closed");
}
function appendTextArea(newData) {
var el = getTextAreaElement();
el.value = el.value + '\n' + newData;
}
function getTextAreaElement() {
return document.getElementById('responseText');
}
function send(event) {
event.preventDefault();
if (window.WebSocket) {
if (socket.readyState == WebSocket.OPEN) {
socket.send(event.target.message.value);
} else {
alert("The socket is not open.");
}
}
}
document.forms.inputform.addEventListener('submit', send, false);
}
window.addEventListener('load', function() {
new Sock();
}, false);
})();

View File

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Web Socket Example</title>
<link rel="stylesheet" href="css/socket.css">
<script src="js/socket.js"></script>
</head>
<body>
<h1>Enter a message</h1>
<form name="inputform">
<input type="text" name="message" id="message" placeholder="Enter text to be sent" autofocus>
<input type="submit" value="Send Web Socket Data">
</form>
<h2>Repsonse from Server</h2>
<textarea id="responseText"></textarea>
</body>
</html>