因需要https服务器,准备用netty3.x版本搭建一个https服务器,但是怎么弄都没有搞好.所以就选了netty4.x版本.(netty3.x最低JDK1.5,netty4.x最低JDK1.6).下面介绍下netty4.x搭建https服务器.
1. HTTPS服务器启动类
如果想启动多个服务器可以采用多个线程启动多个端口号
package best.nettyserver.https;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class ActivorHttpsServer {
public static void main(String[] args) {
new ActivorHttpsServer().start(9998);
}
public void start(int port){
// 创建EventLoopGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(); //创建BOSS线程组 用于服务端接受客户端的连接
EventLoopGroup workerGroup = new NioEventLoopGroup(); //创建WORK线程组 用于进行SocketChannel的网络读写
try {
// 创建ServerBootStrap实例
// ServerBootstrap 用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度
ServerBootstrap b = new ServerBootstrap();
// 绑定Reactor线程池
b.group(bossGroup, workerGroup)
// 设置并绑定服务端Channel
// 指定所使用的NIO传输的Channel
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new HttpsServerInitializer());
System.out.println("接口"+port+"准备就绪");
// 绑定端口,同步等待成功
ChannelFuture future = b.bind(port).sync();
// 等待服务端监听端口关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 优雅地关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2.初始化服务器参数
配置jks文件路径,配置jks密钥的密码,配置handler处理类
package best.nettyserver.https;
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
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.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslHandler;
public class HttpsServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline ph = ch.pipeline();
//添加sslhandler
char[] passArray = "999999".toCharArray(); //jks密码
SSLContext sslContext = SSLContext.getInstance("TLSv1");
KeyStore ks = KeyStore.getInstance("JKS");
//加载keytool 生成的文件
FileInputStream inputStream = new FileInputStream("e:/ysstech.jks");
ks.load(inputStream, passArray);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, passArray);
sslContext.init(kmf.getKeyManagers(), null, null);
inputStream.close();
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
ch.pipeline().addLast(new SslHandler(sslEngine));
//处理http服务的关键handler
//一个组合的HttpRequestDecoder和HttpResponseEncoder使得服务器端HTTP实现更容易。
ph.addLast("codec", new HttpServerCodec());
ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));
ph.addLast("handler", new HttpServerHandler());// 服务端逻辑处理类
}
}
3. handler处理类
配置post,get请求方法,参数,还可以根据path判断其路径
package best.nettyserver.https;
import java.net.InetAddress;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
public class HttpServerHandler extends ChannelInboundHandlerAdapter {
private String result = "";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof FullHttpRequest)) {
result = "未知请求!";
send(ctx, result, HttpResponseStatus.BAD_REQUEST);
return;
}
FullHttpRequest httpRequest = (FullHttpRequest) msg;
try {
String path = httpRequest.uri(); //获取路径 uri路径,可以根据 这个判断请求接口
String body = getBody(httpRequest); //获取参数
HttpMethod method = httpRequest.method();//获取请求方法
System.out.println("接收到:" + method + " 请求");
//如果是GET请求
if (HttpMethod.GET.equals(method)) {
//接受到的消息,做业务逻辑处理...
System.out.println("body:" + body);
result = "GET请求";
send(ctx, result, HttpResponseStatus.OK);
return;
}
//如果是POST请求
if (HttpMethod.POST.equals(method)) {
//接受到的消息,做业务逻辑处理...
System.out.println("body:" + body);
result = "POST请求";
send(ctx, result, HttpResponseStatus.OK);
return;
}
} catch (Exception e) {
System.out.println("处理请求失败!");
e.printStackTrace();
} finally {
//释放请求
httpRequest.release();
}
}
/**
* 获取body参数
*/
private String getBody(FullHttpRequest request) {
ByteBuf buf = request.content();
return buf.toString(CharsetUtil.UTF_8);
}
/**
* 发送的返回值
*/
private void send(ChannelHandlerContext ctx, String context, HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
/*
* 建立连接时,返回消息
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
ctx.writeAndFlush("客户端" + InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");
super.channelActive(ctx);
}
}