java - JNI 包装器的多个实例

标签 java java-native-interface instance

我有一个Modbus类

public class Modbus {
  // init TCP
  public native void init(String ip, int port, int id);
  public native short[] read_registers(int slaveid, int addr, int len);

如果我执行read_registers,init方法中的id将被打印到标准输出

如果我愿意

Modbus mb1 = new Modbus("192.168.0.250", 502, 1);
Modbus mb2 = new Modbus("192.168.0.250", 502, 2);

然后

mb1.read_registers(....);
mb2.read_registers(....);

在这两种情况下,它都会将 2 打印到标准输出。所以看来第二个实例覆盖了第一个实例。如何使用 jni-wrapper 的多个实例?

编辑:

这里是我使用的 C 代码,我的目标是使用与 samre 或不同 modbus 设备的多个连接

#include "eu_company_lib_comm_modbus_Modbus.h"
#include <modbus/modbus-rtu.h>
#include <modbus/modbus.h>
#include <errno.h>
modbus_t *mb;
int readError;
int writeError;
int errnr;
const char* errStr;
int c_id;
JNIEXPORT void JNICALL 
Java_eu_company_lib_comm_modbus_Modbus_init__Ljava_lang_String_2I(
    JNIEnv * env, jobject obj, jstring ip, jint port, jint id) {

const char* c_ip = (*env)->GetStringUTFChars(env, ip, 0);
mb = modbus_new_tcp(c_ip, port);
c_id=id;
if (mb == NULL) {
    fprintf(stderr, "Unable to allocate libmodbus context\n");
    fflush(stderr);
    return;
}
modbus_set_debug(mb, 1);

if (modbus_connect(mb) == -1) {
    fprintf(stderr, "Connection failed: %s\n",     modbus_strerror(errno));
    fflush(stderr);
    modbus_free(mb);
    return;
}

(*env)->ReleaseStringUTFChars(env, ip, c_ip);
}
JNIEXPORT jshortArray JNICALL Java_eu_company_lib_comm_modbus_Modbus_read_1registers(
    JNIEnv * env, jobject obj, jint slave_id, jint address, jint len) {

jshortArray result = (*env)->NewShortArray(env, len);
uint16_t tab_reg[len];
printf("%d\n",c_id);
fflush(stdout);
readError = modbus_read_registers(mb, address, len, tab_reg);

errnr = errno;
errStr = modbus_strerror(errno);

(*env)->SetShortArrayRegion(env, result, 0, len, tab_reg);

return result;
}

最佳答案

您的主要问题是在 JNI 部分中您正在使用全局变量。全局变量。因此,这些变量与 Modbus 实例没有任何关系。

从我的角度来看,您应该将尽可能多的代码从 JNI 移至 ModBus 的 Java 实现中,并使用本地字段来存储 Java JNI 级别上所需的所有持久值:

公共(public)类 Modbus {

private final String ip;
private final int port;
private final int id;

public ModBus(String ip, int port, ind id) {
     this.ip = ip;
     this.port = port;
     this.id = id;
}    

// init TCP
public native void init(String ip, int port, int id);
public native short[] read_registers(int slaveid, int addr, int len);

}

在 JNI 端,您可以使用 JNI 方法 GetObjectClass(..)GetFieldID(..) 访问所有 J​​ava 字段以检索值GetObjectField(..).

搜索 SO 示例,您会发现很多 C 和 C++ 示例。

或者,您可以将 native 方法设置为私有(private),并添加一个包装方法,该方法在每次调用时将所需的值传递给 JNI 部分:

public void init() {
    init(ip, port, id);
}

private native void init(String ip, int port, int id);

关于java - JNI 包装器的多个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38633147/

相关文章:

javascript - 方法可以返回一个新对象吗?

java - 反射 API 不返回带注释的类

java - 当 Bson 过滤器通过时,Mongo 函数 updatemany() 不起作用

java - Hibernate EJB 架构 - 模型 ClassNotFoundException

java - Android、JNI在C++中调用java构造函数

java - 最好的选择。在 Java 应用程序中使用 .Net Dll

java - 使用java获取其他程序的 Activity 窗口

java - 如何使用 JUnit 在 Spring 中获取数据库连接?

java - Java 中的实例

azure - 部署到云时,未将对象引用设置为对象实例错误