# Netty Websocket SSL Java 服务端 + Javascript 客户端

📆 2022-1-5 14:12

# SSL 证书

申请完阿里云免费证书 (opens new window)后,下载 Nginx 版证书。

Nginx 证书的 .pem .key 使用 X.509 协议。

.pem 无需转换,但是 .key 需要转换成 pkcs8 协议。

使用 openssl 转换证书命令如下:

openssl pkcs8 -topk8 -inform PEM -in 142857_netty.tun6.com.key -outform PEM -nocrypt -out 142857_netty.tun6.com.key.pkcs8

# Java 实现

# Java 目录结构

- src/main/java
    - com.tun6
        - MyWebsocketService.java
        - MyMainHandler.java
- src/main/resources
    - 142857_netty.tun6.com.key
    - 142857_netty.tun6.com.key.pkcs8
    - 142857_netty.tun6.com.pem

# MyWebsocketService

public class MyWebsocketService {
    private static MyMainHandler mainHandler=new MyMainHandler();

    public static void main(String[] args) {
        try {
            SslContext sslCtx=SslContextBuilder.forServer(
                this.getClass().getResourceAsStream("/142857_netty.tun6.com.pem"), 
                this.getClass().getResourceAsStream("/142857_netty.tun6.com.key.pkcs8")
            ).build();
            
            EventLoopGroup bossGroup=new NioEventLoopGroup(1);
            EventLoopGroup workerGroup=new NioEventLoopGroup(4);
            
            ServerBootstrap bootstrap=new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                .channel(Epoll.isAvailable()?EpollServerSocketChannel.class:NioServerSocketChannel.class)// 尽量使用 Epool
                .childHandler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ChannelPipeline pp=ch.pipeline();
                        
                        pp.addLast(sslCtx.newHandler(ch.alloc()));// 处理 ssl 协议
                        pp.addLast(new HttpServerCodec());// 分解为 http 协议体
                        pp.addLast(new HttpObjectAggregator(65536));// http 协议长度限制器
                        pp.addLast(new WebSocketServerCompressionHandler());// 处理 websocket 握手
                        pp.addLast(new WebSocketServerProtocolHandler("/websocket",null,true));// 处理 websocket 协议
                        
                        pp.addLast(new BinaryWebSocketFrameDecoder2());// BinaryWebSocketFrame ==> ByteBuf
                        pp.addLast(new ProtobufFrameDecoder2());// ByteBuf ==> ProtobufFrame
                        
                        pp.addLast(new BinaryWebSocketFrameEncoder2());// ByteBuf ==> BinaryWebSocketFrame
                        pp.addLast(new ProtobufFrameEncoder2());// ProtobufFrame ==> ByteBuf
                        
                        pp.addLast(mainHandler);
                    }
                });
            
            Channel ch=bootstrap.bind(888).sync().channel();
            ch.closeFuture().sync();
        } catch (Exception e) {
            log.error("socket service start fail",e);
        }
    }
}

# MyMainHandler

public class MyMainHandler extends SimpleChannelInboundHandler<ProtobufFrame> {
    private ChannelGroup channelGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ProtobufFrame msg) throws Exception {
        log.info("channel read {}, {}",ctx,msg);
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("channel active {}",ctx);
        channelGroup.add(ctx.channel());
        
        log.info("channelGroupSize: {}",channelGroup.size());
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("channel inactive {}",ctx);
        channelGroup.remove(ctx.channel());
        
        log.info("channelGroupSize: {}",channelGroup.size());
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("channel {} error",ctx,cause);
    }
}

# JavaScript 实现

const ws=new WebSocket('wss://netty.tun6.com:888/websocket')
ws.onopen=(e)=>{
    console.log('open');

    ws.send(Uint8Array.from([1,4,2,8,5,7]))
}
ws.onclose=(e)=>{
    console.log('close');
}
ws.onmessage=(e)=>{
    console.log('message');
}
ws.onerror=(e)=>{
    console.log('error',e);
}
最后更新于: 1/6/2022, 2:23:16 PM