ZeroMQ 는 고성능 오픈소스 메시징 라이브러리이다. ZeroMQ는 다양한 메시징 패턴을 제공하며 이 팬턴들의 조합으로 다양한 서비스를 구축할 수 있다. 프로세스 내, 프로세스 간, TCP, 멀티캐스트를 포함한 다양한 전송과 함께 작동한다.
Qt기반의 간단한 서버와 클라이언트 프로그램간 통신을 ZeroMQ의 REQ 및 REP 모델을 이용하여 구축해본다. 하나의 요청에 하나의 응답이 이어진다. IP 주소와 포트를 제공하고 장치가 서버(응답 측) 또는 클라이언트(요청 측)인지 결정하기만 하면 된다.
C++ 를 위한 헤더전용 바인딩을 사용한다. 가장 먼저 할일은 헤더파일을 포함하는 것이다.
#include <zmq.hpp>
ZeroMQ 는 필수적인 객체를 생성함으로써 시작할 수 있다. 다음은 컨텍스트와 소켓을 생성하는 부분이다. 서버 측은 응답을 수행하므로 소켓 생성 시 플래그socket_type::rep
를 설정한다.
using namespace zmq;
auto context = std::make_unique<context_t>();
auto socket = std::make_unique<socket_t>(*context.get(), socket_type::rep);
서버 측 IP 및 포트를 바인딩한다. 피어가 바인딩된 소켓에 연결할 때 대기열이 생성된다.
socket->bind("tcp://*:5570");
QTimer::singleShot(0, &worker, &Worker::loop);
서버 측과 다르게 클라이언트 측은 간단한 UI를 사용자에게 제공한다.
사용자가 메세지를 입력하고 Send 버튼을 클릭하면 서버에 메지시를 보낼 것이다.
컨텍스트와 소켓을 생성하는 부분은 기본적으로 서버 측과 같지만 여기서는 REQ 플래그socket_type::req
로 설정했다는 점이 다르다.
auto context = std::make_unique<context_t>();
auto socket = std::make_unique<socket_t>(*context.get(), socket_type::req);
서버에 연결한다.
socket->connect("tcp://localhost:5570");
Send버튼을 클릭하면 메세지를 보내고 Message Loop를 시작한다.
QString msg = ui->lineEdit->text();
socket->send(message_t(msg.toUtf8()), send_flags::dontwait);
QTimer::singleShot(0, this, &MainWindow::loop); // Start Message Loop
간단한 폴링을 구현한다. 기본 구현은 요청 및 응답 측 모두에 적용된다. 다음은 간단히 구현한 서버 측 예제이며 수신한 메세지에 "you say " 를 더하여 클라이언트에 다시 보낸다.
void loop(){
message_t msg;
socket->recv(msg, recv_flags::dontwait); // 여기서 기다리지 않음.
size_t size = msg.size();
if (size) {
auto message = QString::fromStdString(std::string(reinterpret_cast<char*>(msg.data()), msg.size()));
qDebug() << message;
auto echo = "you say " + message;
socket->send(message_t(echo.toUtf8()), send_flags::dontwait);
}
QTimer::singleShot(100, this, &Worker::loop); // 반복
}
서버와 클라이언트를 빌드하고 실행한 후 클라이언트에서 메세지를 보내본다.
ZeroMQ를 사용하여 간단하게 Qt 응용프로그램 간 통신을 해보았다. 다만 이것은 아주 단순한 형태의 테스트일 뿐이다. 어느정도 규모가 있거나 복잡한 프로젝트에는 적절하지 않을 수 있다.
이런 경우 Qt 응용프로그램을 위한 ZeroMQ 바인딩이 어느 정도 도움이 될 수 있다.