netty做服务端⽀持ssl协议实现websocket的wss协议(客户端
为浏览器)
也是在⽹上查的资料,整理⼀下相互学习下
第⼀步:⽣成SSL证书:
因为是测试,直接使⽤jdk⾃带的keytool⼯具⽣成⾃签名证书(注:⾃签名证书是不被浏览器认可的,只能⽤于测试),
--打开cmd
--输⼊命令(复制啊):keytool -genkey -keysize 2048 -validity 365 -keyalg RSA -keypass netty123 -storepass netty123 -
keystore wss.jks
第⼆步:在ChannelPipeline添加SslHandler:
⾸先写个⼯具类:SslUtil配置SSLContext
public static SSLContext createSSLContext(String type ,String path ,String password) throws Exception {
KeyStore ks = Instance(type); /// "JKS"
InputStream ksInputStream = new FileInputStream(path); /// 证书存放地址
ks.load(ksInputStream, CharArray());
//KeyManagerFactory充当基于密钥内容源的密钥管理器的⼯⼚。
KeyManagerFactory kmf = DefaultAlgorithm());//getDefaultAlgorithm:获取默认的 KeyManagerFactory      kmf.init(ks, CharArray());
//SSLContext的实例表⽰安全套接字协议的实现,它充当⽤于安全套接字⼯⼚或 SSLEngine 的⼯⼚。
SSLContext sslContext = Instance("TLS");
sslContext.KeyManagers(), null, null);
return sslContext;
}
添加SslHandler(放在第⼀个)
@Override
public void initChannel(SocketChannel ch) throws Exception {
SSLContext sslContext = ateSSLContext("JKS","D://wss.jks","netty123");
//SSLEngine 此类允许使⽤ssl安全套接层协议进⾏安全通信
SSLEngine engine = ateSSLEngine();
engine.setUseClientMode(false);
ch.pipeline().addLast(new SslHandler(engine));
ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
ch.pipeline().addLast("http-codec", new HttpServerCodec());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
ch.pipeline().addLast(new AcceptorIdleStateTrigger());
ch.pipeline().addLast("handler", new WebSocketHandler());
}
JS⽂件的URL:
var url = "wss://localhost:8000/ws";
第三步:运⾏
补充:(因为发现⼀些⼩伙伴不清楚部分类的来源,特此补充)--2021.09.08
⽬录:
AcceptorIdleStateTrigger .java
package comty.wss;
import ioty.channel.ChannelHandler;
import ioty.channel.ChannelHandlerContext;
import ioty.channel.ChannelInboundHandlerAdapter;
import ioty.handler.timeout.IdleState;
import ioty.handler.timeout.IdleStateEvent;
@ChannelHandler.Sharable
public class AcceptorIdleStateTrigger extends ChannelInboundHandlerAdapter {    private int unReceivedCounts=0;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
//有消息时归零
unReceivedCounts=0;
super.channelRead(ctx, msg);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
if (evt instanceof IdleStateEvent) {
//在这⾥并处理业务逻辑
IdleState state = ((IdleStateEvent) evt).state();
if (state == IdleState.READER_IDLE) {
unReceivedCounts++;
System.out.println(unReceivedCounts);
if (unReceivedCounts>10) {
ctx.close();
unReceivedCounts = 0;
}
}
} else {
super.userEventTriggered(ctx, evt);
}
}
}
SslUtil.java
package comty.wss;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import javax.ssl.KeyManagerFactory;
import javax.ssl.SSLContext;
public class SslUtil {
public static SSLContext createSSLContext(String type ,String path ,String password) throws Exception {
KeyStore ks = Instance(type); /// "JKS"
InputStream ksInputStream = new FileInputStream(path); /// 证书存放地址
ks.load(ksInputStream, CharArray());
//KeyManagerFactory充当基于密钥内容源的密钥管理器的⼯⼚。
KeyManagerFactory kmf = DefaultAlgorithm());//getDefaultAlgorithm:获取默认的 KeyManagerFactory      kmf.init(ks, CharArray());
/
/SSLContext的实例表⽰安全套接字协议的实现,它充当⽤于安全套接字⼯⼚或 SSLEngine 的⼯⼚。
SSLContext sslContext = Instance("TLS");
sslContext.KeyManagers(), null, null);
return sslContext;
}
}
WebSocketHandler.java
package comty.wss;
import ioty.buffer.ByteBuf;
import ioty.buffer.Unpooled;
import ioty.channel.ChannelFuture;
import ioty.channel.ChannelFutureListener;
import ioty.channel.ChannelHandlerContext;
import ioty.channel.ChannelInboundHandlerAdapter;
import dec.http.DefaultFullHttpResponse;
import dec.http.FullHttpRequest;
import dec.http.HttpResponseStatus;
import dec.http.HttpVersion;
import dec.http.websocketx.CloseWebSocketFrame;
import dec.http.websocketx.TextWebSocketFrame;
import dec.http.websocketx.WebSocketFrame;
import dec.http.websocketx.WebSocketServerHandshaker;
import dec.http.websocketx.WebSocketServerHandshakerFactory;
import ioty.util.CharsetUtil;
/**
* websocket 具体业务处理⽅法
*
* */
public class WebSocketHandler extends ChannelInboundHandlerAdapter{
private WebSocketServerHandshaker handshaker;
/**
* 当客户端连接成功,返回个成功信息
* */
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
/**
* 当客户端断开连接
* 当客户端断开连接
* */
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
// 传统的HTTP接⼊
if(msg instanceof FullHttpRequest){
handleHttpRequest(ctx,(FullHttpRequest)msg);
}else if(msg instanceof WebSocketFrame){
handlerWebSocketFrame(ctx,(WebSocketFrame)msg);
}
super.channelRead(ctx, msg);
}
public void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception{
//关闭请求
if(frame instanceof CloseWebSocketFrame){
handshaker.close(ctx.channel(), (ain());
return;
}
//只⽀持⽂本格式,不⽀持⼆进制消息
if(!(frame instanceof TextWebSocketFrame)){
throw new Exception("仅⽀持⽂本格式");
}
}
//第⼀次请求是http请求,请求头包括ws的信息
public void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req){
if(!req.decoderResult().isSuccess()){
sendHttpResponse(ctx,req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
return;
}
// 构造握⼿响应返回
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws:/"+ctx.channel()+ "/ws",null,false);    handshaker = wHandshaker(req);
// 请求头不合法, 导致handshaker没创建成功
if(handshaker == null){
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
}else{
handshaker.handshake(ctx.channel(), req);
}
}
public static void sendHttpResponse(ChannelHandlerContext ctx,FullHttpRequest req,DefaultFullHttpResponse res){
/
/ 返回应答给客户端
if (res.status().code() != 200){
ByteBuf buf = piedBuffer(res.status().toString(), CharsetUtil.UTF_8);
}
// 如果是⾮Keep-Alive,关闭连接
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (!isKeepAlive(req) || res.status().code() != 200){
f.addListener(ChannelFutureListener.CLOSE);
}
}
}
private static boolean isKeepAlive(FullHttpRequest req){
return false;
}
//异常处理,netty默认是关闭channel
websocket和socket
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)  throws Exception {
//输出⽇志
cause.printStackTrace();
ctx.close();
}
}
WebsocketServer.java (启动类)
package comty.wss;
import ioty.bootstrap.ServerBootstrap;
import ioty.channel.ChannelFuture;
import ioty.channel.ChannelInitializer;
import ioty.channel.ChannelOption;
import ioty.channel.EventLoopGroup;
import ioty.channel.nio.NioEventLoopGroup;
import ioty.channel.socket.SocketChannel;
import ioty.channel.socket.nio.NioServerSocketChannel;
import dec.http.HttpObjectAggregator;
import dec.http.HttpServerCodec;
import ioty.handler.ssl.SslHandler;
import ioty.handler.stream.ChunkedWriteHandler;
import ioty.handler.timeout.IdleStateHandler;
import urrent.TimeUnit;
import javax.ssl.SSLContext;
import javax.ssl.SSLEngine;
public class WebsocketServer {
public static  WebsocketServer instance;
public static final WebsocketServer getInstance(){
return instance;
}
private int port;
public WebsocketServer(int port) {
if(instance!=null){
return;
}
this.port = port;
try {
this.start();
instance=this;
} catch (Exception e) {
e.printStackTrace();
}
}
private void start() throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。