【问题标题】:Netty ExceptionInInitializerErrorNetty ExceptionInInitializerError
【发布时间】:2019-03-08 07:49:19
【问题描述】:

我正在从事一个物联网项目,并试图理清学习曲线和奇怪的方法。我是一名 .Net 程序员,似乎首选库是基于 Java 的 Netty。我们的客户已经在研究将其放置在他们的设备上,并坚持使用 HTTP 而不是 MQTT,因为他们不希望防火墙配置成为正常因素。

所以,我首先要告诉你的是,我第一次尝试使用 DotNetty 作为客户和代理,但我无法确定图书馆的正面或反面,因为它没有文档而且我无法绑定我在对象资源管理器中看到的对象与我在 Netty 文档中看到的对象。然后我突然想到,也许我可以做一些我在 Xamarin 中看到的事情,在那里我清楚地从 C# 代码访问 Java 库。这导致我使用 LKVM,它允许我将 Netty jar 文件转换为 DLL 文件。

因此,当我使用 Visual Studio 和 C# 时,我现在能够遵循 Netty 教程和文档,这让我取得了相当大的进步。

我编写了一个小控制台应用程序,它应该像一个带有 Netty 客户端的物联网设备一样运行。我使用我生成的 DLL 来编写客户端。我在尝试连接时遇到错误,并假设由于我没有代理,它只是没有找到端点。所以今天我写了服务器代码。完成后,我尝试再次连接设备并得到相同的错误。

然后我启动了 Fiddler,这样我就可以检查流量并发现没有流量。所以错误发生在任何尝试连接之前。

所以,在我继续之前,这是客户端代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JSON = Newtonsoft.Json.JsonConvert;
using io.netty.util;
using io.netty.bootstrap;
using io.netty.buffer;
using io.netty.channel;
using io.netty.channel.nio;
using io.netty.channel.socket;
using io.netty.channel.socket.nio;
using io.netty.handler.codec.http;
using io.netty.handler.codec.http.websocketx;
using io.netty.handler.codec.http.websocketx.extensions.compression;
using io.netty.handler.ssl;
using io.netty.handler.ssl.util;
using java.io;
using java.net;
using io.netty.util.concurrent;

namespace Device
{
    public class WebSocketClient
    {
        public string URL { get; set; }
        public URI Uri = null;
        public Uri netUri = null;
        public string Host;
        public int Port;
        public Channel Channel;
        public Bootstrap BootStrap = new Bootstrap();
        public WebSocketClientHandler Handler;
        public EventLoopGroup Group = new NioEventLoopGroup();
        public SslContext SslCtx = null;

        public WebSocketClient(string URL)
        {
            this.URL = URL;
            netUri = new Uri(this.URL);
            Uri = new URI(URL);
            Host = netUri.Host;
            Port = netUri.Port;//Unlike the Netty example, .Net knows the ws/wss ports.
            bool SSL = Port == 443;


            if (SSL)
            {
                SslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
            }

            Handler = new WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(Uri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders()));
            //BootStrap.group(Group).channel(new NioSocketChannel().GetType().handler(new ChannelInitializer(Handler, Host, Port, SslCtx))).connect(Host, Port).sync().channel();

        }

        public void Connect()
        {
            //Channel = BootStrap.connect(Host, Port).sync().channel();            
            //Channel = BootStrap.connect().sync().channel();
            //((Bootstrap)BootStrap.group(Group).channel(new NioSocketChannel().GetType()).handler(new ChannelInitializer(Handler, Host, Port, SslCtx))).connect(Host, Port).sync().channel();

            BootStrap = BootStrap.group(Group) as Bootstrap;
            BootStrap = BootStrap.channel(new NioSocketChannel().GetType()) as Bootstrap;
            BootStrap = BootStrap.handler(new ChannelInitializer(Handler, Host, Port, SslCtx)) as Bootstrap;            
            //BootStrap.remoteAddress(Host, Port);
            //BootStrap.localAddress(Host, Port);
            ChannelFuture cf = BootStrap.connect(Host, Port);
            cf = cf.sync();
            Channel = cf.channel();

            Handler.HandshakeFuture().sync();
        }

