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> { | |
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); | |
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(); | |
} | |
} | |
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>>() { | |
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()); | |
} | |
}); | |
} | |
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> { | |
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> { | |
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |
cause.printStackTrace(); | |
ctx.close(); | |
} | |
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>() { | |
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> { | |
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>>() { | |
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"); | |
} | |
}); | |
} | |
protected void channelRead(ChannelHandlerContext ctx, ByteBuffer byteBuffer) throws Exception { | |
ctx.channel().writeAndFlush(byteBuffer); | |
} | |
public void handlerAdded(ChannelHandlerContext ctx) | |
throws Exception { | |
System.out.println("增加:" + ctx.channel().remoteAddress()); | |
} | |
public void handlerRemoved(ChannelHandlerContext ctx) { | |
System.out.println("移除:" + ctx.channel().remoteAddress()); | |
} | |
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>{ | |
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 { | |
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>() { | |
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> { | |
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>>() { | |
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"); | |
} | |
}); | |
} | |
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); | |
} | |
public void handlerAdded(ChannelHandlerContext ctx) | |
throws Exception { | |
System.out.println("增加:" + ctx.channel().remoteAddress()); | |
} | |
public void handlerRemoved(ChannelHandlerContext ctx) { | |
System.out.println("移除:" + ctx.channel().remoteAddress()); | |
} | |
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>{ | |
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 { | |
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); | |
} | |
} | |
} | |
} |