Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit939e473

Browse files
committed
add * [基于SSL/TSL的双向认证Echo服务器和客户端](netty4-demos/src/main/java/com/waylau/java/demo/secureecho)
1 parentefa4cb6 commit939e473

File tree

12 files changed

+375
-1
lines changed

12 files changed

+375
-1
lines changed

‎README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ Demos of [Netty 4.x User Guide](https://github.com/waylau/netty-4-user-guide)
2828
*[自定义编码器](netty4-demos/src/main/java/com/waylau/java/demo/encoder)
2929
*[自定义编解码器](netty4-demos/src/main/java/com/waylau/java/demo/codec)
3030
*[实现心跳机制](netty4-demos/src/main/java/com/waylau/java/demo/heartbeat)
31-
* ...
31+
*[基于SSL/TSL的双向认证Echo服务器和客户端](netty4-demos/src/main/java/com/waylau/java/demo/secureecho)
32+
* 陆续整理中...
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
packagecom.waylau.netty.demo.secureecho;
2+
3+
importjava.io.BufferedReader;
4+
importjava.io.IOException;
5+
importjava.io.InputStreamReader;
6+
importjava.net.UnknownHostException;
7+
importjava.nio.ByteBuffer;
8+
9+
importio.netty.bootstrap.Bootstrap;
10+
importio.netty.buffer.ByteBuf;
11+
importio.netty.buffer.Unpooled;
12+
importio.netty.channel.Channel;
13+
importio.netty.channel.ChannelFuture;
14+
importio.netty.channel.ChannelOption;
15+
importio.netty.channel.EventLoopGroup;
16+
importio.netty.channel.nio.NioEventLoopGroup;
17+
importio.netty.channel.socket.nio.NioSocketChannel;
18+
19+
/**
20+
* Echo Client.
21+
*
22+
* @since 1.0.0 2019年10月2日
23+
* @author <a href="https://waylau.com">Way Lau</a>
24+
*/
25+
publicfinalclassEchoClient {
26+
27+
publicstaticvoidmain(String[]args)throwsException {
28+
if (args.length !=2) {
29+
System.err.println("用法: java EchoClient <host name> <port number>");
30+
System.exit(1);
31+
}
32+
33+
StringhostName =args[0];
34+
intportNumber =Integer.parseInt(args[1]);
35+
36+
// 配置客户端
37+
EventLoopGroupgroup =newNioEventLoopGroup();
38+
try {
39+
Bootstrapb =newBootstrap();
40+
b.group(group)
41+
.channel(NioSocketChannel.class)
42+
.option(ChannelOption.TCP_NODELAY,true)
43+
.handler(newEchoClientChannelInitializer());
44+
45+
// 连接到服务器
46+
ChannelFuturef =b.connect(hostName,portNumber).sync();
47+
48+
Channelchannel =f.channel();
49+
ByteBufferwriteBuffer =ByteBuffer.allocate(32);
50+
try (BufferedReaderstdIn =newBufferedReader(newInputStreamReader(System.in))) {
51+
StringuserInput;
52+
while ((userInput =stdIn.readLine()) !=null) {
53+
writeBuffer.put(userInput.getBytes());
54+
writeBuffer.flip();
55+
writeBuffer.rewind();
56+
57+
// 转为ByteBuf
58+
ByteBufbuf =Unpooled.copiedBuffer(writeBuffer);
59+
60+
// 写消息到管道
61+
channel.writeAndFlush(buf);
62+
63+
// 清理缓冲区
64+
writeBuffer.clear();
65+
}
66+
}catch (UnknownHostExceptione) {
67+
System.err.println("不明主机,主机名为: " +hostName);
68+
System.exit(1);
69+
}catch (IOExceptione) {
70+
System.err.println("不能从主机中获取I/O,主机名为:" +hostName);
71+
System.exit(1);
72+
}
73+
}finally {
74+
75+
// 优雅的关闭
76+
group.shutdownGracefully();
77+
}
78+
}
79+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Welcome to https://waylau.com
3+
*/
4+
packagecom.waylau.netty.demo.secureecho;
5+
6+
importjavax.net.ssl.SSLEngine;
7+
8+
importio.netty.channel.ChannelInitializer;
9+
importio.netty.channel.socket.SocketChannel;
10+
importio.netty.handler.ssl.SslHandler;
11+
12+
/**
13+
* Echo Client ChannelInitializer.
14+
*
15+
* @since 1.0.0 2019年12月25日
16+
* @author <a href="https://waylau.com">Way Lau</a>
17+
*/
18+
publicclassEchoClientChannelInitializerextendsChannelInitializer<SocketChannel> {
19+
20+
@Override
21+
protectedvoidinitChannel(SocketChannelch)throwsException {
22+
23+
// 先添加SslHandler
24+
StringpkPath =System.getProperties().getProperty("user.dir")
25+
+"/src/main/resources/ssl/nettyClient.jks";
26+
Stringpassword ="defaultPass";
27+
SSLEngineengine =SslContextFactory.getServerContext(pkPath,pkPath,password).createSSLEngine();
28+
engine.setUseClientMode(true);// 设置为服务器模式
29+
engine.setNeedClientAuth(true);// 需要客户端认证
30+
ch.pipeline().addLast(newSslHandler(engine));
31+
32+
// 再添加其他ChannelHandler
33+
ch.pipeline().addLast(newEchoClientHandler());
34+
}
35+
36+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
packagecom.waylau.netty.demo.secureecho;
2+
3+
importio.netty.buffer.ByteBuf;
4+
importio.netty.channel.ChannelHandlerContext;
5+
importio.netty.channel.ChannelInboundHandlerAdapter;
6+
importio.netty.util.CharsetUtil;
7+
8+
/**
9+
* Echo Client Handler.
10+
*
11+
* @since 1.0.0 2019年10月2日
12+
* @author <a href="https://waylau.com">Way Lau</a>
13+
*/
14+
publicclassEchoClientHandlerextendsChannelInboundHandlerAdapter {
15+
@Override
16+
publicvoidchannelRead(ChannelHandlerContextctx,Objectmsg) {
17+
// 接收服务器的信息并打印到控制台
18+
ByteBufin = (ByteBuf)msg;
19+
System.out.println(ctx.channel().remoteAddress() +" -> Client :" +
20+
in.toString(CharsetUtil.UTF_8));
21+
22+
}
23+
24+
@Override
25+
publicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause) {
26+
27+
// 当出现异常就关闭连接
28+
cause.printStackTrace();
29+
ctx.close();
30+
}
31+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
packagecom.waylau.netty.demo.secureecho;
2+
3+
importio.netty.bootstrap.ServerBootstrap;
4+
importio.netty.channel.ChannelFuture;
5+
importio.netty.channel.ChannelOption;
6+
importio.netty.channel.EventLoopGroup;
7+
importio.netty.channel.nio.NioEventLoopGroup;
8+
importio.netty.channel.socket.nio.NioServerSocketChannel;
9+
10+
/**
11+
* Echo Server.
12+
*
13+
* @since 1.0.0 2019年10月2日
14+
* @author <a href="https://waylau.com">Way Lau</a>
15+
*/
16+
publicclassEchoServer {
17+
18+
publicstaticintDEFAULT_PORT =7;
19+
20+
publicstaticvoidmain(String[]args)throwsException {
21+
intport;
22+
23+
try {
24+
port =Integer.parseInt(args[0]);
25+
}catch (RuntimeExceptionex) {
26+
port =DEFAULT_PORT;
27+
}
28+
29+
// 多线程事件循环器
30+
EventLoopGroupbossGroup =newNioEventLoopGroup(1);// boss
31+
EventLoopGroupworkerGroup =newNioEventLoopGroup();// worker
32+
33+
try {
34+
// 启动NIO服务的引导程序类
35+
ServerBootstrapb =newServerBootstrap();
36+
37+
b.group(bossGroup,workerGroup)// 设置EventLoopGroup
38+
.channel(NioServerSocketChannel.class)// 指明新的Channel的类型
39+
.childHandler(newEchoServerChannelInitializer())// 指定ChannelHandler
40+
.option(ChannelOption.SO_BACKLOG,128)// 设置的ServerChannel的一些选项
41+
.childOption(ChannelOption.SO_KEEPALIVE,true);// 设置的ServerChannel的子Channel的选项
42+
43+
// 绑定端口,开始接收进来的连接
44+
ChannelFuturef =b.bind(port).sync();
45+
46+
System.out.println("EchoServer已启动,端口:" +port);
47+
48+
// 等待服务器 socket 关闭 。
49+
// 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
50+
f.channel().closeFuture().sync();
51+
}finally {
52+
53+
// 优雅的关闭
54+
workerGroup.shutdownGracefully();
55+
bossGroup.shutdownGracefully();
56+
}
57+
58+
}
59+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Welcome to https://waylau.com
3+
*/
4+
packagecom.waylau.netty.demo.secureecho;
5+
6+
importjavax.net.ssl.SSLEngine;
7+
8+
importio.netty.channel.ChannelInitializer;
9+
importio.netty.channel.socket.SocketChannel;
10+
importio.netty.handler.ssl.SslHandler;
11+
12+
/**
13+
* Echo Server ChannelInitializer.
14+
*
15+
* @since 1.0.0 2019年12月25日
16+
* @author <a href="https://waylau.com">Way Lau</a>
17+
*/
18+
publicclassEchoServerChannelInitializerextendsChannelInitializer<SocketChannel> {
19+
20+
@Override
21+
protectedvoidinitChannel(SocketChannelch)throwsException {
22+
23+
// 先添加SslHandler
24+
StringpkPath =System.getProperties().getProperty("user.dir") +"/src/main/resources/ssl/nettyServer.jks";
25+
Stringpassword ="defaultPass";
26+
SSLEngineengine =SslContextFactory.getServerContext(pkPath,pkPath,password).createSSLEngine();
27+
engine.setUseClientMode(false);// 设置为服务器模式
28+
engine.setNeedClientAuth(true);// 需要客户端认证
29+
ch.pipeline().addLast(newSslHandler(engine));
30+
31+
// 再添加其他ChannelHandler
32+
ch.pipeline().addLast(newEchoServerHandler());
33+
}
34+
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
packagecom.waylau.netty.demo.secureecho;
2+
3+
importio.netty.buffer.ByteBuf;
4+
importio.netty.channel.ChannelHandlerContext;
5+
importio.netty.channel.ChannelInboundHandlerAdapter;
6+
importio.netty.util.CharsetUtil;
7+
8+
/**
9+
* Echo Server Handler.
10+
*
11+
* @since 1.0.0 2019年12月25日
12+
* @author <a href="https://waylau.com">Way Lau</a>
13+
*/
14+
publicclassEchoServerHandlerextendsChannelInboundHandlerAdapter {
15+
16+
@Override
17+
publicvoidchannelRead(ChannelHandlerContextctx,Objectmsg) {
18+
// 接收客户端的信息并打印到控制台
19+
ByteBufin = (ByteBuf)msg;
20+
System.out.println(ctx.channel().remoteAddress() +" -> Server :" +
21+
in.toString(CharsetUtil.UTF_8));
22+
23+
// 写消息到管道
24+
ctx.write(msg);// 写消息
25+
ctx.flush();// 刷新消息
26+
}
27+
28+
@Override
29+
publicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause) {
30+
31+
// 当出现异常就关闭连接
32+
cause.printStackTrace();
33+
ctx.close();
34+
}
35+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Welcome to https://waylau.com
3+
*/
4+
packagecom.waylau.netty.demo.secureecho;
5+
6+
importjavax.net.ssl.KeyManagerFactory;
7+
importjavax.net.ssl.SSLContext;
8+
importjavax.net.ssl.TrustManagerFactory;
9+
importjava.io.FileInputStream;
10+
importjava.io.IOException;
11+
importjava.io.InputStream;
12+
importjava.security.KeyStore;
13+
14+
/**
15+
* SslContext Factory.
16+
*
17+
* @since 1.0.0 2019年12月25日
18+
* @author <a href="https://waylau.com">Way Lau</a>
19+
*/
20+
publicfinalclassSslContextFactory {
21+
privatestaticfinalStringPROTOCOL ="TLS";
22+
23+
privatestaticSSLContextSERVER_CONTEXT;// 服务器上下文
24+
25+
privatestaticSSLContextCLIENT_CONTEXT;// 客户端上下文
26+
27+
publicstaticSSLContextgetServerContext(StringpkPath,StringcaPath,Stringpassword) {
28+
if (SERVER_CONTEXT !=null)
29+
returnSERVER_CONTEXT;
30+
31+
SERVER_CONTEXT =getContext(pkPath,caPath,password);
32+
33+
returnSERVER_CONTEXT;
34+
}
35+
36+
publicstaticSSLContextgetClientContextgetContext(StringpkPath,StringcaPath,Stringpassword) {
37+
if (CLIENT_CONTEXT !=null)
38+
returnCLIENT_CONTEXT;
39+
40+
CLIENT_CONTEXT =getContext(pkPath,caPath,password);
41+
42+
returnCLIENT_CONTEXT;
43+
}
44+
45+
publicstaticSSLContextgetContext(StringpkPath,StringcaPath,Stringpassword) {
46+
if (CLIENT_CONTEXT !=null)
47+
returnCLIENT_CONTEXT;
48+
49+
InputStreamin =null;
50+
InputStreamtIN =null;
51+
try {
52+
KeyManagerFactorykmf =null;
53+
if (pkPath !=null) {
54+
KeyStoreks =KeyStore.getInstance("JKS");
55+
in =newFileInputStream(pkPath);
56+
ks.load(in,password.toCharArray());
57+
kmf =KeyManagerFactory.getInstance("SunX509");
58+
kmf.init(ks,password.toCharArray());
59+
}
60+
61+
TrustManagerFactorytf =null;
62+
if (caPath !=null) {
63+
KeyStoretks =KeyStore.getInstance("JKS");
64+
tIN =newFileInputStream(caPath);
65+
tks.load(tIN,password.toCharArray());
66+
tf =TrustManagerFactory.getInstance("SunX509");
67+
tf.init(tks);
68+
}
69+
70+
CLIENT_CONTEXT =SSLContext.getInstance(PROTOCOL);
71+
CLIENT_CONTEXT.init(kmf.getKeyManagers(),tf.getTrustManagers(),null);
72+
73+
}catch (Exceptione) {
74+
thrownewError("Failed to initialize the client-side SSLContext");
75+
}finally {
76+
if (in !=null) {
77+
try {
78+
in.close();
79+
}catch (IOExceptione) {
80+
e.printStackTrace();
81+
}
82+
in =null;
83+
}
84+
85+
if (tIN !=null) {
86+
try {
87+
tIN.close();
88+
}catch (IOExceptione) {
89+
e.printStackTrace();
90+
}
91+
tIN =null;
92+
}
93+
}
94+
95+
returnCLIENT_CONTEXT;
96+
}
97+
98+
}
719 Bytes
Binary file not shown.
3.19 KB
Binary file not shown.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp