Netty(UDP)SSLException:在handskake,close channel期间收到close_notify

时间:2015-08-11 10:54:39

标签: ssl udp netty

我想用SSL编写UDP Netty Server / Client。我这样做的方式类似于TCP Netty Server / Client,效果很好。但我遇到了一个例外:

javax.net.ssl.SSLException:Received close_notify during handskake,close channel...

我的netty是3.x,SSL配置运行良好。这是我的Udp服务器和客户端的一些代码。服务器:

serverBootstrap = new ConnectionlessBootstrap(
            new NioDatagramChannelFactory(Executors.newCachedThreadPool(),maxThreads));
serverBootstrap.setOption("receiveBufferSizePredictorFactory",
            new FixedReceiveBufferSizePredictorFactory(8192));
 ChannelPipelineFactory fac = null;
 try {

        ServiceDecoder serviceProcessor = (ServiceDecoder)Class.forName(serviceDecoderName).newInstance();

        Class<? extends ChannelPipelineFactory> clazz = (Class<? extends ChannelPipelineFactory>) Class
                .forName(msgFactoryName);

        Constructor ctor = clazz.getConstructor(ChannelProcessor.class,
                ChannelGroup.class, CounterGroup.class, CounterGroupExt.class, String.class,ServiceDecoder.class,
                String.class, Integer.class, String.class, String.class, Boolean.class,Integer.class,Boolean.class,Boolean.class,Context.class);

        logger.info("Using channel processor:{}", getChannelProcessor().getClass().getName());
        fac = (ChannelPipelineFactory) ctor.newInstance(
                getChannelProcessor(), allChannels, counterGroup, counterGroupExt, "udp", serviceProcessor,
                messageHandlerName, maxMsgLength, topic, attr, filterEmptyMsg, maxConnections, isCompressed,enableSsl,context);
    } catch (Exception e) {
        logger.error(
                "Simple Udp Source start error, fail to construct ChannelPipelineFactory with name {}, ex {}",
                msgFactoryName, e);
        stop();
        throw new FlumeException(e.getMessage());
    }

    serverBootstrap.setPipelineFactory(fac);

    try {
        if (host == null) {
            nettyChannel = serverBootstrap
                    .bind(new InetSocketAddress(port));
        } else {
            nettyChannel = serverBootstrap.bind(new InetSocketAddress(host,
                    port));
        }

服务器中的管道:

 if(enableSsl) {
        cp.addLast("ssl", sslInit());
    }
if (processor != null) {

        try {
            Class<? extends SimpleChannelHandler> clazz = (Class<? extends SimpleChannelHandler>) Class
                    .forName(messageHandlerName);

            Constructor<?> ctor = clazz.getConstructor(
                    ChannelProcessor.class, ServiceDecoder.class, ChannelGroup.class,
                    CounterGroup.class, CounterGroupExt.class, String.class, String.class,
                    Boolean.class, Integer.class, Integer.class, Boolean.class);

            SimpleChannelHandler messageHandler = (SimpleChannelHandler) ctor
                    .newInstance(processor, serviceProcessor, allChannels,
                            counterGroup, counterGroupExt, topic, attr,
                            filterEmptyMsg, maxMsgLength, maxConnections, isCompressed);

            cp.addLast("messageHandler", messageHandler);

        } catch (Exception e) {
            e.printStackTrace();
        }
 }
       if (this.protocolType.equalsIgnoreCase(ConfigConstants.UDP_PROTOCOL)) {
            cp.addLast("execution", executionHandler);
        }

客户端:

private ConnectionlessBootstrap clientBootstrap;
    clientBootstrap = new ConnectionlessBootstrap(
            new NioDatagramChannelFactory(Executors.newCachedThreadPool()));
    clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        @Override
        public ChannelPipeline getPipeline() throws Exception {
            ChannelPipeline pipeline = Channels.pipeline();

            pipeline.addLast("sslHandler", sslInit());
            pipeline.addLast("orderHandler",new ExecutionHandler(
                    new OrderedMemoryAwareThreadPoolExecutor(cores * 2,
                            1024 * 1024, 1024 * 1024)));
            return pipeline;
        }
    });

两个在客户端发送消息的功能:

public void sendMessage(byte[] data) {
    ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(data);
    sendMessage(buffer);
}

public void sendMessage(ChannelBuffer buffer) {
    Random random = new Random();
    Channel channel = channelList.get(random.nextInt(channelList.size()));
    if(!channel.isConnected()){
        channel.close();
        ChannelFuture cf = clientBootstrap
                .connect(new InetSocketAddress(ip, port));
        if(cf.awaitUninterruptibly(3000, TimeUnit.MILLISECONDS)){
            channel = cf.getChannel();
        }else {
            channelList.remove(channel);
            return;
        }
    }
    ChannelFuture future = channel.write(buffer);
    if(!future.awaitUninterruptibly(3, TimeUnit.SECONDS)){
        logger.warn("send failed!{}",future.getCause());
    }else {
        sendCnt.incrementAndGet();
    }
}

我怀疑UDP Netty Server / Client是否支持SSL。任何提示都表示赞赏。

1 个答案:

答案 0 :(得分:0)

UDP不保证数据包的顺序,而不是TCP,因为没有会话。因此,在SSL协商期间,可能存在问题,具体取决于UDP数据包的顺序。

根据我读到的内容,您可能会看一下DTLS,它假设在UDP数据包中添加一种顺序控制,但很多SSL库都不支持它。

由于Netty仅实现TLS,因此它可能不适用于UDP。