[C++,QT/Qml]34.Qt 프로세스간의 통신(IPC) 구현하기3(commonapi를 이용한 프로세스간 통신 구현)
안녕하세요 고급 프로그래머가 꿈인 코린이 입니다.
오늘은 commonapi를 이용해서 서버에서 클라이언트로 브로드 캐스트하는 방법에 대해서 설명 드리겠습니다.
브로드 캐스트란 특정한 이벤트가 발생했을때 받을 함수를 클라이언트에서 등록을 한 뒤에 서버에서
이 특정한 이벤트를 발생하면 클라이언트가 등록한 함수로 이벤트의 내용을 받을수 있도록 구현된 내용 입니다.
이 내용이 주로 쓰이는 곳은 서버에서 특정한 이벤트가 발생 되었을때 예를들어 서버가 300일 이상 가동되면
클라이언트에게 300일이상 가동이 되었다고 알려줘야할때 이 이벤트의 주최는 클라이언트가 아닌 서버쪽이 됩니다.
그렇기 때문에 서버쪽에서 클라이언트 들에게 300일 이상이 지났다고 알려주어야하는데요 이때 사용하는 것이
브로드 캐스트(broadcast)입니다.
ipc를 구현하다보면 이러한 브로드 캐스트 이벤트를 많이 사용하는데요 왜냐하면 로직과 ui가 나누어 졌을때
로직에서 특정한 이벤트가 발생하면 ui쪽에서는 알수가 없기 때문이죠 그렇기 때문에 서버가 주최가 되어서
클라이언트들에게 이벤트를 발생하는 내용을 broadcast로 구현을 하게 됩니다.
그래서 이 broadcast를 commonpi를 이용해서 사용하는 방법을 이 포스팅에 적을 예정이고
다음 포스팅에서는 이 commonapi를 제가 만든 qt ui프로그램에 포팅하는 내용을 다루겠습니다.
Helloworld.fidl
1
2
3
4
5
6
7
|
broadcast enumBroadCastMethod{
out{
testEnum outputEnum
}
}
|
브로드 캐스트를 구현할 fidl을 위와 같이 설정해 줍니다.
broadcast를 적어주시고 함수이름과 그리고 매개변수르 enum값을 넣어서 호출하도록 위에 처럼 넣어주었습니다.
그 이후에 fidl을 commonapi code 제너레이트를 해서 브로드 캐스트 함수가 자동으로 만들어 지도록 해줍니다
client code
1
2
3
4
|
myProxy->getEnumBroadCastMethodEvent().subscribe([&](HelloWorld::testEnum value){
std::cout << "Client Log!! getEnumBroadCastMethodEvent value: " << value << std::endl;
});
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
그리고 위와 같이 클라이언트 쪽 소스코드에서 제가 만들어준 broadcast함수를 등록해 줍니다.
위에 처럼 등록을 해주면 서버에서 broadcast 이벤트를 발생 시키면 위의 등록된 함수를 통해서 이벤트를 받아올수
있습니다. 서버에서 enum값을 매개변수로 broadcast를 해주기 때무넹 enum값을 받아서 출력하는 내용으로
구현하였습니다.
server code
1
2
3
4
5
6
|
while (true) {
std::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;
myService->fireEnumBroadCastMethodEvent(v1::commonapi::HelloWorld::testEnum::TEST_THIRD);
std::this_thread::sleep_for(std::chrono::seconds(30));
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
위의 내용과 같이 while문을 이용해서 30초에 한번씩 서버에서 브로드 캐스트 함수가 불려지도록 구현을 하였습니다.
그래서 30초에 한번씩 fireENumBroadCastMethodEvent가 불려지게 됩니다.
저 함수는 myService안에서 함수를 상속 받지않고 HelloWorldStubDefault 클래스의 함수를 그대로 사용 하였습니다.
이렇게 진행한 후 아래는 실행 결과 입니다.
server 쪽 로그
아래의 send broadcast method 로그가 찍힌 것으로 서버에서 브로드 캐스트 이벤트를 날린것을 알수 있습니다.
client쪽 로그
아래의 getEnumBroadCastMethodEvent로그가 찍히는 것을 보고 이벤트가 발생되었다는 것을 알수 있습니다.
아래의 로그들은 이전 내용에서 다룬 내용을 모두 포함한 내용으로 broadcast쪽 로그를
보시면 됩니다.
참고해주세요 ^^
아래는 전체 소스코드를 올려드리겠습니다.
혹시나 참고할때 도움이 되었으면 좋겠습니다.
HelloWorldStubImpl.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#ifndef HELLOWORLDSTUBIMPL_H_
#define HELLOWORLDSTUBIMPL_H_
#include <CommonAPI/CommonAPI.hpp>
#include <v1/commonapi/HelloWorldStubDefault.hpp>
class HelloWorldStubImpl: public v1::commonapi::HelloWorldStubDefault {
public:
HelloWorldStubImpl();
virtual ~HelloWorldStubImpl();
virtual void sayHello(const std::shared_ptr<CommonAPI::ClientId> _client, std::string _name, sayHelloReply_t _return);
virtual void intDataMethod(const std::shared_ptr<CommonAPI::ClientId> _client, int32_t _parameter, intDataMethodReply_t _reply);
virtual void enumMethod(const std::shared_ptr<CommonAPI::ClientId> _client, v1::commonapi::HelloWorld::testEnum _testEnumParameter, enumMethodReply_t _reply);
virtual void structInMethod(const std::shared_ptr<CommonAPI::ClientId> _client, v1::commonapi::HelloWorld::testStruct _structParameter, structInMethodReply_t _reply);
virtual void structOutMethod(const std::shared_ptr<CommonAPI::ClientId> _client, int32_t _input, structOutMethodReply_t _reply);
};
#endif /* HELLOWORLDSTUBIMPL_H_ */
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
HelloWorldStubImpl.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include "HelloWorldStubImpl.hpp"
HelloWorldStubImpl::HelloWorldStubImpl() { }
HelloWorldStubImpl::~HelloWorldStubImpl() { }
void HelloWorldStubImpl::sayHello(const std::shared_ptr<CommonAPI::ClientId> _client, std::string _name, sayHelloReply_t _reply) {
std::stringstream messageStream;
messageStream << "Hello " << _name << "!";
std::cout << "sayHello('" << _name << "'): '" << messageStream.str() << "'\n";
_reply(messageStream.str());
}
void HelloWorldStubImpl::intDataMethod(const std::shared_ptr<CommonAPI::ClientId> _client, int32_t _parameter, v1::commonapi::HelloWorldStub::intDataMethodReply_t _reply)
{
std::cout << __FUNCTION__<<" server log parameter" << _parameter << std::endl;
std::int32_t returnData = 100;
_reply(returnData);
}
void HelloWorldStubImpl::enumMethod(const std::shared_ptr<CommonAPI::ClientId> _client, v1::commonapi::HelloWorld::testEnum _testEnumParameter, v1::commonapi::HelloWorldStub::enumMethodReply_t _reply)
{
std::cout << __FUNCTION__<<" server log _testEnumParameter" << _testEnumParameter << std::endl;
std::int32_t returnData = 101;
_reply(returnData);
}
void HelloWorldStubImpl::structInMethod(const std::shared_ptr<CommonAPI::ClientId> _client, v1::commonapi::HelloWorld::testStruct _structParameter, v1::commonapi::HelloWorldStub::structInMethodReply_t _reply)
{
std::cout << __FUNCTION__<<" server log _structParameter id" << _structParameter.getId() << std::endl;
std::cout << __FUNCTION__<<" server log _structParameter code" << _structParameter.getCode() << std::endl;
std::int32_t returnData = 102;
_reply(returnData);
}
void HelloWorldStubImpl::structOutMethod(const std::shared_ptr<CommonAPI::ClientId> _client, int32_t _input, v1::commonapi::HelloWorldStub::structOutMethodReply_t _reply)
{
std::cout << __FUNCTION__<<" server log _input" << _input << std::endl;
v1::commonapi::HelloWorld::testStruct returnStruct;
returnStruct.setId("returnData");
returnStruct.setCode(103);
_reply(returnStruct);
};
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
HelloWorldClient.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
#include <iostream>
#include <string>
#include <unistd.h>
#include <CommonAPI/CommonAPI.hpp>
#include <v1/commonapi/HelloWorldProxy.hpp>
using namespace v1::commonapi;
int main() {
std::shared_ptr < CommonAPI::Runtime > runtime = CommonAPI::Runtime::get();
std::shared_ptr<HelloWorldProxy<>> myProxy = runtime->buildProxy<HelloWorldProxy>("local", "shin");
std::cout << "Checking availability!" << std::endl;
while (!myProxy->isAvailable())
usleep(10);
std::cout << "Available..." << std::endl;
CommonAPI::CallStatus callStatus;
std::string returnMessage;
myProxy->sayHello("Bob", callStatus, returnMessage);
std::cout << "Got message: '" << returnMessage << "'\n";
std::int32_t intData = 3;
std::int32_t outputData;
myProxy->intDataMethod(intData,callStatus,outputData);//int형 데이터를 매개변수로 하는 함수 호출
std::cout << "Client Log!! outputData :" << outputData << std::endl;
HelloWorld::testEnum testenum = HelloWorld::testEnum::TEST_THIRD;
std::cout << "testenum:" << testenum << std::endl;
myProxy->enumMethod(testenum,callStatus,outputData);//enum 데이터를 매개변수로 하는 함수 호출
std::cout << "Client Log!! outputData :" << outputData << std::endl;
HelloWorld::testStruct teststruct;
teststruct.setId("input Data");
teststruct.setCode(12341234);
myProxy->structInMethod(teststruct,callStatus,outputData);//구조체 데이터를 매개변수로 하는 함수 호출
std::cout << "Client Log!! outputData: " << outputData << std::endl;
HelloWorld::testStruct outStruct;
std::int32_t test;
myProxy->structOutMethod(test,callStatus,outStruct);//구조체 데이터를 리턴 받는 함수 호출
std::cout << "Client Log!! outputData id: " << outStruct.getId() << std::endl;
std::cout << "Client Log!! outputData code: " << outStruct.getCode() << std::endl;
myProxy->getEnumBroadCastMethodEvent().subscribe([&](HelloWorld::testEnum value){
std::cout << "Client Log!! getEnumBroadCastMethodEvent value: " << value << std::endl;
});
while (true) {
std::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(30));
}
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
HelloWorldClient.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include <iostream>
#include <thread>
#include <CommonAPI/CommonAPI.hpp>
#include "HelloWorldStubImpl.hpp"
using namespace std;
int main() {
int i = 0;
std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
std::shared_ptr<HelloWorldStubImpl> myService = std::make_shared<HelloWorldStubImpl>();
if(runtime->registerService("local", "shin", myService)){
std::cout << "Service registered." << std::endl;
}else{
std::cout << "Service not registered." << std::endl;
}
std::cout << "Successfully Registered Service!" << std::endl;
while (true) {
std::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;
myService->fireEnumBroadCastMethodEvent(v1::commonapi::HelloWorld::testEnum::TEST_THIRD);
std::this_thread::sleep_for(std::chrono::seconds(30));
}
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
여기까지 commonapi를 사용해서 서버에서 broadcast이벤트를 날리고 클라이언트에서 이벤트를 받는 내용을
다루어 봤습니다.
다음 포스팅에는 제가 만든 ui프로그램에 commonapi를 포팅한 후에 서버와 클라이언트 연동하는 내용을 다루어
보겠습니다.
아직 직접 해보지는 않았지만 코드적으로는 거의 비슷한 내용일것 같고 라이브러리를 어떻게 자신의 프로젝트에
포팅을 시키느냐가 제일 관건일것 같은데 이내용을 중점으로 다음 포스팅에 준비하도록 하겠습니다.
여기까지 읽어주셔서 감사합니다.!!