【问题标题】:Java JNA call will not run native code, causes application to stallJava JNA 调用不会运行本机代码,导致应用程序停止
【发布时间】:2015-08-04 22:47:58
【问题描述】:

我正在使用 JNA (Java Native Access) 将本地方法从 Java 调用到 C。本地方法 (int funcServer(int param1)) 是基本的 unix 套接字侦听。但无论我是优化 JNA Direct Mapping 还是 Interface Mapping,JNA 都会对我不利。本机代码即使在函数调用的第一行也不会打印任何内容,但不会引发异常。

查看我的最小可行 Java 示例(在 NetBeans IDE 产品版本上运行:8.0.2 Build 201411181905 和 Ubuntu Linux):

package viableexamplejava;

import com.sun.jna.*; // link jna-4.1.0.jar, jna-platform-4.1.0.jar

/**
 * Test on Ubuntu Linux or with Cygwin on Windows 7.
 */
public class ViableExample {

    /**
     * This library depends on Unix Sockets.
     */
    public interface NativeLibary extends Library {

        public int funcServer(int param1);
    }
    //uncomment for Indirect Mapping
    //private static final NativeLibary myNativeLibrary_;

    public static native int funcServer(int param1);

    static {
        final String windowsLibraryName = "ViableExample.dll";
        final String linuxLibraryName = "libViableExampleNative.so"; // compiled with Netbeans

        if (Platform.isWindows()) {
            System.err.println("Loading Windows dll. 'cygwin1.dll' should be in same directory.");
            //myNativeLibrary_ = (NativeLibary) Native.loadLibrary(windowsLibraryName, NativeLibary.class);
            Native.register(windowsLibraryName);
        } else {
            System.err.println("Loading Linux .so");
            //myNativeLibrary_ = (NativeLibary) Native.loadLibrary(linuxLibraryName, NativeLibary.class);
            Native.register(linuxLibraryName);
        }
    }

    public static void main(String[] args) {
        System.err.println("Hello World from Java");
        //uncomment for Indirect Mapping
        //myNativeLibrary_.funcServer(7);
        funcServer(7); // This never prints.
    }

}

/**
 * Side notes: If the dynamic library cannot be found, this error occurs:
 *
 * Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load
 * library 'libViableExampleNative.so': Native library
 * (linux-x86-64/libViableExampleNative.so) not found in resource path
 * ([file:/home/user/Desktop/Dropbox/jna-4.1.0.jar,
 * file:/home/user/Desktop/Dropbox/jna-platform-4.1.0.jar,
 * file:/home/user/NetBeansProjects/ViableExampleJava/build/classes/])
 *
 * at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:271) at
 * com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398) at
 * com.sun.jna.Library$Handler.<init>(Library.java:147) at
 * com.sun.jna.Native.loadLibrary(Native.java:412) at
 * com.sun.jna.Native.loadLibrary(Native.java:391) at
 * viableexamplejava.ViableExample.<clinit>(ViableExample.java:29) Java Result:
 * 1
 * 
 * If this happens, you have to put libViableExample.so into the resource path,
 * in my case into:
 * /home/user/NetBeansProjects/ViableExampleJava/build/classes/
 * 
 * Once it's in there, "Hello World from Java" prints, but nothing else gets
 * printed. "myNativeLibrary_.funcServer(7);" doesn't print anything.
 *
 * Output: 
 * Loading Linux .so 
 * Hello World from Java
 * (The application does not terminate or throw an exception).
 */

这是我使用的 C 代码:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

/**
 * Unix server that sends clients the date and time.
 * Compiled with -shared -std=c99. 
 * Produces "libViableExampleNative.so" when built with Netbeans on Linux.
 */
