[C++,QT/Qml]33.Qt 프로세스간의 통신(IPC) 구현하기2(commonapi를 이용한 프로세스간 통신 구현,구조체를 이용한 통신)
안녕하세요 고급 프로그래머가 꿈인 코린이 입니다.
오늘은 commonapi를 이용한 dbus통신 방법중에 method콜이 아닌 broadcast나 struct형식의 데이터들을 넘기는
방법에 대해서 포스팅 하겠습니다.
struct형식의 데이터는 프로세스가 통신할때 가장 많이 사용하는 데이터 중에 입니다.
왜냐하면 프로세스간 통신할때 데이터들이 한가지만 있는경우가 그렇게 많지 않고 한번에 많은 데이터들을 담아서 주는
경우가 많기때문에 struct형식을 선호하는 편입니다.
하지만 현재 genivi에서 제공하는 예제 코드에는 string형식의 데이터들만 호출할수 있고 struct형식에 대해서는
따로 설명되어 있지 않아서 struct형식으로 보내거나 받을때는어떻게 해야할지 감이 안잡힙니다.
그래서 오늘은 struct형식과 int형식 데이터 및 enum값 데이터를 이용해서 함수호출하는 방법에 대해서 다루어 보겠습니다.
1. int형 데이터를 매개변수로 넣고 호출하는 함수
각 데이터형들을 호출하는 함수는 dbus및 commonapi generator에서 자동으로 만들어 줍니다.
그렇기 때문에 각 데이터 형들을 fidl에 선언하는 방법이 가장 중요한데요
int 형 데이터를 매개변수로 호출하는 함수의 fidl선언 하는 방법을 먼저 보겠습니다.
1
2
3
4
5
6
7
8
9
|
method intDataMethod{
in {
Int32 parameter
}
out {
Int32 output
}
}
|
server code
서버에서는 아래의 intDataMethod라는 함수를 상속 받아서 int형 매개변수를 받았을때 동작하는 내용과
리턴할 내용을 선언할수 있습니다. 리턴될 내용은 숫자 100입니다.
1
2
3
4
5
6
7
|
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);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
Client code
클라이언트 소스코드에는 아래와 같이 fidl에서 선언해준 함수를 이용해서 int형 변수를 호출하고 리턴받을
int형 변수를 넣어주어서 리턴받는 내용을 받을수 있게 해주고 아래처럼 로그로 리턴받은 변수를 출력해 줍니다.
1
2
3
4
5
|
std::int32_t intData = 3;
std::int32_t outputData;
myProxy->intDataMethod(intData,callStatus,outputData);//int형 데이터를 매개변수로 하는 함수 호출
std::cout << "Client Log!! outputData:" << outputData << std::endl;
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
2. enum값 데이터를 매개변수로 넣고 호출하는 함수
이번에는 c++에서 많이 사용하는 enum값을 이용해서 함수를 호출하는 방법입니다.
enum값을 아래와 같이 fidl에 선언해 줍니다.
그리고 그 enum값을 사용해서 호출할 함수를 선언해 줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
enumeration testEnum{
TEST_FIRST
TEST_SECOND
TEST_THIRD
}
method enumMethod{
in {
testEnum testEnumParameter
}
out {
Int32 output
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
server Code
서버코드도 위의 int형 함수와 같이 함수를 상속 받아서 그에 따른 동작을 함수에 구현 해주면 됩니다.
아래와 같이 받은 enum값을 출력해주고 숫자 101을 리턴해 줍니다.
1
2
3
4
5
6
7
|
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);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
client 코드
클라이언트 쪽 코드도 generator로 만들어진 fidl에 선언한 함수를 아래와 같이 호출해 주면 됩니다.
enum값은 fidl에 선언하였으므로 namespace를 HelloWorl의 testEnum 값으로 설정 해주고 아래와 같이 알맞는
enum값을 설정해주고 함수를 호출해 주면 됩니다.
1
2
3
4
5
|
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;
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
3. 구조체 변수를 매개변수로 넣고 호출하는 함수
이번에는 구조체 변수를 매개변수로 넣기 위해서 fidl에 아래와 같이 구조체를 선언해 줍니다.
그리고 아래와 같이 구조체를 매개변수로 넣을 함수를 선언해 줍니다.
매개변수에 구조체를 넣어줄 예정이라 in부분에 구조체 변수를 넣어주었습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
struct testStruct {
Int32 code
String id
}
method structInMethod{
in {
testStruct structParameter
}
out {
Int32 output
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
server Code
여태까지 해왔던 내용 처럼 fidl에 선언해준 함수를 상속을 받아서 그에 대한 로직을 구현해 줍니다.
저는 아래와 같이 구조체로 받은 데이터들을 출력하고 int형 변수를 리턴하는 함수로 구현 했습니다.
여기서 중요한 점은 각 구조체는 commonapi 및 dbus generator에서 get및 set을 할수 있도록 getter와 setter를
지원해 줍니다.
그렇기 때문에 각 구조체 값의 데이터를 set하거나 get하실때는 아래과 같이 getId() 처럼 값을 가져올수도 있고
setId함수를 통해서 구조체값을 설정할수가 있습니다.
1
2
3
4
5
6
7
8
|
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);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
Client Code
클라이언트쪽 코드에서는 아개와 같이 구조체를 선언해주고 구조체에 setter를 통해서 id값과 code값을
넣어주고 함수를 호출했습니다.
그리고 리턴받은 데이터를 출력하도록 구현 했습니다.
1
2
3
4
5
6
|
HelloWorld::testStruct teststruct;
teststruct.setId("input Data");
teststruct.setCode(12341234);
myProxy->structInMethod(teststruct,callStatus,outputData);//구조체 데이터를 매개변수로 하는 함수 호출
std::cout << "Client Log!! outputData:" << outputData << std::endl;
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
4. 구조체 데이터를 리턴받는 함수
구조체 데이터를 리턴 받기위해서 위의 구조체 데이터를 넣는것과 반대로 out에 구조체로 받을 데이터 변수를
설정해 줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
struct testStruct {
Int32 code
String id
}
method structOutMethod{
in {
Int32 input
}
out {
testStruct structParameter
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
server Code
위의 내용들과 마찬가지로 generator로 만들어진 함수를 상속 받아줍니다. 그리고 int형 데이터를 받아서 로그로 출력해
주고 구조체 데이터들을 설정한 후에 리턴해주는 내용을 구현하였습니다.
1
2
3
4
5
6
7
8
9
|
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
|
Client Code
클라이언트쪽 코드는 int형 데이터를 매개변수로 넣어주고 구조체형 데이터를 리턴받기위해서 구조체를 넣어준 후
받는 구조체 데이터들을 로그로 출력해 주도록 구현하였습니다.
1
2
3
4
5
6
|
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;
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
여기까지 구조체 데이터,enum 데이터,int형 데이터들을 fidl에 선언해주고 호출하는 방법을 다루어 보았습니다.
아래 내용에 전체 소스코드를 보여드릴테니 fidl을 어떻게 선언했는지 각 함수들을 어떻게 선언하고 리턴했는지를
확인해주시면 될것 같습니다
먼저 실행 이미지를 보겠습니다.
Server 실행 이미지
아래는 서버 실행 로그 입니다.
각 받은 데이터들을 출력하도록 로그를 넣어 두었습니다.
Client 실행 이미지
아래는 클라이언트 실행 로그 입니다.
서버에서 리턴받은 데이터들을 출력하도록 구현 하였습니다.
그리고 아래는 전체 소스코드 입니다.
Hellowordl.fidl
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
|
package commonapi
interface HelloWorld {
version {major 1 minor 0}
enumeration testEnum{
TEST_FIRST
TEST_SECOND
TEST_THIRD
}
struct testStruct {
Int32 code
String id
}
method sayHello {
in {
String name
}
out {
String message
}
}
method intDataMethod{
in {
Int32 parameter
}
out {
Int32 output
}
}
method enumMethod{
in {
testEnum testEnumParameter
}
out {
Int32 output
}
}
method structInMethod{
in {
testStruct structParameter
}
out {
Int32 output
}
}
method structOutMethod{
in {
Int32 input
}
out {
testStruct structParameter
}
}
}
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
|
#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;
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
HelloworldServer.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
|
#include <iostream>
#include <thread>
#include <CommonAPI/CommonAPI.hpp>
#include "HelloWorldStubImpl.hpp"
using namespace std;
int main() {
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;
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
|
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
|
여기까지 전체 소스코드 였습니다.
위의 fidl을 잘 살펴 보시고 어떻게 선언하고 소스코드상에서는 어떻게 구현 했는지를 중점적으로 보시기 바랍니다.
다음 포스팅에서는 함수 호출이 아닌 broadcast를 이용한 출력 내용을 다루어 보겠습니다.
여기 까지 읽어주셔서 감사합니다!!
'QT and QML' 카테고리의 다른 글
[C++,QT/Qml]35.Qt 프로세스간의 통신(IPC) 구현하기4(나의 qt프로젝트에 commonapi 라이브러리 포팅하기) (0) | 2019.12.29 |
---|---|
[C++,QT/Qml]34.Qt 프로세스간의 통신(IPC) 구현하기3(commonapi를 이용한 프로세스간 통신 구현) (0) | 2019.12.28 |
[C++,QT/Qml]32.Qt 프로세스간의 통신(IPC) 구현하기1(commonapi를 이용한 프로세스간 통신 구현) (5) | 2019.12.07 |
[C++,QT/Qml]31.QML 위치 지정 속성(두개의 텍스트를 항상 가운데 정렬 하기) (0) | 2019.11.23 |
[C++,QT/Qml]30.QML 위치 지정 속성(anchors) (2) | 2019.11.09 |