Linux System V 메시지 큐 활용법

메시지 큐 개념

System V 메시지 큐는 프로세스 간 비동기 데이터 교환을 위한 IPC 메커니즘이다. 커널에서 관리하는 메시지 버퍼로, 송신 프로세스가 데이터를 큐에 넣으면 수신 프로세스가 순차적으로 내 사용한다. 현대 분산 아키텍처에서 활용되는 RabbitMQ, Kafka 등과 달리, System V 메시지 큐는 동일 시스템 내 프로세스 간 통신에 최적화되어 있다.

핵심 API 함수

msgget — 큐 생성 및 접근

int msgget(key_t key, int msgflg);
매개변수설명
key큐 식별 키값
msgflg권한 및 생성 플래그 (예: IPC_CREAT | 0644)

성공 시 큐 식별자(qid) 반환, 실패 시 -1

msgsnd — 메시지 전송

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

메시지 구조체는 다음 형식을 따른다:

struct msg_buffer {
    long mtype;      /* 반드시 양수 */
    char payload[];  /* 실제 데이터 */
};

msgrcv — 메시지 수신

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, 
               long msgtyp, int msgflg);
msgtyp 값동작
> 0해당 타입의 메시지 선택적 수신
== 0큐의 첫 번째 메시지 수신
< 0절댓값 이하의 최소 타입 메시지 수신

msgctl — 큐 제어 및 삭제

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

cmdIPC_RMID 지정 시 큐 제거

실전 예제

큐 생성

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>

#define PROJECT_KEY 0x5678

int main(void)
{
    int queue_id = msgget((key_t)PROJECT_KEY, IPC_CREAT | 0660);
    if (queue_id < 0) {
        perror("msgget failure");
        exit(EXIT_FAILURE);
    }
    
    printf("큐 생성 완료: ID = %d\n", queue_id);
    return 0;
}

메시지 송신

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/msg.h>

#define PROJECT_KEY 0x5678
#define BUFFER_SIZE 256

typedef struct {
    long category;
    char body[BUFFER_SIZE];
} packet;

int main(void)
{
    int qid = msgget((key_t)PROJECT_KEY, IPC_CREAT | 0660);
    if (qid < 0) {
        perror("msgget failure");
        exit(EXIT_FAILURE);
    }

    packet outgoing;
    outgoing.category = 10;
    strncpy(outgoing.body, "안녕하세요, 메시지 큐!", BUFFER_SIZE - 1);
    outgoing.body[BUFFER_SIZE - 1] = '\0';

    if (msgsnd(qid, &outgoing, sizeof(packet) - sizeof(long), 0) == -1) {
        perror("msgsnd failure");
        exit(EXIT_FAILURE);
    }

    printf("전송 완료: [%ld] %s\n", outgoing.category, outgoing.body);
    return 0;
}

메시지 수신

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>

#define PROJECT_KEY 0x5678
#define BUFFER_SIZE 256

typedef struct {
    long category;
    char body[BUFFER_SIZE];
} packet;

int main(void)
{
    int qid = msgget((key_t)PROJECT_KEY, IPC_CREAT | 0660);
    if (qid < 0) {
        perror("msgget failure");
        exit(EXIT_FAILURE);
    }

    packet incoming;
    
    /* 카테고리 10번 메시지 대기 수신 */
    ssize_t received = msgrcv(qid, &incoming, 
                              sizeof(packet) - sizeof(long), 
                              10, 0);
    if (received < 0) {
        perror("msgrcv failure");
        exit(EXIT_FAILURE);
    }

    printf("수신 완료: [%ld] %s (바이트: %zd)\n", 
           incoming.category, incoming.body, received);
    return 0;
}

비차단 수신 및 큐 정리

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/msg.h>

#define PROJECT_KEY 0x5678
#define BUFFER_SIZE 256

typedef struct {
    long category;
    char body[BUFFER_SIZE];
} packet;

int main(void)
{
    int qid = msgget((key_t)PROJECT_KEY, IPC_CREAT | 0660);
    if (qid < 0) {
        perror("msgget failure");
        exit(EXIT_FAILURE);
    }

    packet incoming;
    
    /* IPC_NOWAIT: 즉시 반환, 메시지 없으면 EAGAIN */
    ssize_t received = msgrcv(qid, &incoming,
                              sizeof(packet) - sizeof(long),
                              10, IPC_NOWAIT);
    
    if (received < 0) {
        if (errno == ENOMSG) {
            printf("큐에 수신할 메시지 없음\n");
        } else {
            perror("msgrcv failure");
        }
    } else {
        printf("수신: %s\n", incoming.body);
    }

    /* 큐 완전 제거 */
    if (msgctl(qid, IPC_RMID, NULL) == -1) {
        perror("msgctl failure");
        exit(EXIT_FAILURE);
    }
    
    printf("큐 삭제 완료\n");
    return 0;
}

상태 확인 및 관리

명령어기능
ipcs -q메시지 큐 목록 조회
ipcrm -q <id>특정 큐 강제 삭제
ipcs -qa상세 정보 확인

주의사항

  • 메시지 타입은 반드시 양수(0 제외) 사용
  • 수신 버퍼 크기는 sizeof(long) 제외한 데이터 영역만 계산
  • 프로세스 종료 후에도 큐는 커널에 남아있으므로 명시적 삭제 필요
  • IPC_NOWAIT 미설정 시 큐가 비어있으면 수신 프로세스 블로킹

태그: System V IPC msgget msgsnd msgrcv msgctl

7월 30일 22:19에 게시됨