netty +html5 实现 wss 配置 ssl 各类踩坑经验记录,最后有测试ok的套解决方案V2几套解决方案

1,681 阅读9分钟

目录

介绍

修改本地该hosts 文件 

地址截图

修改截图

提示

先看各类bug就不介绍bug啥意思了,一艘好多介绍的

一套ok好方案

介绍

初始化类加上这个

主要就这段代码

截图效果

初始化类型全代码

创建 SslUtil类

页面code

主要是这个

搭建详细框架看我这片博客

持续更新

在上一套写法方案,将 SslContext 创建的时候只创建一次,省去每次调用每次创建

启动类型

初始化类型



介绍

本地开发用localhost 127.0.0.1 和ws 的方法即可

切换到服务端就要调整了,或本地其他人访问也要调整

域内换可以修改window下的hosts文件  加个  127.0.0.1  域名    或 对方域内ip  域名 

去各类云服务器申请域名和ssl  域内开发可以先设置hosts文件 不是域内直接配置服务器即可

最近把项目挂出去,和其他前端使用 所以要调整,从127 改成 域名,让外部也可访问,改种发现一车bug 有需要的可以看看

 

修改本地该hosts 文件 

系统盘:C:\Windows\System32\drivers\etc\hosts

地址截图

修改截图

提示

windows 很多,没这么多东西 都是空的,直接在下边加

127.0.0.1  自定义域名

或其他ip  自定义域名即可 

 

 

 

先看各类bug就不介绍bug啥意思了,一艘好多介绍的

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown

 

netty URL“wss//192.168.8.109:9999/ws”无效。

 

test.html:39 WebSocket connection to 'wss://ma.yueduixiang.com:9999/ws' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED

 

15:45:17.585 [nioEventLoopGroup-3-1] WARN io.netty.channel.ChannelInitializer - Failed to initialize a channel. Closing: [id: 0x04cb96ee, L:/127.0.0.1:9999 - R:/127.0.0.1:56833]
java.io.IOException: Keystore was tampered with, or password was incorrect
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:780)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56)
at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)
at java.security.KeyStore.load(KeyStore.java:1445)
at com.superman.nettyim.SslUtil.createSSLContext(SslUtil.java:35)
at com.superman.nettyim.IMNettyServerInitialzer.initChannel(IMNettyServerInitialzer.java:44)
at com.superman.nettyim.IMNettyServerInitialzer.initChannel(IMNettyServerInitialzer.java:1)
at io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:115)
at io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:107)
at io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:637)
at io.netty.channel.DefaultChannelPipeline.access$000(DefaultChannelPipeline.java:46)
at io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1487)
at io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1161)
at io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:686)
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:514)
at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:427)
at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:474)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:909)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.security.UnrecoverableKeyException: Password verification failed
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:778)
... 23 common frames omitted
15:45:17.602 [nioEventLoopGroup-3-2] WARN io.netty.channel.ChannelInitializer - Failed to initialize a channel. Closing: [id: 0x81b2235f, L:/127.0.0.1:9999 - R:/127.0.0.1:56837]
java.io.IOException: Keystore was tampered with, or password was incorrect
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:780)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56)
at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)
at java.security.KeyStore.load(KeyStore.java:1445)
at com.superman.nettyim.SslUtil.createSSLContext(SslUtil.java:35)
at com.superman.nettyim.IMNettyServerInitialzer.initChannel(IMNettyServerInitialzer.java:44)
at com.superman.nettyim.IMNettyServerInitialzer.initChannel(IMNettyServerInitialzer.java:1)
at io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:115)
at io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:107)
at io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:637)
at io.netty.channel.DefaultChannelPipeline.access$000(DefaultChannelPipeline.java:46)
at io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1487)
at io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1161)
at io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:686)
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:514)
at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:427)
at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:474)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:909)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.security.UnrecoverableKeyException: Password verification failed
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:778)
... 23 common frames omitted

 

 

 

test.html:39 WebSocket connection to 'wss://ma.yueduixiang.com:9999/ws' failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID

 

