Home
System Hacking
🎟️

메시지 큐(MESSAGE QUEUE)란

Type
운영체제
날짜
2025/10/21
종류
libc
Kernel
msg
1 more property

Message Queue

IPC기법 중 하나로 Data Structure 중 Queue를 사용
기본적으로 선입선출
Message Queuemsgtype에 따라 메시지의 순서를 변경
MessageKernel에서 보관, 프로세스가 종료되어도 소멸되지 않음

Message Queue 종류

1.
System V의 Message Queue
2.
POSIX의 Message Queue
System V: 옛날 유닉스 방식 POSIX: 지금의 Linux 방식
해당 글의 내용은 System V에서 Message Queue 활용

Header File

Message Queue를 사용하기 위해 아래의 헤더 파일이 필요
#include <sys/msg.h> #include <sys/ipc.h> #include <sys/types.h>
C
복사

msgget

System VMessage Queueid를 할당받음
int msgget (key_t key, int msgflg) { #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS return INLINE_SYSCALL_CALL (msgget, key, msgflg); #else return INLINE_SYSCALL_CALL (ipc, IPCOP_msgget, key, msgflg, 0, NULL); #endif }
C
복사
1.
key_t key
Message Queue를 얻어올 때 사용하는 고유 key
2.
int msgfla
2가지가 존재
a.
IPC_CREAT : Message Queue가 없으면 새로 생성
b.
IPC_EXCL : IPC_CREAT와 같이 사용하는 flag, 만약 Message Queue가 존재하면 msgget은 error return

msgsnd

Message Queue메시지 전송
int __libc_msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) { #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS return SYSCALL_CANCEL (msgsnd, msqid, msgp, msgsz, msgflg); #else return SYSCALL_CANCEL (ipc, IPCOP_msgsnd, msqid, msgsz, msgflg, msgp); #endif } weak_alias (__libc_msgsnd, msgsnd)
C
복사
1.
int msqid
Message Queueid
2.
const void *msgp
msgpvoid*이지만 아래의 구조체 형식으로 정의가 필요
struct msg { long mtype; /* message type, must be > 0 */ char mtext[BUF_SIZE]; /* message data */ };
C
복사
mtype
Message Type을 나타냄, 이 값은 0보다 커야함, Message Queue의 msgbuf를 정의할 때 long형의 mtype을 반드시 명시
mtext
Message Queue에 보낼 데이터
3.
size_t msgsz
msgsz는 Message Queue에 전송할 데이터 사이즈, 위 mtext의 배열 크기를 전달
4.
int msgfla
몇몇 주요 flag
0(default) : 큐가 꽉 차면 대기
IPC_NOWAIT : 큐가 꽉 차면 에러
MSG_NOERROR : 너무 크면 잘라서 전송

msqid_ds

msgsnd가 성공적으로 동작하면 msqid_ds라는 구조체 필드 값이 변경
struct msqid_ds { struct ipc_perm msg_perm; /* structure describing operation permission */ __time_t msg_stime; /* time of last msgsnd command */ __time_t msg_rtime; /* time of last msgrcv command */ __time_t msg_ctime; /* time of last change */ msgqnum_t msg_qnum; /* number of messages currently on queue */ msglen_t msg_qbytes; /* max number of bytes allowed on queue */ __pid_t msg_lspid; /* pid of last msgsnd() */ __pid_t msg_lrpid; /* pid of last msgrcv() */ };
C
복사
해당 구조체는 Message Queue의 메타데이터 같은 것이며, 아래와 같이 변경
1.
msg_lspid는 호출된 process id로 변경
2.
msg_qnum의 값 1증가
3.
msg_stime을 현재 시간으로 설정

msgrcv

Message Queue에 존재하는 메시지 수신
ssize_t __libc_msgrcv (int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg) { #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS return SYSCALL_CANCEL (msgrcv, msqid, msgp, msgsz, msgtyp, msgflg); #else return SYSCALL_CANCEL (ipc, IPCOP_msgrcv, msqid, msgsz, msgflg, MSGRCV_ARGS (msgp, msgtyp)); #endif } weak_alias (__libc_msgrcv, msgrcv)
C
복사
1.
int msqid
Message Queueid
2.
void *msgp
메시지를 저장하는 메모리 주소
3.
size_t msgsz
메시지를 읽을 크기, 만약 읽어들인 메시지가 저장된 크기보다 크다면 msgflg에 따라 동작
4.
long int msgtyp
a.
msgtyp == 0
큐의 첫번째 메시지를 읽음
b.
msgtyp > 0
그 값과 동일한 message type을 갖는 메시지를 반환
c.
msgtyp < 0
msgtyp의 절대값 이해의 가장 작은 메시지를 읽음
5.
int msgflg
4개 정도가 존재
a.
IPC_NOWAIT
b.
MSG_COPY
c.
MSG_EXCEPT
d.
MSG_NOERROR

msgctl

Message Queue를 제어
static int msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf) { #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf); #else return INLINE_SYSCALL_CALL (ipc, IPCOP_msgctl, msqid, cmd | __IPC_64, 0, buf); #endif }
C
복사
1.
msqid
Message Queueid
2.
cmd
제어할 command 대표적으로 3개가 존재
a.
IPC_STAT
buf로 Message Queue 정보를 읽기
b.
IPC_SET
buf로 Message Queue 정보를 설정
c.
IPC_RMID
Message Queue를 제거
3.
buf
위에서 설명했던 구조체,cmd로 IP_STAT와 IPC_SET을 사용할 때 전달, 없을 경우 NULL 전달

Example

msgq.c

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/types.h> #include <unistd.h> struct data{ int age; char name[0x10]; }; struct message{ long msg_type; struct data data; }; int main(){ key_t key=1; int msqid; struct message msg; msg.msg_type=1; msg.data.age=26; strcpy(msg.data.name,"JANGJONGMIN"); // 메시지 큐 생성 msqid = msgget(key, IPC_CREAT | 0666); if (msqid == -1) { perror("msgget"); exit(1); } // 송신 if(msgsnd(msqid,&msg,sizeof(struct data),0)==-1){ printf("msgsnd failed\n"); exit(0); } printf("Send Name: %s\n", msg.data.name); printf("Send Age: %d\n", msg.data.age); // Clear memset(&msg.data, 0, sizeof(struct data)); printf("msg Name: %s\n", msg.data.name); printf("msg Age: %d\n", msg.data.age); // 수신 if (msgrcv(msqid, &msg, sizeof(struct data), 1, 0) == -1) { perror("msgrcv"); exit(1); } printf("Received Name: %s\n", msg.data.name); printf("Received Age: %d\n", msg.data.age); return 1; }
C
복사