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:
parent
aa2c6b77e3
commit
ba28679775
16
pom.xml
16
pom.xml
|
@ -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
87
run-example.sh
Executable 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"
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
textarea {
|
|
||||||
width: 500px;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
})();
|
|
|
@ -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>
|
|
Loading…
Reference in New Issue
Block a user