15:46:33.159 [nioEventLoopGroup-3-1] WARN io.netty.channel.DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:472)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:656)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:591)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:508)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:470)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:909)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634)
at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800)
at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1083)
at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907)
at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
at io.netty.handler.ssl.SslHandler$SslEngineType$3.unwrap(SslHandler.java:295)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1301)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1203)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1247)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:441)
... 16 common frames omitted
15:46:33.160 [nioEventLoopGroup-3-1] WARN io.netty.channel.DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:472)
at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:405)
at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:372)
at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:355)
at io.netty.handler.ssl.SslHandler.channelInactive(SslHandler.java:1054)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:224)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1429)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231)
at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:947)
at io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:826)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:474)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:909)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634)
at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800)
at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1083)
at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907)
at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
at io.netty.handler.ssl.SslHandler$SslEngineType$3.unwrap(SslHandler.java:295)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1301)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1203)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1247)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:441)
... 18 common frames omitted
客户端断开,channle对应的长id为:005056fffec00001-00003328-00000001-371e6fb621ac9d11-9b925be2
客户端断开,channle对应的短id为:9b925be2

 

 

 

 

一套ok好方案

介绍

/**
 * 初始化类
 * netty 配置ssl 踩坑记录  最安全的一套方案  ,页面 访问后台,要用
 * 1.页面 wss://(阿里云或腾讯云申请的ssl 域名地址 )/port/ws
 * 2.服务端,配置域名使用申请下来的ssl 的jks  配置到 初始化类里 
 * 3.启动即可
 * 4如果不安上边方法,很多种时候会出现 域名不正确,或不让连接,域名密码异常jks 和域名不匹配等一系列杂乱问题,
 * 5.所以使用上边这套方案就好了
 * 6.如果想,不要每次初始化类,可以吧初始化sslcontext 放出来,不要每次调用即可 
 * 7.ok
 * 
 * @author jianghy
 *
 * @version 1.0
 */

 

初始化类加上这个

主要就这段代码

	String jksPath = (System.getProperty("user.dir")+ "/target/classes/ssl/test/ma.yueduixiang.com.jks");
        SSLContext sslContext = SslUtil.createSSLContext("JKS",jksPath,"ma.yueduixiang.com");
        SSLEngine sslEngine = sslContext.createSSLEngine();
        sslEngine.setNeedClientAuth(false);
        sslEngine.setUseClientMode(false);
        pipeline.addLast("sslHandler", new SslHandler(sslEngine));

 

截图效果

 

初始化类型全代码

package com.superman.nettyim;

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.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

/**
 * 初始化类
 * netty 配置ssl 踩坑记录  最安全的一套方案  ,页面 访问后台,要用
 * 1.页面 wss://(阿里云或腾讯云申请的ssl 域名地址 )/port/ws
 * 2.服务端,配置域名使用申请下来的ssl 的jks  配置到 初始化类里 
 * 3.启动即可
 * 4如果不安上边方法,很多种时候会出现 域名不正确,或不让连接,域名密码异常jks 和域名不匹配等一系列杂乱问题,
 * 5.所以使用上边这套方案就好了
 * 6.如果想,不要每次初始化类,可以吧初始化sslcontext 放出来,不要每次调用即可 
 * 7.ok
 * 
 * @author jianghy
 *
 * @version 1.0
 */
public class IMNettyServerInitialzer extends ChannelInitializer<SocketChannel> {

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();

		String jksPath = (System.getProperty("user.dir")+ "/target/classes/ssl/test/ma.yuedxuixiang.com.jks");
        SSLContext sslContext = SslUtil.createSSLContext("JKS",jksPath,"ma.yueduixxiangozm");
        SSLEngine sslEngine = sslContext.createSSLEngine();
        sslEngine.setNeedClientAuth(false);
        sslEngine.setUseClientMode(false);
        pipeline.addLast("sslHandler", new SslHandler(sslEngine));
        
 
        ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));    
   
		// websocket 基于http协议,所以要有http编解码器
		pipeline.addLast(new HttpServerCodec());
//		// 对写大数据流的支持 
		pipeline.addLast(new ChunkedWriteHandler());
//		// 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
//		// 几乎在netty中的编程,都会使用到此hanler
		pipeline.addLast(new HttpObjectAggregator(1024*64));
		
		// ====================== 以上是用于支持http协议    ======================
		
		// ====================== 以下是支持httpWebsocket ======================
		
		/**
		 * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
		 * 本handler会帮你处理一些繁重的复杂的事
		 * 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳
		 * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同
		 */
		  pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
	        pipeline.addLast(new StringDecoder());
	        pipeline.addLast(new StringEncoder());
		
		pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
		 
		
		// 自定义的handler
		pipeline.addLast(new IMNettyHandler());
	}

}

 

创建 SslUtil类

package com.superman.nettyim;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
/**
 * 创建ssl 上下文
 *
 * @author jianghy
 *
 * @version 1.0
 */
public class SslUtil {

    private static volatile SSLContext sslContext = null;
    /**
     * 创建 
     * @param type 类型(JKS)
     * @param path JKS文件路径
     * @param password  jks 密码
     * @return
     * @throws Exception
     */
    public static SSLContext createSSLContext(String type ,String path ,String password) throws Exception {
        if(null == sslContext){
            synchronized (SslUtil.class) {
                if(null == sslContext){
                    // 支持JKS、PKCS12(我们项目中用的是阿里云免费申请的证书,下载tomcat解压后的pfx文件,对应PKCS12)
                    KeyStore ks = KeyStore.getInstance(type);
                    // 证书存放地址
                    InputStream ksInputStream = new FileInputStream(path);
                    ks.load(ksInputStream, password.toCharArray());
                    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                    kmf.init(ks, password.toCharArray());
                    sslContext = SSLContext.getInstance("TLS");
                    sslContext.init(kmf.getKeyManagers(), null, null);
                }
            }
        }
        return sslContext;
    }
}

 

页面code

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title></title>
</head>

<body>

    <h3>在线客服</h3>
    <p>
        发送人id: <input type="text" id="msg0" value="1001"/><br />
        发送人token:<input type="text" id="msg1" value="101"/><br />
        收信人类型:<input type="text" id="msg2" value="1" /><br />
        收信人id:<input type="text" id="msg3" value="1002"/><br />
        信息:<input type="text" id="msg4" value="好帅"/><br />

        <input type="button" value="点我发送" onclick="CHAT.chat()" />
    </p>

    <div>消息:</div>

    <div id="receiveMsg" style="background-color: gainsboro;"></div>

    <script type="application/javascript">

        window.CHAT = {
            socket: null,
            init: function () {
                if (window.WebSocket) {
                   
                     var socketAddress = "wss://ma.yueduixiang.com:9999/ws";
                    
                    CHAT.socket = new WebSocket(socketAddress);
                    CHAT.socket.onopen = function () {
                        console.log("连接建立成功...");
                    },
                        CHAT.socket.onclose = function () {
                            console.log("连接关闭...");
                        },
                        CHAT.socket.onerror = function () {
                            console.log("发生错误...");
                        },
                        CHAT.socket.onmessage = function (e) {
                            console.log("接受到消息:" + e.data);
                            var receiveMsg = document.getElementById("receiveMsg");
                            var html = receiveMsg.innerHTML;
                            receiveMsg.innerHTML = html + "<br/>" + "接受到消息:" + e.data;
                        }
                } else {
                    alert("浏览器不支持websocket协议...");
                }
            },
            chat: function () {
                var msg0 = document.getElementById("msg0").value;
                var msg1 = document.getElementById("msg1").value;
                var msg2 = document.getElementById("msg2").value;
                var msg3 = document.getElementById("msg3").value;
                var msg4 = document.getElementById("msg4").value;
                CHAT.socket.send(msg0 + "," + msg1 + "," + msg2 + "," + msg3 + "," + msg4);

                var receiveMsg = document.getElementById("receiveMsg");
                var html = receiveMsg.innerHTML;
                receiveMsg.innerHTML = html + "<br/>" + "发送消息:" + msg4;

            }
        };

        CHAT.init();

    </script>
</body>

</html>

主要是这个

var socketAddress = "wss://ma.yueduixiang.com:9999/ws";

 

申请ssl 

搭建详细框架看我这片博客

除了 ssluitl 没有和 初始化类加了几行代码,还有页面修改了ws 改成 wss://域名:port/ws  剩下都一样

yushen.blog.csdn.net/article/det…

 

 

ok

 

 

持续更新

 

在上一套写法方案,将 SslContext 创建的时候只创建一次,省去每次调用每次创建

启动类型

package com.superman.nettyim;

import javax.net.ssl.SSLContext;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * 及时通讯服务端
 *
 * @author jianghy
 *
 * @version 1.0
 */
public class IMNettyServer {
	private int port = 8088;

	public IMNettyServer(int port) {
		this.port = port;
	}

	public void run() throws Exception {
		String jksPath = (System.getProperty("user.dir")+ "/target/classes/ssl/test/ma.yuedasuixisaang.com.jks");
	    SSLContext sslContext = SslUtil.createSSLContext("JKS",jksPath,"ma.yasueduixasiang.com");
	    
		EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		System.out.println("-----------------  netty Server Start--------------------");
		try {
			ServerBootstrap b = new ServerBootstrap(); // (2)
			b.group(bossGroup, workerGroup)
			//在这里,我们指定使用NioServerSocketChannel用于实例化新的类Channel以接受传入的连接。
					.channel(NioServerSocketChannel.class) // (3)
						.childHandler(new IMNettyServerInitialzer(sslContext))
						.option(ChannelOption.SO_BACKLOG, 128) // (5)
				.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

			ChannelFuture f = b.bind(port).sync(); // (7)
			System.out.println("-------------------netty server port:"+port+" start success -----------");
			// 等待服务器套接字关闭。
			//在本例中,这种情况不会发生,但您可以这样做
			//优雅地
			//关闭服务器。
			f.channel().closeFuture().sync();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}

	public static void main(String[] args) throws Exception {
		new IMNettyServer(9999).run();
	}

}

 

初始化类型

package com.superman.nettyim;

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.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

/**
 * 初始化类
 * netty 配置ssl 踩坑记录  最安全的一套方案  ,页面 访问后台,要用
 * 1.页面 wss://(阿里云或腾讯云申请的ssl 域名地址 )/port/ws
 * 2.服务端,配置域名使用申请下来的ssl 的jks  配置到 初始化类里 
 * 3.启动即可
 * 4如果不安上边方法,很多种时候会出现 域名不正确,或不让连接,域名密码异常jks 和域名不匹配等一系列杂乱问题,
 * 5.所以使用上边这套方案就好了
 * 6.如果想,不要每次初始化类,可以吧初始化sslcontext 放出来,不要每次调用即可 
 * 7.ok
 * 
 * @author jianghy
 *
 * @version 1.0
 */
public class IMNettyServerInitialzer extends ChannelInitializer<SocketChannel> {
	private SSLContext sslContext;
	public IMNettyServerInitialzer(SSLContext sslContext){
		this.sslContext = sslContext;
	}
	
	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
//		String jksPath = (System.getProperty("user.dir")+ "/target/classes/ssl/test/ma.yudedzuixiang.com.jks");
//        SSLContext sslContext = SslUtil.createSSLContext("JKS",jksPath,"ma.yuedauisxiang.com");
        SSLEngine sslEngine = sslContext.createSSLEngine();
        sslEngine.setNeedClientAuth(false);
        sslEngine.setUseClientMode(false);
        pipeline.addLast("sslHandler", new SslHandler(sslEngine));
        
 
        ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));    
   
		// websocket 基于http协议,所以要有http编解码器
		pipeline.addLast(new HttpServerCodec());
//		// 对写大数据流的支持 
		pipeline.addLast(new ChunkedWriteHandler());
//		// 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
//		// 几乎在netty中的编程,都会使用到此hanler
		pipeline.addLast(new HttpObjectAggregator(1024*64));
		
		// ====================== 以上是用于支持http协议    ======================
		
		// ====================== 以下是支持httpWebsocket ======================
		
		/**
		 * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
		 * 本handler会帮你处理一些繁重的复杂的事
		 * 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳
		 * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同
		 */
		  pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
	        pipeline.addLast(new StringDecoder());
	        pipeline.addLast(new StringEncoder());
		
		pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
		 
		
		// 自定义的handler
		pipeline.addLast(new IMNettyHandler());
	}

}

 

ok  

 

 

 

持续更新