Message Queue
•
IPC기법 중 하나로 Data Structure 중 Queue를 사용
•
기본적으로 선입선출
•
Message Queue의 msgtype에 따라 메시지의 순서를 변경
•
Message는 Kernel에서 보관, 프로세스가 종료되어도 소멸되지 않음
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 V의 Message Queue의 id를 할당받음
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 Queue의 id
2.
const void *msgp
msgp는 void*이지만 아래의 구조체 형식으로 정의가 필요
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 Queue의 id
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 Queue의 id
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
복사