[ZeroMQ] send-recv (TPC, IPC) 메시징 전송 속도 테스트 Develop Tip

ZeroMQ를 이용하면 아주 쉽게 프로세스간 또는 다른 호스트에 있는 프로세스 간에 메시지를 주고 받을 수 있습니다.
궁금한 것은 과연 ZeroMQ를 이용하면 어느 정도의 메시징 속도가 나올 수 있는가 였습니다.

아주 쉬운 send, recv 프로그램을 작성해 보았습니다.

우선 메시지를 받고 있는 서버 역할의 recv.cpp를 보면,

recv.cpp

#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <zmq.h>
#define ZMQ_IPC_CONNSTR "ipc:///tmp/sendrecv.zmq"
#define ZMQ_TCP_CONNSTR "tcp://127.0.0.1:56789"

//========================================================================================
bool g_break;

//========================================================================================
void sig_handler(int signo)
{
    g_break = true;
}

//========================================================================================
int recv_loop(bool verbose=false)
{
    char buffer[1024*10];

    void *context = zmq_ctx_new ();
    void *responder = zmq_socket (context, ZMQ_REP);
    char send_buff[256];

//    int rc = zmq_bind (responder, ZMQ_IPC_CONNSTR);
    int rc = zmq_bind (responder, ZMQ_TCP_CONNSTR);

    int cnt = 0;
    while(!g_break) {
        cnt++;
        zmq_recv (responder, buffer, sizeof(buffer), 0);
        if (verbose)
            printf("recv=<%s>\n", buffer);
        /*** doing something with buffer ***/
        sprintf(send_buff, "%d", cnt);
        zmq_send (responder, send_buff, strlen(send_buff), 0);
    }

    return 0;
}

//========================================================================================
main()
{
    if (signal(SIGINT, sig_handler) == SIG_ERR) {
        fprintf(stderr, "\ncan't catch SIGINT\n");
    }
    if (signal(SIGTERM, sig_handler) == SIG_ERR) {
        fprintf(stderr, "\ncan't catch SIGTERM\n");
    }
    g_break = false;
//    recv_loop(true);
    recv_loop();
}



그 다음은, 메시지를 주는 것의 client 역할의 send.cpp 입니다.

send.cpp

#include <string.h>
#include <stdlib.h>
#include <string>
#include <zmq.h>
#define ZMQ_IPC_CONNSTR "ipc:///tmp/sendrecv.zmq"
#define ZMQ_TCP_CONNSTR "tcp://127.0.0.1:56789"

//========================================================================================
//  Convert C string to 0MQ string and send to socket
int _send (void *socket, char *string)
{
    zmq_msg_t message;
    zmq_msg_init_size (&message, strlen (string));
    memcpy (zmq_msg_data (&message), string, strlen (string));
    int size = zmq_msg_send (&message, socket, 0);
    zmq_msg_close (&message);
    return (size);
}
//========================================================================================
//  Receive 0MQ string from socket and convert into C string
const char * _recv (void *socket)
{
    static std::string zmq_str;
    zmq_msg_t message;
    zmq_msg_init (&message);
    int size = zmq_msg_recv (&message, socket, 0);
    if (size == -1)
        return NULL;
    char *string = (char*)malloc(size + 1);
    memcpy (string, zmq_msg_data (&message), size); zmq_msg_close (&message);
    string[size] = '\0';
    zmq_str = string;
    free(string);
    return zmq_str.c_str();
}
//========================================================================================
void send_loop(int limit=1000000, bool verbose=false)
{
    char send_msg[4096];
    void *context = zmq_ctx_new ();
    void *zmqcxt = zmq_socket (context, ZMQ_REQ);

//    zmq_connect (zmqcxt, ZMQ_IPC_CONNSTR);
    zmq_connect (zmqcxt, ZMQ_TCP_CONNSTR);

    for (int i = 0; i < limit; ++i) {
        sprintf(send_msg, "[%010d]%s", i,
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
        );
        _send(zmqcxt, send_msg);
        const char *recv_msg = _recv(zmqcxt);
        if (verbose)
            printf("[%010d] recv=%s\n", i, recv_msg);
    }

    zmq_close(zmqcxt);
    zmq_ctx_destroy (context);
}

//========================================================================================
int main()
{
//    send_loop(10,true);
    send_loop(100000);
}


그리고 다음은 Makefile 입니다.

CC=gcc
CPP=g++

CLEANFILES    = $(TGT1_OBJ) $(TARGET1)
MY_CFLAGS    = $(DEBUG) $(PROF) $(CFLAGS) -Wno-unused-result


TARGET1 = send
TGT1_SRC = send.cpp
TGT1_OBJ = ${TGT1_SRC:.cpp=.o}

TARGET2 = recv
TGT2_SRC = recv.cpp
TGT2_OBJ = ${TGT2_SRC:.cpp=.o}

.c.o:
    $(CC) $(MY_CFLAGS) -c $<

.cpp.o:
    $(CPP) $(MY_CFLAGS) -c $<


all: $(TARGET1) $(TARGET2)

$(TARGET1):    $(TGT1_OBJ)
    $(CPP) $(DEBUG) $(PROF) -o $(TARGET1) $(TGT1_OBJ) $(LFLAGS) \
        -lpthread -lzmq

$(TARGET2):    $(TGT2_OBJ)
    $(CPP) $(DEBUG) $(PROF) -o $(TARGET2) $(TGT2_OBJ) $(LFLAGS) \
        -lpthread -lzmq

clean:
    @rm -f $(TARGET1) $(TARGET2) *.o


위에서
    int rc = zmq_bind (responder, ZMQ_TCP_CONNSTR);
대신
    int rc = zmq_bind (responder, ZMQ_IPC_CONNSTR);
를 이용하면 TCP 대신 한 호스트내의 프로세스간 메시징 통신을 하게 됩니다.

recv 를 다른 터미널에서 기동시키고,
다른 터미널에서 send를 돌려보았습니다.

IPC를 기동시키면

300바이트 10줄의 메시지를 10만번 호출하고 결과를 받는데
2.5초 ~ 4.1초 정도 걸렸고,

TCP를 이용하면
3.8초 ~ 6.4초 정도 걸렸습니다.


어느 분께는 도움이 되셨기를...

덧글

  • ㅎㅇ 2017/09/30 23:23 # 삭제 답글

    많은 도움이 되었습니다. 감사합니다!!
  • 지훈현서아빠 2017/10/04 16:43 #

    도움이 되셨다니 저의 보람입니다~
댓글 입력 영역

구글애드텍스트