使用JNA呼叫c/c++的so動態庫函式
最近專案收到個需求,需要呼叫c寫的函式,給的是so檔案,查閱了資料,so檔案為linux下的動態庫函式檔案,windos下為dll檔案。傳統方案用JNI方式進行連線,大致看了下JNI方式實在麻煩,崩潰中找到JNA,併成功實現了呼叫,特此記錄使用過程。
一、將so檔案放在linux伺服器下,並且指定export LD_LIBRARY_PATH路徑為你的so檔案放置路徑(so檔案需要字首lib,因為jna為去動態庫中匹配lib字首的so檔案,如libcompress.so)
我這邊放置在/etc/profile
vim /etc/profile然後設定
export LD_LIBRARY_PATH=你的so檔案放置路徑
編寫好後執行:source /etc/profile使之生效
二、maven匯入jna包
<!-- https://mvnrepository.com/artifact/com.sun.jna/jna -->
<dependency>
<groupId>com.sun.jna</groupId>
<artifactId>jna</artifactId>
<version>3.0.9</version>
</dependency>
三、根據c提供的標頭檔案看需要呼叫的方法和其引數,在java下建立
c中格式如下:
#define uint8_t unsigned char #define uint16_t unsigned short #define COMPRESS_IR_MAX_DIF_VAL (255) //the max different value of the ir data #define COMPRESS_INDEX_LEN_3 (3) #define COMPRESS_INDEX_LEN_4 (4) #define COMPRESS_INDEX_LEN_5 (5) #define COMPRESS_INDEX_LEN_6 (6) #define COMPRESS_INDEX_LEN_7 (7) #define COMPRESS_INDEX_LEN_8 (8) #define COMPRESS_VAGUE_MAX_VALUE (20)//樣品資料最大模糊值 #define COMPRESS_SRC_DATA_DIVIDE_VAL (5)//原資料整除值 typedef struct { uint16_t freq; //frequency int *srcData; //sourdata pointer uint16_t srcSize; //source data size uint16_t *diffData; //different value buffer pointer uint8_t diffSize; //different value count uint8_t *indexBuf; //index buffer pointer uint16_t indexBufSize; //index buffer Size uint16_t indexSize; //size of the index list uint8_t indexLen; //the length of the single index value }COMPRESS_INFO; typedef struct { int freq; //frequency int srcData[2000]; //source data uint16_t srcSize; //source data Size }COMPRESS_INPUT; typedef struct { int compressDataSize; uint8_t compressData[2000]; //compress data pointer }COMPRESS_OUTPUT; typedef struct { uint8_t data2:2; uint8_t data1:3; uint8_t data0:3; uint8_t data6:1; uint8_t data5:3; uint8_t data4:3; uint8_t data3:1; uint8_t data9:3; uint8_t data8:3; uint8_t data7:2; }UNIT_3; typedef struct { uint8_t data0:4; uint8_t data1:4; }UNIT_4; typedef struct { uint8_t data1:3; uint8_t data0:5; uint8_t data4:1; uint8_t data3:5; uint8_t data2:2; uint8_t data6:4; uint8_t data5:4; uint8_t data9:2; uint8_t data8:5; uint8_t data7:1; uint8_t data11:5; uint8_t data10:3; }UNIT_5; typedef struct { uint8_t data1:2; uint8_t data0:6; uint8_t data3:4; uint8_t data2:4; uint8_t data5:6; uint8_t data4:2; }UNIT_6; typedef struct { uint8_t data1:1; uint8_t data0:7; uint8_t data3:2; uint8_t data2:6; uint8_t data5:3; uint8_t data4:5; uint8_t data7:4; uint8_t data6:4; uint8_t data9:5; uint8_t data8:3; uint8_t data11:6; uint8_t data10:2; uint8_t data13:7; uint8_t data12:1; }UNIT_7; COMPRESS_OUTPUT * compress_handle(COMPRESS_INPUT *inputData);
由上可知,c中提供的為一個簡單壓縮方法,引數為COMPRESS_INPUT,返回值為COMPRESS_OUT兩個物件除了有基本資料型別,還有byte型別和int型別指標。如果引數或者返回值都只是基本型別,很簡單,這邊不講,這種引數返回值都為物件,並且屬性涉及指標(java沒有指標的概念),稍微複雜一些,廢話不多說,直接上程式碼,首先建立入參物件:
package com.intre.kksdk.bean;
import com.sun.jna.Structure;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by YQ11053 on 2018/8/28 0028.
*/
public class COMPRESS_INPUT extends Structure implements Serializable {
public int freq;
public int[] srcData = new int[2000];
public int srcSize;
public COMPRESS_INPUT() {
allocateMemory();
}
public static class ByReference extends COMPRESS_INPUT implements Structure.ByReference {}
public static class ByValue extends COMPRESS_INPUT implements Structure.ByValue {}
@Override
protected List<String> getFieldOrder() {
List<String> Field = new ArrayList<String>();
Field.add("freq");
Field.add("srcData");
Field.add("srcSize");
return Field;
}
public int getFreq() {
return freq;
}
public void setFreq(int freq) {
this.freq = freq;
}
public int[] getSrcData() {
return srcData;
}
public void setSrcData(int[] srcData) {
this.srcData = srcData;
}
public int getSrcSize() {
return srcSize;
}
public void setSrcSize(int srcSize) {
this.srcSize = srcSize;
}
}
上面需要注意點如下:
1、類需要繼承Structure //這樣才能接受c中的結構體
2、用int型別的陣列去對應c中int型別的指標,並且直接初始化並設定大小
3、建構函式中執行allocateMemory();,允許計算大小
4、建立(一般都寫上)
public static class ByReference extends COMPRESS_INPUT implements Structure.ByReference {} //引數為物件需要這麼寫
public static class ByValue extends COMPRESS_INPUT implements Structure.ByValue {} //為基本型別這麼寫
5、重寫方法getFieldOrder,實現c的結構體和java的物件屬性值的傳遞
@Override
protected List<String> getFieldOrder() {
List<String> Field = new ArrayList<String>();
Field.add("freq");
Field.add("srcData");
Field.add("srcSize");
return Field;
}
返回值物件同上:
package com.intre.kksdk.bean;
import com.sun.jna.Structure;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by YQ11053 on 2018/8/28 0028.
*/
public class COMPRESS_OUTPUT extends Structure implements Serializable {
public int compressDataSize;
public byte[] compressData = new byte[2000];
public COMPRESS_OUTPUT(){
allocateMemory();
}
public static class ByReference extends COMPRESS_OUTPUT implements Structure.ByReference {}
public static class ByValue extends COMPRESS_OUTPUT implements Structure.ByValue {}
@Override
protected List<String> getFieldOrder() {
List<String> Field = new ArrayList<String>();
Field.add("compressDataSize");
Field.add("compressData");
return Field;
}
@Override
public String toString() {
return "CompressOutput{" +
"compressData=" + Arrays.toString(compressData) +
", compressDataSize=" + compressDataSize +
'}';
}
}
實現類:
package com.intre.kksdk.utils;
import com.intre.kksdk.bean.COMPRESS_INPUT;
import com.intre.kksdk.bean.COMPRESS_OUTPUT;
import com.intre.kksdk.bean.DECOMPRESS_INPUT;
import com.intre.kksdk.bean.DECOMPRESS_OUTPUT;
import com.sun.jna.Library;
import com.sun.jna.Native;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by YQ11053 on 2018/8/28 0028.
*/
public class CompressJNA {
private Logger logger = LoggerFactory.getLogger(CompressJNA.class);
public interface CompressLib extends Library {
CompressLib INSTANCE = (CompressLib) Native.loadLibrary("compress",CompressLib.class);
COMPRESS_OUTPUT.ByReference compress_handle(COMPRESS_INPUT compress_input); //壓縮方法
}
public COMPRESS_OUTPUT.ByReference compress_handle(COMPRESS_INPUT compress_input){
return CompressLib.INSTANCE.compress_handle(compress_input);
}
public COMPRESS_OUTPUT.ByReference compress(COMPRESS_INPUT compress_input){
COMPRESS_OUTPUT.ByReference compressOutput = new CompressJNA().compress_handle(compress_input);
return compressOutput;
}
}
需要注意的是載入so檔案方法中,CompressLib INSTANCE = (CompressLib) Native.loadLibrary("compress",CompressLib.class);
第一個引數為so檔案出去lib字首後的名稱.
四、呼叫(windos下無法測試,需要在linux下才能執行成功,windos下可用dll檔案)
public static void main(String[]args){
int frec = 3600;
COMPRESS_INPUT inputData = new COMPRESS_INPUT();
inputData.setFreq(frec);
int[] srcData= {2,1,4,5,6,7,8,9};
int srcDataSize = 8;
inputData.setSrcData(srcData);
inputData.setSrcSize(srcDataSize);
COMPRESS_OUTPUT compressOutput = new CompressJNA().compress(inputData); //呼叫so函式獲取壓縮物件
}
ps:伺服器由於某些原因關閉重啟後需要重新執行source /etc/profile 然後再啟動tomcat使之生效。
相關推薦
使用JNA呼叫c/c++的so動態庫函式
最近專案收到個需求,需要呼叫c寫的函式,給的是so檔案,查閱了資料,so檔案為linux下的動態庫函式檔案,windos下為dll檔案。傳統方案用JNI方式進行連線,大致看了下JNI方式實在麻煩,崩潰中找到JNA,併成功實現了呼叫,特此記錄使用過程。 一、將s
c++呼叫c++的so動態庫2
1.環境 ubuntu 14.04 g++ 4.8.4 2.有類的情況 1)庫檔案 a)原始碼 //cppl2.h class cal { public: cal(); virtual ~
Java呼叫C/C++生成的動態庫函式
問題背景 之前的文章中,筆者將超長整數的四則運算利用C語言實現,因個人需要在web專案中使用該功能, 此時能想到的辦法是重寫實現過程,即利用Java重寫一遍C的實現過程 不談工作量的多少,單單是這個重寫的過程就讓我望而生畏,程式設計師最頭疼的一個是bug找不到,還有一個就是
C++批量載入動態庫函式方法
1、列舉定義enum { // 0 - GigE DLL (implicitly called) Func_isVersionCompliantDLL, Func_isDriverAv
程式碼告訴你:Java到底是怎麼呼叫dll&so動態庫的?
使用Java呼叫dll&so動態庫的函式 *應用背景:專案中需要呼叫一項其他平臺提供的服務,是一位C語言老大哥寫的,可牛啦。但是因為一些特殊原因導致不能通過API呼叫的方式實現,最終的解決方案是老大哥把他的程式封裝成so和dll動態庫,然後我在專案裡使用JNA呼叫so或dll動態
Linux環境下 lua 呼叫自定義so動態庫(skynet)
最近看的 skynet 使用的 c+lua 的架構,框架提供的是基礎的api,所以業務邏輯還得自己去寫,如果某些業務邏輯比較耗效能,那可能就需要把某些業務邏輯丟到 c/c++ 去做,提供個介面供
C語言中呼叫靜態庫函式和動態庫函式的方式
C語言中呼叫動態庫函式的兩種方式 方式一.隱式呼叫 將動態庫的相關檔案拷貝到當前目錄下(lib、dll),然後新增以下程式碼,在程式中指定連線庫函式。 注意:第二個引數給出的是引入庫檔案(或稱“匯出庫檔案”),而不是dll。在程式執行過程中,lib將dll中需要用到的函式對映到對應的記憶
java jni呼叫c/c++的so動態連結庫簡易demo
需求: 工作中需要多個團隊協作開發,而不同團隊提供的程式語言不同,比較常見的是底層互動使用C++或c來實現任務排程,java層實現業務排程或者業務實現,正好有涉及到這方面的應用,就分享一下java使用jni呼叫linux中so檔案的幾個注意事項編寫簡易的
c++呼叫c語言的so動態庫
1.環境 ubuntu14.04 gcc 4.8.4 g++ 4.8.4 2.庫檔案 1)原始碼 //clTest.c int add(int a, int b) { return a + b; } 2)生成庫檔案 cd到clTest.c所
C++中使用_asm彙編呼叫動態庫函式的一點問題
因為從事dll 編寫的相關工作。沒寫完一個dll 之後都要對函式進行測試,對每個dll都要寫一個測試demo的話就非常費勁。能不能一個公共的測試軟體來各種dll裡的函式測試呢? 嘗試開始,從外界的.h檔案中讀取函式名很簡單,但是我們不能在程式已經編譯的過程中
C語言 呼叫的動態庫函式重名問題分析
設計兩個動態庫 第一個動態庫:libHelloc: func1.h #ifndef FUNC1_H_ #define FUNC1_H_ int func1(); void func(); #endif func1.c #include "func1.h" int
C語言呼叫so動態庫的兩種方式
方式1:類似靜態庫的呼叫(使用標頭檔案) 這種方式生成的程式會在啟動時候就載入so動態庫。 add.h int add(int x, int y); add.c #include "add.h" int add(int x, int y
c++ 呼叫Python指令碼或者動態庫——環境Ubuntu 16.04下用codeblocks
背景:因為使用的是python版本的程式,最終要整合到C++環境的架構中,也就是說架構是c++的,交付使用者為c++的介面,但是呼叫的是python的庫,因此需要學習在c++環境下呼叫python。因為對python不熟悉,可以說有點一抹黑,因此從簡到難逐步探索。首先在c++
Java呼叫C++編寫的動態庫(JNI)
1. 在eclipse裡利用java建立一個類,在類中加入帶有native的方法(eclipse建立的類會自動新增class在bin目錄下) 2.利用javah命令生成本地方法的c++標頭檔案。進入到工程bin目錄下,按住shift,並右擊,選擇 “在此處開啟命令視窗”,進入命令視
PB呼叫.NET/C#開發的動態庫DLL的問題
之前用C#做了一個Dll提供給第三方呼叫(主要為PB使用者)。 pb一直無法呼叫我寫的dll,導致問題排查了3天。 最後找出原因是因為,對方環境沒有安裝.net framework。沒有將dll註冊導致的。
安卓so動態庫載入代理實現,可以實現C層的類反射效果
一般來說如果我們需要載入so檔案,需要一個java對應層的類,即有一個類必須要是包名和類名是不變的。 比如說下面的c層程式碼,這樣寫就必須要求有個類是com.example.hellojni.HelloJni,呼叫的方法為stringFromJNI /* DO NOT
利用c#實現dll動態庫,並在c++中呼叫的方法
近期,在進行一個大專案開發。其中涉及多語言協同開發。主要是c#dll和c++dll的開發和應用,其中,需要在c++中呼叫c#dll的內容。現在把開發中的經驗、教訓和注意事項總結整理如下,希望對其他人能有所幫助。 1.建立c#dll,
VS2015用C++建立的動態庫匯出函式名亂碼原因分析
在上一篇部落格【在VS2015中用C++建立動態庫並用C#呼叫】中提到,在C# DllImport匯入C/C++編寫的動態庫時函式,要加上CallingConvention = Ca
eclipse c/c++程式設計引用動態庫(so)
動態庫的引用: 右擊專案,選中屬性,在屬性頁中: C/C++ Build=》Settings=》Tool Settings=》GCC C Compiler=》command 欄寫上gcc -lpthread -ltcmrdriver (使用者自定義庫libtcmrdriver.so) 同樣在GCC
C 語言兩個動態庫函式重名問題
應用程式a(a.c),動態庫liba.so(liba.h, liba.c),libb.so,均實現了func() gcc -la -lb a.c 則呼叫的是liba.so中的函式實現 gcc -lb -la a.c 則呼叫的是libb.so中的函式實現