ssl 认证、单向认证和双向认证
SSL认证,客户端到服务器端的认证,主要用来提供对用户和服务器的认证,对传送的数据进行加密和隐藏,确保数据在传送中不被改变,即数据的完整性,现已成为该领域中全球化的标准。
单向认证,服务端部署 SSL证书 就行,任何用户都可以去访问(IP被限制除外等),只是服务端提供了身份认证。
双向认证,服务端部署SSL证书,也需要客户端提供身份认证,只有服务端允许的客户端才能访问,安全性相对于要高一些。
:
客户端&客户端代码总结:
// false为服务器端模式,true为客户端模式
SSL Engine.setUseClientMode(false);
//false为单向认证,true为双向认证
sslEngine.setNeedClientAuth(true);
单向认证代码
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdkto18</artifactId>
<version>.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdkto18</artifactId>
<version>.70</version>
</dependency>
<!-- netty -all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>.1.60.Final</version>
</dependency>
服务器端:
package com.what.netty01.demo02.server;
import io.netty.bootstrap.Server Bootstrap ;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel. socket .nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class Secure ChatServer {
public void run(int port) throws Interrupted Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup )
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new SecureChatServerInitializer());
ChannelFuture cf = b.bind(port).sync();
cf.channel().closeFuture().sync();
} finally {
bossGroup. shutdown Gracefully();
workGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new SecureChatServer().run();
}
}
package com.what.netty01.demo02.server;
import javax .net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java .io. File InputStream;
import java.io.IOException;
import java.io. InputStream ;
import java.security.KeyStore;
public class SecureChatServerSslContextFactory {
private static final String PROTOCOL = "TLS";
//服务器安全套接字协议
private static SSLContext SERVER_CONTEXT;
/**
* @param pkPath
* @return
*/
public static SSLContext getServerContext(String pkPath) {
if (SERVER_CONTEXT != null) {
return SERVER_CONTEXT;
}
InputStream in = null;
try {
//密钥管理器
KeyManagerFactory kmf = null;
if (pkPath != null) {
//密钥库KeyStore
KeyStore ks = KeyStore. getInstance ("JKS");
//加载服务端证书
in = new FileInputStream(pkPath);
//加载服务端的KeyStore ;sNetty是生成仓库时设置的密码,用于检查密钥库完整性的密码
ks.load(in, "".toCharArray());
kmf = KeyManagerFactory.getInstance("SunX");
//初始化密钥管理器
kmf.init(ks, "".toCharArray());
}
//获取安全套接字协议( TLS协议 )的对象
SERVER_CONTEXT = SSLContext.getInstance(PROTOCOL);
//初始化此上下文
//参数一:认证的密钥 参数二:对等信任认证 参数三: 伪随机数 生成器 。 由于单向认证,服务端不用验证客户端,所以第二个参数为null
SERVER_CONTEXT.init(kmf.getKeyManagers(), null, null);
} catch (Exception e) {
throw new Error("Failed to initialize the server-side SSLContext", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return SERVER_CONTEXT;
}
}
package com.what.netty01.demo02.server;
import javax.net.ssl.SSLEngine;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslHandler;
public class SecureChatServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline pipeline = sc.pipeline();
String sChatPath = "d:/server.jks";
SSLEngine engine = SecureChatServerSslContextFactory.getServerContext(sChatPath).createSSLEngine();
engine.setUseClientMode(false);//设置为服务器模式
//engine.setNeedClientAuth(false);//不需要客户端认证,默认为false,故不需要写这行。
pipeline.addLast("ssl", new SslHandler(engine));
// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic.
pipeline.addLast("handler", new SecureChatServerHandler());
}
}
package com.what.netty01.demo02.server;
import java.net.InetAddress;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.GlobalEventExecutor;
public class SecureChatServerHandler extends SimpleChannelInboundHandler<String> {
static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead(ChannelHandlerContext ctx, String msg) throws Exception {
// Send the received message to all channels but the current one.
for (Channel c : channels) {
if (c != ctx.channel()) {
c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n');
} else {
c.writeAndFlush("[you] " + msg + '\n');
}
}
// Close the connection if the client has sent 'bye'.
if ("bye".equals(msg.toLowerCase())) {
ctx.close();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Once session is secured, send a greeting and register the channel to
// the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture()
.addListener(new GenericFutureListener<Future<Channel>>() {
@Override
public void operationComplete(Future<Channel> arg)
throws Exception {
ctx.writeAndFlush("Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n");
ctx.writeAndFlush("Your session is protected by " + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() + " cipher suite.\n");
channels.add(ctx.channel());
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端:
package com.what.netty01.demo02.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
public class SecureChatClient {
public void start(String host,int port) throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
try{
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new SecureChatClientInitializer());
// Start the connection attempt.
Channel ch = b.connect(host, port).sync().channel();
// 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 = ch.writeAndFlush(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
ch.closeFuture().sync();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
}finally{
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new SecureChatClient().start("localhost",);
}
}
package com.what.netty01.demo02.client;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
public final class SecureChatClientSslContextFactory {
private static final String PROTOCOL = "TLS";
//客户端安全套接字协议
private static SSLContext CLIENT_CONTEXT;
public static SSLContext getClientContext(String caPath) {
if (CLIENT_CONTEXT != null) {
return CLIENT_CONTEXT;
}
InputStream tIN = null;
try {
//信任库
TrustManagerFactory tf = null;
if (caPath != null) {
//密钥库KeyStore
KeyStore tks = KeyStore.getInstance("JKS");
//加载客户端证书
tIN = new FileInputStream(caPath);
tks.load(tIN, "".toCharArray());
tf = TrustManagerFactory.getInstance("SunX");
// 初始化信任库
tf.init(tks);
}
CLIENT_CONTEXT = SSLContext.getInstance(PROTOCOL);
//设置信任证书
TrustManager[] gtf = tf.getTrustManagers();
CLIENT_CONTEXT.init(null, tf == null ? null : gtf, null);
} catch (Exception e) {
throw new Error("Failed to initialize the client-side SSLContext");
} finally {
if (tIN != null) {
try {
tIN.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return CLIENT_CONTEXT;
}
}
package com.what.netty01.demo02.client;
import javax.net.ssl.SSLEngine;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslHandler;
public class SecureChatClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
String cChatPath = "d:/client.jks";
//创建SSLEngine
SSLEngine engine = SecureChatClientSslContextFactory.getClientContext(cChatPath).createSSLEngine();
//客户方模式
engine.setUseClientMode(true);
pipeline.addLast("ssl", new SslHandler(engine));
// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// and then business logic.
pipeline.addLast("handler", new SecureChatClientHandler());
}
}
package com.what.netty01.demo02.client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SecureChatClientHandler extends SimpleChannelInboundHandler<String> {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead(ChannelHandlerContext ctx, String msg) throws Exception {
System.err.println(msg);
}
}
双向认证代码
package com.what.netty01.demo03;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
/**
* 初始化sslcontext类
*/
public class ContextSSLFactory {
private static final SSLContext SSL_CONTEXT_S;
private static final SSLContext SSL_CONTEXT_C;
static {
SSLContext sslContext = null;
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSLv");
sslContext = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
if (getKeyManagersServer() != null && getTrustManagersServer() != null) {
sslContext.init(getKeyManagersServer(), getTrustManagersServer(), null);
}
if (getKeyManagersClient() != null && getTrustManagersClient() != null) {
sslContext.init(getKeyManagersClient(), getTrustManagersClient(), null);
}
} catch (Exception e) {
e.printStackTrace();
}
sslContext.createSSLEngine().getSupportedCipherSuites();
sslContext.createSSLEngine().getSupportedCipherSuites();
SSL_CONTEXT_S = sslContext;
SSL_CONTEXT_C = sslContext;
}
public ContextSSLFactory() {
}
public static SSLContext getSslContext() {
return SSL_CONTEXT_S;
}
public static SSLContext getSslContext() {
return SSL_CONTEXT_C;
}
private static TrustManager[] getTrustManagersServer() {
FileInputStream is = null;
KeyStore ks = null;
TrustManagerFactory keyFac = null;
TrustManager[] kms = null;
try {
// 获得KeyManagerFactory对象. 初始化位默认算法
keyFac = TrustManagerFactory.getInstance("SunX");
is = new FileInputStream("d:/server.jks");
ks = KeyStore.getInstance("JKS");
String keyStorePass = "";
ks.load(is, keyStorePass.toCharArray());
keyFac.init(ks);
kms = keyFac.getTrustManagers();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return kms;
}
private static TrustManager[] getTrustManagersClient() {
FileInputStream is = null;
KeyStore ks = null;
TrustManagerFactory keyFac = null;
TrustManager[] kms = null;
try {
// 获得KeyManagerFactory对象. 初始化位默认算法
keyFac = TrustManagerFactory.getInstance("SunX");
is = new FileInputStream("d:/client.jks");
ks = KeyStore.getInstance("JKS");
String keyStorePass = "";
ks.load(is, keyStorePass.toCharArray());
keyFac.init(ks);
kms = keyFac.getTrustManagers();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return kms;
}
private static KeyManager[] getKeyManagersServer() {
FileInputStream is = null;
KeyStore ks = null;
KeyManagerFactory keyFac = null;
KeyManager[] kms = null;
try {
// 获得KeyManagerFactory对象. 初始化位默认算法
keyFac = KeyManagerFactory.getInstance("SunX");
is = new FileInputStream("d:/server.jks");
ks = KeyStore.getInstance("JKS");
String keyStorePass = "";
ks.load(is, keyStorePass.toCharArray());
keyFac.init(ks, keyStorePass.toCharArray());
kms = keyFac.getKeyManagers();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return kms;
}
private static KeyManager[] getKeyManagersClient() {
FileInputStream is = null;
KeyStore ks = null;
KeyManagerFactory keyFac = null;
KeyManager[] kms = null;
try {
// 获得KeyManagerFactory对象. 初始化位默认算法
keyFac = KeyManagerFactory.getInstance("SunX");
is = new FileInputStream("d:/client.jks");
ks = KeyStore.getInstance("JKS");
String keyStorePass = "";
ks.load(is, keyStorePass.toCharArray());
keyFac.init(ks, keyStorePass.toCharArray());
kms = keyFac.getKeyManagers();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return kms;
}
}
服务器端:
package com.what.netty01.demo03.server;
import javax.net.ssl.SSLEngine;
import com.what.netty01.demo03.ContextSSLFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslHandler;
public class NettySocketServer {
private static SslHandler sslHandler = null;
private EventLoopGroup bossGroup = null;
private EventLoopGroup workerGroup = null;
public void start() {
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverStrap = new ServerBootstrap();
serverStrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, * 5 * 60)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pie = socketChannel.pipeline();
pie.addLast("decoder", new MyServerDecoder());
pie.addLast("encoder", new MyServerEncoder());
pie.addLast("handler", new NettySocketSSLHandler());
SSLEngine engine = ContextSSLFactory.getSslContext().createSSLEngine();
engine.setUseClientMode(false);
engine.setNeedClientAuth(true);
pie.addFirst("ssl", new SslHandler(engine));
}
});
serverStrap.bind().sync();
System.out.println("服务已开启...");
} catch (Exception e) {
e.printStackTrace();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private SslHandler getSslHandler() {
if (sslHandler == null) {
SSLEngine sslEngine = ContextSSLFactory.getSslContext().createSSLEngine();
// false为服务器端模式,true为客户端模式
sslEngine.setUseClientMode(false);
//false为单向认证,true为双向认证
sslEngine.setNeedClientAuth(true);
sslHandler = new SslHandler(sslEngine);
}
return sslHandler;
}
public static void main(String[] args) {
new NettySocketServer().start();
}
}
package com.what.netty01.demo03.server;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.InetAddress;
import java.nio.ByteBuffer;
public class NettySocketSSLHandler extends SimpleChannelInboundHandler<ByteBuffer> {
@Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
// Once session is secured, send a greeting and register the channel to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
new GenericFutureListener<Future<Channel>>() {
@Override
public void operationComplete(Future<Channel> future) throws Exception {
if (future.isSuccess()) {
System.out.println("握手成功");
byte[] array = new byte[]{(byte)d, 04};
ByteBuffer bu = ByteBuffer.wrap(array);
ctx.channel().writeAndFlush(bu);
} else {
System.out.println("握手失败");
}
ctx.writeAndFlush(
"Welcome to " + InetAddress.getLocalHost().getHostName() +
" secure chat service!\n");
ctx.writeAndFlush(
"Your session is protected by " +
ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
" cipher suite.\n");
}
});
}
@Override
protected void channelRead(ChannelHandlerContext ctx, ByteBuffer byteBuffer) throws Exception {
ctx.channel().writeAndFlush(byteBuffer);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx)
throws Exception {
System.out.println("增加:" + ctx.channel().remoteAddress());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
System.out.println("移除:" + ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("Unexpected exception from downstream.");
ctx.close();
}
}
package com.what.netty01.demo03.server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import java.nio.ByteBuffer;
public class MyServerEncoder extends MessageToByteEncoder<ByteBuffer>{
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuffer message,
ByteBuf out) throws Exception {
if(message==null){
return;
}
if(message.hasArray()){
byte[] msg =message.array();
if(msg == null || msg.length <=){
return;
}
out.writeBytes(msg) ;
}
}
}
package com.what.netty01.demo03.server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.nio.ByteBuffer;
import java.util.List;
public class MyServerDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer,
List<Object> out) throws Exception {
//UnpooledUnsafeDirectByteBuf(ridx:, widx: 1, cap: 1024)
if (buffer != null) {
ByteBuffer msg = null;
try {
if(buffer.readableBytes() > ){
msg = ByteBuffer.allocate(buffer.readableBytes()) ;
byte[] bb = new byte[buffer.readableBytes()] ;
buffer.readBytes(bb) ;
msg.put(bb);
msg.flip();
}
} catch (Exception e) {
e.printStackTrace();
msg = null ;
}
if (msg != null) {
out.add(msg);
}
}
}
}
客户端:
package com.what.netty01.demo03.client;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import javax.net.ssl.SSLEngine;
import com.what.netty01.demo03.ContextSSLFactory;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslHandler;
public class NettySocketClient {
private EventLoopGroup group ;
private Channel channel = null ;
public void connect(String ip , int port){
group = new NioEventLoopGroup();
try{
Bootstrap strap = new Bootstrap();
strap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE , true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pieple = socketChannel.pipeline() ;
pieple.addLast("decoder" , new MyClientDecoder()) ;
pieple.addLast("encoder" , new MyClientEncoder()) ;
pieple.addLast("handler" , new NettySocketSSLClientHandler()) ;
SSLEngine engine = ContextSSLFactory.getSslContext().createSSLEngine();
engine.setUseClientMode(true);
pieple.addFirst("ssl", new SslHandler(engine));
}
});
SocketAddress address = new InetSocketAddress(ip, port);
final ChannelFuture future = strap.connect(address).sync();
channel = future.awaitUninterruptibly().channel();
System.out.println("连接成功, channel =" + channel.remoteAddress());
}catch(Exception e ){
e.printStackTrace();
group.shutdownGracefully() ;
}finally{
}
}
private static SslHandler sslHandlerClient = null ;
public static SslHandler getSslHandler(){
if(sslHandlerClient == null){
SSLEngine sslEngine = ContextSSLFactory.getSslContext().createSSLEngine() ;
sslEngine.setUseClientMode(true) ;
sslHandlerClient = new SslHandler(sslEngine);
}
return sslHandlerClient ;
}
public static void main(String[] args) {
new NettySocketClient().connect(".0.0.1", 16161) ;
}
}
package com.what.netty01.demo03.client;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.InetAddress;
import java.nio.ByteBuffer;
public class NettySocketSSLClientHandler extends SimpleChannelInboundHandler<ByteBuffer> {
@Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
// Once session is secured, send a greeting and register the channel to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
new GenericFutureListener<Future<Channel>>() {
@Override
public void operationComplete(Future<Channel> future) throws Exception {
if (future.isSuccess()) {
System.out.println("握手成功");
byte[] array = new byte[]{(byte)d, 04};
ByteBuffer bu = ByteBuffer.wrap(array);
ctx.channel().writeAndFlush(bu);
} else {
System.out.println("握手失败");
}
ctx.writeAndFlush("Welcome to " + InetAddress.getLocalHost().getHostName() +
" secure chat service!\n");
ctx.writeAndFlush("Your session is protected by " +
ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
" cipher suite.\n");
}
});
}
@Override
protected void channelRead(ChannelHandlerContext ctx, ByteBuffer byteBuffer) throws Exception {
Thread.sleep();
System.out.println("客户端 receive msg ");
byte[] array = new byte[]{, 01, 00, 00, 00, 06, 05, 03, (byte) 7d, 00, 00, 07};
ByteBuffer bu = ByteBuffer.wrap(array);
ctx.channel().writeAndFlush(bu);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx)
throws Exception {
System.out.println("增加:" + ctx.channel().remoteAddress());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
System.out.println("移除:" + ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("Unexpected exception from downstream.");
ctx.close();
}
}
package com.what.netty01.demo03.client;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import java.nio.ByteBuffer;
public class MyClientEncoder extends MessageToByteEncoder<ByteBuffer>{
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuffer message,
ByteBuf out) throws Exception {
if(message==null){
return;
}
if(message .hasArray()){
byte[] msg =message.array();
if(msg == null || msg.length <=){
return;
}
out.writeBytes(msg);
}
}
}
package com.what.netty01.demo03.client;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.nio.ByteBuffer;
import java.util.List;
public class MyClientDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer,
List<Object> out) throws Exception {
//UnpooledUnsafeDirectByteBuf(ridx:, widx: 1, cap: 1024)
if (buffer != null) {
ByteBuffer msg = null;
try {
if(buffer.readableBytes() > ){
msg = ByteBuffer.allocate(buffer.readableBytes()) ;
byte[] bb = new byte[buffer.readableBytes()] ;
buffer.readBytes(bb) ;
msg.put(bb);
msg.flip();
}
} catch (Exception e) {
e.printStackTrace();
msg = null ;
}
if (msg != null) {
out.add(msg);
}
}
}
}