본문 바로가기
배달앱 개발일지

[삽질중]JNI로 배민 dll 함수 사용하기_서비스 초기화

by 우딬 2021. 10. 1.

안녕하세요. 바람처럼 배달 대행 1인 개발자로 활동 중인 최수지입니다.

배달 대행이 먹고 사는건 배민이 있어서라고 할 정도로

한 없이 '을'인 배달 대행 회사는 배민과 연동을 위해

배민 배달 진단 프로그램을 이용해 개발을 진행하고 있습니다.

저는 데이터 분석을 시작해서 현재 자바 개발자로 근무하고 있고,

c언어를 printf 밖에 모르는 그래서 너무 어려운 이 숙제를 하나씩 풀어가고

공부하고자 블로그에 작성하게 되었습니다.

그리고 저를 도와 주고 같이 JNI를 공부하고 있는

히로시에게 너무 고맙다고 말하고 시작하겠습니다.

 

1. 서비스 초기화 시키기

배민에는 3가지의 Callback 함수가 존재합니다.

 

1. TOnNewDeliveryFunc : 접수된 새로운 주문이 있으면 해당 함수가 호출된다.

(상황설명) 보통 배민에 주문이 들어오면 가게에서 시간을 찍어서 소비자에게 전달한다.

그 때 새로운 주문이 접수 되고 내 프로그램이나 DB로 값을 저장 시켜야한다.

도로명 주소가 없을 경우가 있으니 이 부분도 개발할때 염두 해두어야한다.

성공했다면 true, 오류가 발생했다면 false

 

2. TOnStatusChangedProc : 주문 상태가 변경되었을때

0 - 새로운 주문 발생 1 - 주문을 접수함 2 - 주문이 완료됨 3 - 주문이 취소됨

실제로 받을 수 있는 코드는 2번 코드 뿐이다.

(상황설명)

1 - 주문 접수 하면 > 위의 콜백함수가 사용되니

2 - 주문이 완료된다는건 가게에서 주문이 끝나고 완료 버튼을 눌렸다는건데

이건 가게마다 차이가 있어서 어떤 가게는 배달 다 하고 한꺼번에 몰아서 완료버튼 눌린다던지

어떤 가게는 배달대행에서 완료 됬다고 하면 완료 버튼을 바로 눌린다던지

사실 막 개발을 시작한 단계에서 이 기능이 어떻게 쓰이는지 잘 모르겠다.

 

3. TOnDisconnectedProc : FinalizeService를 호출하여 설정 초기화한 다음
초기화 과정을 다시 수행하는 것을 권장

(상황설명)

나중에 나오지만 배민 프로그램이 꺼지는 경우 해당 이벤트가 발생하고

연결된 Callback 함수 연결 해제하고 서버와 접속을 종료한 이후

다시 새로운 서비시를 초기화 할때 쓰이는 콜백함수

 

첫번째 미션 : 3가지 콜백함수를 등록하기.

 

콜백 함수를 등록하려면 등록 함수가 있을거니 이번엔 등록 함수를 알아보자.

1. RegisterNewDeliveryFunction

TOnNewDeliveryFunc 함수를 등록

2. RegisterStatusChangedFunction

TOnStatusChangedProc 함수를 등록

3. RegisterDisconnectedFunction

TOnDisconnectedProc 함수를 등록

 

간단하게 플로워를 생각해 본다면,

1. [자바] 콜백 등록 함수를 정의한다. : RegisterCallbackFuncs

2. [C++] 등록 함수에 3가지 콜백함수가 등록되도록 설정한다. 

3. [자바] 등록된 콜백 함수를 실행한다.

 

A. 자바 콜백함수 정의

public native boolean WindcallRegisterCallbackFuncs();

* 함수에 _(언더바)를 사용하면 JNI헤더에 숫자 1이 생긴다. 그래서 언더바를 사용하지 않았다.

 

B. C++에서 불러올 함수

//dll 불러오기
auto LoadLib() {
    auto load = LoadLibraryA("절대경로\\BMOrderRelayx64.dll");
    return load;
}

