java - native 方法上的 JNI UnsatisfiedLinkError

标签 java c++ c java-native-interface

我正在为 C++ BSD 套接字客户端运行一个基本的 Java 包装器。我可以编译 Java 并生成头文件,但是当我尝试运行它时,它返回 Exception in thread "main"java.lang.UnsatisfiedLinkError: JavaClient.socketComm()V

从我能够找到的内容来看,这似乎表明方法签名之间存在不匹配,但我找不到我的任何问题。

Java代码

public class JavaClient 
{
    public native void socketComm();

    public static void main(String[] args)
    {
        System.load("/home/cougar/workspace/ArbiterBSDSocketComms/JNIClient/JavaClient.so");
        JavaClient client = new JavaClient();
        client.socketComm();

        System.out.println("Done");
    }
}

C实现

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <cstdlib>
#include <stdio.h>
#include <jni.h>
#include "JavaClient.h"
#define MAXHOSTNAME 256

JNIEXPORT void JNICALL Java_JavaClient_socketComm
    (JNIEnv *env, jobject obj) {
    struct sockaddr_in remoteSocketInfo;
    struct hostent *hPtr;
    int socketHandle;
    char *remoteHost="localhost";
    int portNumber = 8080;

memset(&remoteSocketInfo, 0, sizeof(struct sockaddr_in));       //Clear structure memory

if ((hPtr = gethostbyname(remoteHost)) == NULL)             //Get sysinfo
{
    printf("System DNS resolution misconfigured.");
    printf("Error number: ", ECONNREFUSED);
    exit(EXIT_FAILURE);
}

if((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0)        //Create socket
{
    close(socketHandle);
    exit(EXIT_FAILURE);
}

memcpy((char *)&remoteSocketInfo.sin_addr,
        hPtr->h_addr, hPtr->h_length);                          //Load sys info into sock data structures
remoteSocketInfo.sin_family = AF_INET;
remoteSocketInfo.sin_port = htons((u_short)portNumber);         //Set port number

if(connect(socketHandle, (struct sockaddr *)&remoteSocketInfo, sizeof(struct sockaddr_in)) < 0)
{
    close(socketHandle);
    exit(EXIT_FAILURE);
}

int rc=0;
char buf[512];

strcpy(buf, "Sup server");
send(socketHandle, buf, strlen(buf)+1, 0);
}

void main(){}

头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JavaClient */

#ifndef _Included_JavaClient
#define _Included_JavaClient
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JavaClient
 * Method:    socketComm
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JavaClient_socketComm
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

请原谅一些糟糕的格式,我没有经常使用 stackoverflow,代码格式有点粗略。

这些文件都位于/JNIClient 中。

我正在运行 Ubuntu 12.04 x64,并且安装了 32 位和 64 位 JDK。我尝试首先使用 32 位版本生成 .so,这本来是理想的,但我发现 ELF 不匹配,所以我只使用 64 位版本,这样我就不必处理它了。 (也欢迎对此提出任何见解。)

我的流程是:

$>javac JavaClient.java

$>javah JavaClient

$>cc -m64 -g -I/usr/lib/jvm/java-6-openjdk-amd64/include -I/usr/lib/jvm/java-6-openjdk-amd64/include/linux -shared JavaClient.c -o JavaClient.so

$>java JavaClient

完整的错误信息是

Exception in thread "main" java.lang.UnsatisfiedLinkError: JavaClient.socketComm()V
    at JavaClient.socketComm(Native Method)
    at JavaClient.main(JavaClient.java:9)

$>nm JavaClient.so 返回:

cougar@Wanda:~/workspace/ArbiterBSDSocketComms/JNIClient$ nm JavaClient.so
0000000000200e50 a _DYNAMIC
0000000000200fe8 a _GLOBAL_OFFSET_TABLE_
             w _Jv_RegisterClasses
0000000000200e30 d __CTOR_END__
0000000000200e28 d __CTOR_LIST__
0000000000200e40 d __DTOR_END__
0000000000200e38 d __DTOR_LIST__
00000000000005e0 r __FRAME_END__
0000000000200e48 d __JCR_END__
0000000000200e48 d __JCR_LIST__
0000000000201010 A __bss_start
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000000540 t __do_global_ctors_aux
0000000000000490 t __do_global_dtors_aux
0000000000201008 d __dso_handle
                 w __gmon_start__
0000000000201010 A _edata
0000000000201020 A _end
0000000000000578 T _fini
0000000000000438 T _init
0000000000000470 t call_gmon_start
0000000000201010 b completed.6531
0000000000201018 b dtor_idx.6533
0000000000000510 t frame_dummy

编辑:我认为 .so 构建不正确,因为 $>nm JavaClient.so 没有在其中显示方法名称。关于那个 cc 命令有什么问题有什么建议吗?

好的,所以:我一直坚持这个,因为似乎没有什么是对的。方法签名全部匹配,应该没有错,eclipse 文件属性说它正在编辑正确的文件,等等。我终于找到了 JavaClient.c,它是空白的。显然,eclipse 并没有真正编辑它所说的文件。修复了这个问题,现在一切正常。

最佳答案

我会给你一个更好的解决方案。

public void socketComm() throws IOException
{
  Socket socket = new Socket("localhost", 8080);
  try
  {
    socket.getOutputStream().write("Sup server\u0000".getBytes());
  }
  finally
  {
    socket.close(); // You forgot this
  }
}

根本不需要 JNI。如果 socket() 返回 < 0,它也不会关闭无效句柄,这与您的代码不同。

关于java - native 方法上的 JNI UnsatisfiedLinkError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11512203/

相关文章:

c - kbuild 外部模块问题

c - glibc的free()的内部工作原理

java - java中的支付网关集成

java - 读取文件时内联检查整数

java - 在日期对象中添加 5.30 小时

c++ - QFile 复制 - 静态与临时对象

c++ - 可以插入 fstream,但不能插入 iostream

java - 通过 REST API 访问机器学习模型

C++ lambda指针/引用内存占用之争

C 程序意外终止