        public void Close()
        {
            Group.shutdownGracefully();
        }

        public void Ping()
        {
            WebSocketFrame frame = new PingWebSocketFrame(Unpooled.wrappedBuffer(new byte[] { 8, 1, 8, 1 }));
            Channel.writeAndFlush(frame);
        }

        public void Send(string content)
        {
            Channel.writeAndFlush(content);
            Channel.newPromise().addListener(new Listener());
        }

    }

    public class Listener : GenericFutureListener
    {
        public void operationComplete(Future f)
        {
            System.Console.WriteLine(JSON.SerializeObject(f.get()));
        }
    }
}

在构造函数中有一个注释行,模仿了他们的客户端示例中的内容。因为它是链式的,所以很难判断错误来自哪里。所以,我把它移到了我的连接函数中并打破了它。

在连接函数中,以下行是我看到问题的第一个迹象:

ChannelFuture cf = BootStrap.connect(Host, Port);

如果我查看“手表”中的对象,我会发现它似乎已经存在错误。它看起来像这样:

{DefaultChannelPromise@67755d(failure: java.lang.ExceptionInInitializerError)}

但是,它不会在该行出错,而是在以下行:

cf = cf.sync();

堆栈跟踪如下所示:

at io.netty.util.internal.PlatformDependent0.throwException(Exception )
   at io.netty.util.internal.PlatformDependent.throwException(Exception t)
   at io.netty.util.concurrent.DefaultPromise.rethrowIfFailed()
   at io.netty.util.concurrent.DefaultPromise.sync()
   at io.netty.channel.DefaultChannelPromise.sync()
   at io.netty.channel.DefaultChannelPromise.<bridge>sync()
   at io.netty.channel.DefaultChannelPromise.io.netty.channel.ChannelFuture/()Lio.netty.channel.ChannelFuture;sync()
   at Device.WebSocketClient.Connect() in c:\Users\ME\Documents\Visual Studio 2017\Projects\MQTT Sandbox\Device\WebSocketClient.cs:line 70
   at Device.Program.SocketTest() in c:\Users\ME\Documents\Visual Studio 2017\Projects\MQTT Sandbox\Device\Program.cs:line 106
   at Device.Program.Main(String[] args) in c:\Users\ME\Documents\Visual Studio 2017\Projects\MQTT Sandbox\Device\Program.cs:line 72

我唯一的另一个线索是,如果我探索该异常,则该异常有一个子异常(与内部异常相反),它说:“未知指针大小”。该堆栈跟踪如下所示:

我今天花了很大一部分时间修修补补和研究,但我完全没有找到任何关于哪里出了问题的线索。任何帮助将不胜感激。

提前感谢您的帮助!

更新 我能够从 ChannelFuture cf = BootStrap.connect(Host, Port); 中提取更好的堆栈跟踪。

May 29, 2018 8:25:37 AM io.netty.channel.DefaultChannelId defaultProcessId
WARNING: Failed to find the current process ID from ''; using a random value: -251539282
May 29, 2018 8:25:43 AM io.netty.channel.AbstractChannel$AbstractUnsafe register
WARNING: Force-closing a channel whose registration task was not accepted by an event loop: [id: 0x6312b48a]
java.lang.ExceptionInInitializerError
        at io.netty.util.internal.shaded.org.jctools.queues.LinkedArrayQueueUtil.modifiedCalcElementOffset(LinkedArrayQueueUtil.java:24)
        at io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueue.offer(BaseMpscLinkedArrayQueue.java:308)
        at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:330)
        at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:321)
        at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:765)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.register(AbstractChannel.java:479)
        at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:81)
        at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:74)
        at io.netty.channel.MultithreadEventLoopGroup.register(MultithreadEventLoopGroup.java:86)
        at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:333)
        at io.netty.bootstrap.Bootstrap.doResolveAndConnect(Bootstrap.java:163)
        at io.netty.bootstrap.Bootstrap.connect(Bootstrap.java:145)
        at io.netty.bootstrap.Bootstrap.connect(Bootstrap.java:126)
        at cli.Device.WebSocketClient.Connect(WebSocketClient.cs:70)
        at cli.Device.Program.SocketTest(Program.cs:106)
        at cli.Device.Program.Main(Program.cs:72)
