5

在过去的几年中,我们创建了一个使用 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(确定)

在这两种情况下,共享库中的 C 代码都没有接收外部参数,因此条件相同,我不明白从 java 加载我的“x25lib.so”共享库是否有一点差异,导致connect()C 失败。

使用 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

湾。使用该共享库创建测试 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调用时失败?

感谢您的任何建议。

4

2 回答 2

1

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

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

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

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

链接到 java X25 错误 ID:4077576

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

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

bash$ java TestX25

然后使用 jni 一切正常。

LD_PRELOAD 参考:指向 java 调优的链接

于 2012-04-11T21:50:51.340 回答
0

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

假设X.25 over TCP(?):

  1. 从手册页EINVAL返回connect(3socket)“namelen 不是指定地址族的有效地址的大小”,其中定义namelensockaddr结构是<sys/socket_impl.h>. namelen通常是 16(一个 2 字节的地址系列(我期望SOCK_STREAM),后跟 14 个八位字节的地址数据)。您的程序返回namelen112 或 114。

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

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

于 2012-04-10T15:36:27.440 回答