【问题标题】:Error with jni (java6) and X25 native code (C language) when code uses system call "connect()" on Solaris 5.9当代码在 Solaris 5.9 上使用系统调用“connect()”时,jni (java6) 和 X25 本机代码(C 语言)出错
【发布时间】:2012-04-10 01:45:32
【问题描述】:

在过去几年中,我们创建了一个使用 X25 协议的程序。它是用 C 语言制作的,适用于装有 Solaris 5.9 的 Sun-Fire 机器。 最近,我们正在同一台机器上使用 java 6,我们正在尝试调整 C 中的旧程序以通过 jni 使用 java。 所以我对旧的C程序做了一些修改,并创建了一个名为x25lib.so的共享库

但是我在使用 jni 和 X25 时发现了一个运行时问题:当通过 jni 从 java 调用 C 函数时,C 代码的工作方式与从另一个 C 程序调用时不同。

具体来说,使用jni,共享库中的C代码可以正常工作,直到调用系统调用connect(),然后返回-1,

但是从另一个 C 程序调用我的共享库的相同 C 代码返回 0(ok)

在这两种情况下,共享库中的 C 代码都没有接收外部参数,所以条件是一样的,我不明白从 java 加载我的“x25lib.so”共享库是否有一点不同会导致@ C 中的 987654323@ 失败。

使用 java 中的“truss”命令我发现了错误:

/2: connect(5, 0xFD878B75, 112, 1)          Err#22 EINVAL

相同,但从另一个 C 程序调用共享库:

connect(4, 0xFFBFE794, 114, 1)          = 0

所以它只适用于纯 C,

在 solaris 5.9 中使用 jni 和 X25 是否还有其他注意事项?

重要提示:共享库中的 C 代码在两种情况下都是相同的。

编译时间:

一个。创建x25lib.so

    cc  -w -fd -G -Kpic subs.o -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib -lsockx25
        -lsocket -lnsl -I"/SDK/jdk/include/" -I"/SDK/jdk/include/solaris/"
        -o x25lib.so -h x25lib.so x25jni.c

b.使用该共享库创建测试 C 程序:

    cc -w x25lib.so -o x25test x25test.c

where `x25test.c` contains:


    #include <stdio.h>
    main()
    {
        java_x25();
    }

c。使用java:

public class X25 {

        static {
           System.load("/home/x25lib.so");
        }
    public native void ejecutaComando();
}

public class TestX25 {

    public static void main(String ... args) {
    X25 x25 = new X25();

    x25.ejecutaComando();
    }

}

然后在C代码共享库中:

/*
 * Class:     X25
 * Method:    ejecutaComando
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_X25_ejecutaComando
  (JNIEnv *env, jobject obj)
{

        java_x25();

}

所以最后两个程序(java y C)在共享库中调用完全相同的 C 代码:

java_x25()
没有参数,所以执行相同的代码。

为什么从 C 调用时运行良好,从 java 调用时失败?

感谢您的建议。

【问题讨论】:

  • 您确定您的独立“C”代码与您的 JNI 代码相同吗?
  • 感谢您的回答 EJP。是的,代码是相同的,这是我的挫败感。我编辑了我的问题并添加了 jni 代码,您可以看到它被调用的代码与独立 C 代码中的代码相同。

标签: java java-native-interface solaris


【解决方案1】:

感谢您的 cmets。我在尝试另一种方法时找到了一个解决方案:我决定不使用 jni,而是调整了旧的 C 程序以侦听来自 java 的简单 tcp 连接,然后可以执行 x25 代码,但令人惊讶的是,我得到了相同的运行时错误,例如使用 jni:

connect(5, 0xFD8789C5, 112, 1)          Err#22 EINVAL

包括 112 而不是 114 的大小,这是同样的问题。

所以我注意到问题在于我在 "-lsockx25" 之前使用 "-lsocket" 选项编译了新的 C 程序,所以这是一个线索。然后我在google上搜索,发现了类似的问题:

link to java X25 Bug ID:4077576

在那篇文章的最后,提到了选项 LD_PRELOAD 强制首先加载 sockx25 库。最后解决方案是在运行时:

bash$ export LD_PRELOAD=/opt/SUNWconn/lib/libsockx25.so

bash$ java TestX25

然后使用 jni 一切正常。

LD_PRELOAD 参考:link to java tuning

【讨论】:

    【解决方案2】:

    一些观察(如果您希望我们更深入地了解这一点,请发布您的代码 - 特别是设置参数为 connect() 的部分):

    假设 X.25 over TCP(?):

    1. 从手册页中,EINVALconnect(3socket) 返回“namelen 不是指定地址族的有效地址的大小”,其中 namelen 是在 &lt;sys/socket_impl.h&gt; 中定义的 sockaddr 结构. namelen 通常为 16(一个 2 字节地址系列(我希望 SOCK_STREAM),后跟 14 个八位字节的地址数据)。您的程序返回 namelen 112 或 114。

    2. 0xFD878B75 上方的失败truss(1) 输出中name 的地址是奇数(奇数在“非偶数”的意义上)。鉴于 Solaris 的典型对齐要求,这似乎很奇怪。 (SPARC 或 x86?什么编译器和标志?)。也许是指针或 sizeof 问题?

    3. 从您的truss(1) 输出可以看出,线程正在java 调用中使用。您的库是线程安全的吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-11
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多