Caused by: java.lang.IllegalStateException: Unknown pointer size
 at io.netty.util.internal.shaded.org.jctools.util.UnsafeRefArrayAccess.<clinit>(UnsafeRefArrayAccess.java:51)
        ... 11 more

May 29, 2018 8:25:43 AM io.netty.util.concurrent.DefaultPromise safeExecute
SEVERE: Failed to submit a listener notification task. Event loop shut down?
java.lang.NoClassDefFoundError: Could not initialize class io.netty.util.internal.shaded.org.jctools.util.UnsafeRefArrayAccess
        at io.netty.util.internal.shaded.org.jctools.queues.LinkedArrayQueueUtil.modifiedCalcElementOffset(LinkedArrayQueueUtil.java:24)
        at io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueue.offer(BaseMpscLinkedArrayQueue.java:308)
        at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:330)
        at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:321)
        at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:765)
        at io.netty.util.concurrent.DefaultPromise.safeExecute(DefaultPromise.java:764)
        at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:438)
        at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104)
        at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:84)
        at io.netty.channel.AbstractChannel$CloseFuture.setClosed(AbstractChannel.java:1148)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.register(AbstractChannel.java:491)
        at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:81)
        at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:74)
        at io.netty.channel.MultithreadEventLoopGroup.register(MultithreadEventLoopGroup.java:86)
        at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:333)
        at io.netty.bootstrap.Bootstrap.doResolveAndConnect(Bootstrap.java:163)
        at io.netty.bootstrap.Bootstrap.connect(Bootstrap.java:145)
        at io.netty.bootstrap.Bootstrap.connect(Bootstrap.java:126)
        at cli.Device.WebSocketClient.Connect(WebSocketClient.cs:70)
        at cli.Device.Program.SocketTest(Program.cs:106)
        at cli.Device.Program.Main(Program.cs:72)

【问题讨论】:

  • 我猜这确实与您的日志记录配置有关。尝试查看是否可以以某种方式调整最大行数限制并在能够捕获它后发布完整的堆栈跟踪
  • 我能够逐行复制嵌套异常,并用它的图像更新了我的原始帖子。
  • 嗨@JRodd,几个月后,你有没有得到解决方案?我在尝试用 IKVM 做你正在做的事情时遇到了类似的问题。
  • @SimpleGuy 不幸的是,我最终放弃了 Netty,转而使用 lib 调用 MQTTnet。 nuget.org/packages/MQTTnet
  • 感谢@JRodd,我想这对我没有帮助,因为我正在尝试转换第三方 Java API 并且无法更改源。

标签: netty ikvm


【解决方案1】:

我找到了解决方案并在我的 IKVM 分支中实施了修复。 https://github.com/Draspax/ikvm8

基本上在 io.netty.util.internal.shaded.org.jctools.util.UnsafeRefArrayAccess 类中调用 UnsafeAccess.UNSAFE.arrayIndexScale(Object[].class);它应该返回 4 或 8,并且 IKVM Unsafe 实现不考虑 Object[].class,因此它返回默认值 1。我已添加对象数组作为 arrayIndexScale 返回 4 的选项。

希望这些人能够让 IKVM 保持活力,尽快将其包含在 https://github.com/wwrd/ikvm8 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 2017-11-17
    相关资源
    最近更新 更多