int funcServer(int param1) {
    printf("\n Hello World from C. This is a Socket Server Example Program \n");
    printf("\n param1: %d \n", param1);
    {
        int listenfd = 0, connfd = 0;
        struct sockaddr_in serv_addr;

        char sendBuff[1025];
        time_t ticks;
        // Just verifying that the C code is running.
        printf("I made it to line %d in file %s\n", __LINE__, __FILE__);
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        memset(&serv_addr, '0', sizeof (serv_addr));
        memset(sendBuff, '0', sizeof (sendBuff));

        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_addr.sin_port = htons(5000);

        bind(listenfd, (struct sockaddr*) &serv_addr, sizeof (serv_addr));

        printf("I made it to line %d in file %s\n", __LINE__, __FILE__);
        listen(listenfd, 10);

        while (1) {
            connfd = accept(listenfd, (struct sockaddr*) NULL, NULL);

            ticks = time(NULL);
            snprintf(sendBuff, sizeof (sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, strlen(sendBuff));

            close(connfd);
            sleep(1);
        }
    }
    return 0;
}

更新 1

尝试将 .so 放入 jar 文件,然后从终端运行它(UnsatisfiedLinkError: Unable to load library 'libViableExampleNative.so': Can't gain InputStream for linux-x86-64/libViableExampleNative.so):

$ zip ./ViableExampleJava.jar ./libViableExampleNative.so 
  adding: libViableExampleNative.so (deflated 73%)

~/NetBeansProjects/ViableExampleJava/dist$ java -jar ./ViableExampleJava.jar 
Loading Linux .so

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'libViableExampleNative.so': Can't obtain InputStream for linux-x86-64/libViableExampleNative.so
    at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:271)
    at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398)
    at com.sun.jna.Native.register(Native.java:1396)
    at com.sun.jna.Native.register(Native.java:1156)
    at viableexamplejava.ViableExample.<clinit>(ViableExample.java:33)

* 更新 2 *

尝试设置系统属性“jna.library.path”

从终端(不是 Netbeans)运行时输出正确:

// Set jnaPath to: /home/user/NetBeansProjects/ViableExampleNative/dist/Debug/GNU-Linux-x86

$ java -jar ./ViableExampleJava.jar

Hello World from Java

 Hello World from C. This is a Socket Server Example Program 

 param1: 7 
I made it to line 26 in file ../../Desktop/Dropbox/ViableExample/native/ViableExample.c
I made it to line 37 in file ../../Desktop/Dropbox/ViableExample/native/ViableExample.c

* 更新 3 *

即使它可以在 Ubuntu Linux 终端上运行,我的 Windows 版本(使用 Cygwin)也失败了。

【问题讨论】:

    标签: java java-native-interface native jna


    【解决方案1】:

    尝试在 Netbeans 之外运行它。

    当我在 netbeans 中运行它时,我看到的最后一件事是:

    Loading Linux .so
    Hello World from Java
    

    当我从终端运行时:

    java -jar target/mavenproject5-1.0-SNAPSHOT.jar
    Loading Linux .so
    Hello World from Java
    
     Hello World from C. This is a Socket Server Example Program 
    
     param1: 7 
    I made it to line 27 in file newfile.c
    I made it to line 38 in file newfile.c
    

    该程序似乎仍在 Netbeans 中运行,但未显示 C 打印输出。我可以判断,因为当根本不运行 telnet 时会显示:

    telnet localhost 5000
    Trying 127.0.0.1...
    telnet: Unable to connect to remote host: Connection refused
    

    但是当程序在 Netbeans 中运行时运行 telnet 会产生这样的结果:

    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    Tue Aug  4 19:46:38 2015
    Connection closed by foreign host.
    

    【讨论】:

    • 当您转到菜单栏中的“帮助”>“关于”时,您获得的是什么产品版本?
    • NetBeans IDE 8.0.2(内部版本 201411181905)
    • 相同。此外,从终端运行它会导致“无法加载库 'libViableExampleNative.so':无法获取 linux-x86-64/libViableExampleNative.so 的 InputStream”
    • 没关系。我通过 System.setProperty("jna.library.path", pathToMyLib); 得到了与您相同的结果。您知道这是 Netbeans 错误还是 JNI/JNA 错误?
    • 不是真的,我发现这个链接表明有一个基于 JNA 的替代终端,但我不知道如何启用它。 wiki.netbeans.org/TerminalEmulator
    猜你喜欢
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多