메시지 큐 개념
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);
cmd에 IPC_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미설정 시 큐가 비어있으면 수신 프로세스 블로킹