JNIEXPORT jboolean JNICALL Java_Beamin_BeaminFunc_WindcallRegisterCallbackFuncs
    (JNIEnv* env, jobject obj)
    {
        
        //배민 dll 불러오기
        auto load = LoadLib();
        if (load == NULL)
        {
            return false;
        }
		
        //등록 함수로 등록하기 *3
        auto RegisterNewDeliveryFunction = 
        reinterpret_cast<RegisterNewDeliveryFunction_t>
        (GetProcAddress(load, "RegisterNewDeliveryFunction"));
        
        auto RegisterStatusChangedFunction = 
        reinterpret_cast<RegisterStatusChangedFunction_t>
        (GetProcAddress(load, "RegisterStatusChangedFunction"));
        
        auto RegisterDisconnectedFunction = 
        reinterpret_cast<RegisterDisconnectedFunction_t>
        (GetProcAddress(load, "RegisterDisconnectedFunction"));

        if (RegisterNewDeliveryFunction == NULL
        || RegisterStatusChangedFunction == NULL
            || RegisterDisconnectedFunction == NULL)
        {
            return false;
        }
        // 등록 완료

        auto ret = true;
        //모두가 true가 안되면 실행 되지 않는다.
        ret &= RegisterNewDeliveryFunction(MyOnNewDeliveryFunc);
        ret &= RegisterStatusChangedFunction(MyOnStatusChangedProc);
        ret &= RegisterDisconnectedFunction(MyOnDisconnectedProc);

        if (ret == false)
        {
            return false;
        }

        return true;

    }

C. 자바에서 사용하기

public static void start() {
	BeaminFunc b = new BeaminFunc();
	boolean ret = b.WindcallRegisterCallbackFuncs();
	System.out.println(ret);	
}
	
public static void main(String[] args) {
	start();
	while(true) {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
	}
}

 

C++ 공부 노트 1 (auto)

auto LoadLib() {
    auto load = LoadLibraryA("절대경로\\BMOrderRelayx64.dll");
    return load;
}

auto라니.. 자바의 object 같은건가? 모든 코드의 어머니 조상님 그런??

 

1. 형식이 추론되는 변수를 선언하는 역활이고

2. 함수의 파라미터로 쓸수 없고, 멤버 변수로 사용 X

3. 함수의 return으로는 사용가능 어느정도 추론이 가능하는것

 

object라는 좀 다른 느낌의 타입 같고 자바 10의 var정도로 생각하면 될거 같다.

 

B-1 함수 등록 함수 자세히 들여다 보기

auto RegisterStatusChangedFunction = 
  reinterpret_cast<RegisterStatusChangedFunction_t>
  (GetProcAddress(load, "RegisterStatusChangedFunction"));

2번째 콜백함수를 등록하는 과정을 살펴보면

1. GetProcAddress로 배민dll에 존재하는 함수를 불러온다.

2. reinterpret_cast로 형 변환을 시켜줍니다.

    int* p = new int(100);

    char c = reinterpret_cast<char> (p);

    <char>안의 값으로 (p)를 형변환 시켜 c로 저장한다.

 

그럼 배민 함수를 불러올땐 <> 안에 뭘 써야하나

typedef void (*TOnStatusChangedProc)(wchar_t*, wchar_t*);
typedef bool (*RegisterStatusChangedFunction_t)(TOnStatusChangedProc);

typedef로 미리 타입을 선언 , 정의하는 것으로 형변환을 실행시키면 된다.

배민의 공식 API PPT에 나와있는대로 파라미터 리턴값을 잘 설정하면 된다.

 

B-2 함수 등록 코드 자세히 살펴보기

RegisterStatusChangedFunction(MyOnStatusChangedProc);

위에서 형 변환을 통해 배민 함수와 똑같은 기능을 하는 함수를 만들었고,

그 함수의 매개변수는 TOnStatusChangedProc이다.

 

배민 C# 샘플코드(유일하게 자바와 비슷한 좀 읽을 수 있는..)

에서 정의된 함수를 사용해 봤기에

MyOnStatusChangeProc 함수를 새로 정의하여 만들어 보았다.

 

void MyOnStatusChangedProc(wchar_t* AOrderNo, wchar_t* AOrderStatus) {

}

 

안의 내용은 나중에 채워야겠지만 TOnStatusChangedProc와

똑같은 함수를 만들어 콜백 함수로 사용할 예정이다.

 

두번째 미션 : 인증키를 사용하여 인증하기.

 

int InitializeService(WCHAR[] ASignKey);

라는 함수는 리턴 값이 0이 아니면 모두 오류라고 생각하면 된다.

 

이건 만들기 간단하지 라고 했는데

왠걸 C++은 그냥 String만 있는게 아니잖아..?

물론 자바도 char String 등등이 있지만 그렇게 복잡하진 않은거 같은데..

 

자바에서 String값을 보내면 C++에선 jstring으로 받아서 사용된다.

그런 jstring을 wchar_t[] 로 바꾸는 과정만 하루를 썼던거 같다.

궁금하다면 아래의 링크로 확인해 주세요.

 

https://suji-choi.tistory.com/61

 

[삽질중]JNI로 배민 dll 함수 사용하기 jstring >> wchar_t

JNIEXPORT jint JNICALL Java_Beamin_BeaminFunc_WindcallInitializeService (JNIEnv* env, jobject obj, jstring j_String) { // 1. jstring을 const char*로 변환 const char* c_String = (env)->GetStringUTFCh..

suji-choi.tistory.com

 

 

마지막으로 코드를 돌려보면..

댓글