'Open Source/Java'에 해당되는 글 6건
- 2012.12.05 RMI 제작 및 사용법
- 2012.10.30 C Code JNI 사용 (Class, 인수 사용등) 1
- 2012.10.30 Jni C 사용 방법
Remote로 사용할 Data Object
import java.io.*; public class TestDataObj implements Serializable { private int Tag; private int Stat; public void setTag(int iTag) { this.TagNo = iTag; } public void setStat(int iStat) { this.Stat = iStat; } public int getTag() { return this.Tag; } public int getStat() { return this.Stat; } }
넘길 Object를 직렬화 해줘야 하기 때문에 implements Serializable 해줘야 한다.
Interface 선언
import java.rmi.*; public interface IReadData extends Remote { public TestDataObj GetTestDataObj() throws RemoteException; }
rmi에서 사용할 Data Object
import java.rmi.server.*; import java.rmi.*; import java.io.*; public class ReadDataImpl extends UnicastRemoteObject implements IReadData { public ReadDataImpl() throws RemoteException { super(); } public TestDataObj GetTestDataObj() { TestDataObj Data = new TestDataObj(); Data.setTag(1); Data.setStat(5); return rtlData; } }
rmi Server
import java.rmi.*; import java.net.*; public class RmiShmServer { public static void main(String[] args) { try { ReadDataImpl remoteObj = new ReadDataImpl (); Naming.rebind("rmi://localhost:1099/TestRemote", remoteObj); System.out.println("Test Remote Obj Bound to the registry"); } catch (RemoteException e) { System.err.println("incoming method call" + e); } catch (MalformedURLException e) { System.err.println("Checking URL " + e); } } }
rmi 주소를 넣어 줄시 rmi://localhost:[port]/[Remote Object] 형식으로 만들어 준다
나중에 rmiregistry 등록시 port를 기입 해준다.
rmi Client
import java.rmi.*; import java.net.*; public class RmiShmClinet { public static void main(String[] args) { try { Object obj = Naming.lookup("rmi://localhost:1099/TestRemote"); IReadData remoteObj = (IReadData)obj; TestDataObj Data = remoteObj.GetTestDataObj(); System.out.println(Data.getTag() + ":" + Data.getStat()); } catch (RemoteException e) { System.out.println("Somthig has gone wrong during reote method call.." + e); } catch (NotBoundException e) { System.out.println("Could't Bound.. "); } catch (java.net.MalformedURLException e) { System.out.println("Check url String.."); } } }
Server에서 선언한 주소를 사용하여 Remote Object를 바라본다.
unix 명령어
1차 console
prompt>javac *.java
prompt>rmic ReadDataImpl
prompt>rmiregistry 1099 &
(Background로 rmiregistry 실행)
prompt>java RmiShmServer
2차 console
prompt>java RmiShmClinet
Data 확인
Compile이 잘 되지 않을 경우 profile의 classpath를 잡아 준다.
CLASSPATH=경로:.
export CLASSPATH
대략 이런식이 되겠지?!
ShmData.java
package SharedMemory; public void setTagData(int iTagData) { this.TagData = iTagData; } public void setAnalogData(int iAnalogData) { this.AnalogData = iAnalogData; } public void setComment(String strComment) { this.Comment = strComment; } public int getTagData() { return this.TagData; } public int getAnalogData() { return this.AnalogData; } public String getComment() { return this.Comment; } } |
이 같은 Java Class의 형식을 JNI를 이용하여 Return 하고자 할 경우 C Code File의 작성
JNIEXPORT jobject JNICALL Java_SharedMemory_MemoryRead_Data1 (JNIEnv *env, jobject obj, jint iIndex) { int iTagData = 100; int iAnalogData = 1200; char strComment[100]; memset(strComment, 0x00, sizeof(strComment)); sprintf(strComment, "%s", "Jni Test !!"); jclass targetClass; jmethodID mid; jobject newObject; jfieldID fid; jint result; jstring Comment; targetClass = (*env)->FindClass(env, "SharedMemory/ShmData"); // 생성자 찾기 mid = (*env)->GetMethodID(env, targetClass, "<init>", "()V"); // 객체 생성(객체 레퍼런스 반환) newObject = (*env)->NewObject(env, targetClass, mid, "()V"); // JniObject 객체의 intField 필드값 설정 fid = (*env)->GetFieldID(env, targetClass, "TagData", "I"); (*env)->SetIntField(env, newObject, fid, iTagData); fid = (*env)->GetFieldID(env, targetClass, "AnalogData", "I"); (*env)->SetIntField(env, newObject, fid, iAnalogData ); fid = (*env)->GetFieldID(env, targetClass, "Comment", "Ljava/lang/String;"); Comment = (*env)->NewStringUTF(env, strComment); (*env)->SetObjectField(env, newObject, fid, Comment); return newObject; } |
위 Code는 JNI를 기반으로 한 C Code이다.
return형을 보자면 jobject 형이므로 Code안에서 return할 jobject newObject를 선언하였다.
그리고 java Code로는 class가 기준이 되므로 C와 java class를 연결할 jclass targetClass를 선언 하였다.
targetClass = (*env)->FindClass(env, "SharedMemory/ShmData");
SharedMemory/ShmData Class를 targetClass에 설정한다.
newObject = (*env)->NewObject(env, targetClass, mid, "()V");
newObject로 targetClass의 Instance를 생성하고 생성자를 실행한다.
fid = (*env)->GetFieldID(env, targetClass, "TagData", "I");
fid에 field(Class 변수)를 설정한다. 변수명은 TagData이고 Type는 I 즉 int Type이다.
(*env)->SetIntField(env, newObject, fid, iTagData);
설정된 Field에 값을 설정한다.
fid = (*env)->GetFieldID(env, targetClass, "Comment", "Ljava/lang/String;");
fid에 field(Class 변수)를 설정한다. 변수명은 Comment이고 Type는 Ljava/lang/String 즉 String Type이다.
Comment = (*env)->NewStringUTF(env, strComment);
jstring형으로 Data를 만들어 준다. c char 배열 또는 포인터 형과 java의 string의 관리 형태가 많이 다르기 때문에 이러한 형태를 취하는게 아닐까 싶다.
Instance에 값을 전부 설정했다면 return newObject를 하여 java에서 받을 수 있게 해준다.
위에서 주의 해야 할 것은 GetFieldID에서는 targetClass를 사용 하였지만 SetIntField 또는 SetObjectField시에는 NewObject 를 사용했다는 점이다.
javah를 사용하여 C Header File을 생성 하였다면 그 형식은 Package_Class.h 형식이 될 것이다.
File을 open 하면 Source.Java File의 native 뒷부분 정의 된 함수가 Header 로 정의되가 된다.
형식은
JNIEXPORT jobject JNICALL Java_Package_Class_NativeFunction(JNIEnv *, Java Parameter);
EX) Package : SharedMemory
Class : MemoryRead
NativeFunction : Data1(int Index)
JNIEXPORT jobject JNICALL Java_SharedMemory_MemoryRead_Data1(JNIEnv *, jobject, jint);
C Header File에서 정의된 함수를 기준으로 Soucre Code를 작성하여 라이브러리 형식으로 만든뒤 Java에서 Call 하여 사용하는 방식을 취하면 된다.
Source를 제작 하여 컴파일 후 라이브러리로 만든 파일의 위치는 Java Class Package의 상위에 위치시키면 된다.
EX ) Package Class File 위치 = :/JniTest/Package
C 라이브러리 위치 = :/JniTest
C Source 제작
Jni로 생성된 Header File을 inlucde 하여 Coding 하면 된다.
위 예제를 기준으로 Code를 작성하면
#include "SharedMemory_MemoryRead.h" { } |
Function 내용은 원하는 걸로 채우면 된다!!
jint Index 의 경우 그냥 int Type과 동일하게 하여 작성해 나가면 된다.
java에서의 사용법
MemoryRead.java
package SharedMemory; import java.util.ArrayList; public class MemoryRead{ native ShmData Data1(int Index); static{ try{ System.loadLibrary("ShmRead"); }catch(Exception e) e.printStackTrace(); } } public ArrayList<ShmData> GetShmData() { ArrayList<ShmData> Data = new ArrayList<ShmData>(); for(int i = 0 ; i < MAX_DATA; i++) { ShmData Tmp = Data1(i); Data.add(Tmp); } return Data; } } |
Java Sample Code를 작성하자면 대략 위와 같은 형태가 될 것이다.
여기서 System.loadLibrary("ShmRead"); 라인의 ShmRead는 C로 제작된 라이브러리
즉 libShmRead.so file을 참조 한다는 이야기가 되겠다.