메시지 큐
-
운영체제는
IPC
를 위해서 메시지 큐라는 객체를 제공한다. 메시지 큐는 말 그대로 큐라는 자료 구조로 구성되어 있다. -
메시지 큐는 운영체제가 관리하는 별도의 객체로서 따라서 프로세스 A에서 프로세스 B에게 메시지를 전달하고자 프로세스 A에서 메시지 큐에 데이터를 복사하는 과정, 프로세스 B가 메시지 큐에서 데이터를 읽어오는 과정을 거쳐서 통신이 가능하다.
-
공유 메모리를 설명했을 때와 유사한 순서로 메시지 큐의 생성, 메시지 큐의 타입 설정, 데이터 읽기, 데이터 쓰기의 과정에 관여하는 함수에 대해서 알아볼 것이다.
-
메시지 큐를 사용하기 위해서는
mq_open()
함수를 통해서 기존에 존재하는 메시지 큐에 접근할 수 있는 디스크립터를 얻어오거나 새로운 메시지 큐를 생성한 후에 생성된 메시지 큐에 접근할 수 있는 디스크립터를 얻어야한다.
// oflag에 O_CREAT가 명시된 경우
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
// oflag에 O_CREAT가 명시되지 않은 경우
mqd_t mq_open(const char *name, int oflag);
-
name: 메시지 큐 객체를 지칭하기 위한 이름
-
oflag: 생성되는 메시지 큐의 특성 정의(공유 메모리의 oflag와 유사함)
-
mode: 생성되는 메시지 큐 객체의 퍼미션
-
attr: 생성되는 메시지 큐 객체의 속성
-
oflag
,mode
는 공유 메모리와 세마포어 함수의open
함수에서 사용되는 인자와 비슷한 성격을 가진다.
struct mq_attr {
long mq_flags; // 메시지 큐의 블록, 논블록 설정 여부
long mq_maxmsg; // 메시지 큐에 저장될 수 있는 메시지의 최대 수
long mq_msgsize; // 메시지의 최대 사이즈 (바이트)
long mq_curmsgs; // 메시지 큐에 들어있는 메시지의 수
}
mq_attr
구조체는 생성되는 메시지 큐의 속성을 지정하기 위해서 사용되며 다음과 같이 정의된다.
int mq_getattr(mqd_t mqd, struct mq_attr *attr);
-
mqd: 속성값을 얻어오려고 하는 메시지 큐를 지칭하는 디스크립터
-
attr: 속성값을 저장하기 위한
mq_attr
구조체 -
메시지 큐의 속성 정보는
mq_getattr
함수를 사용하여 조회할 수 있다.
int mq_send(mqd_t mqd, const char *ptr, size_t len, unsigned int prio);
-
mqd: 접근할 메시지 큐를 지정하기 위한 디스크립터
-
ptr: 전송할 데이터의 시작 지점을 가리키는 포인터
-
len: 전송할 데이터의 길이를 나타내는 매개변수
-
prio: 메시지의 우선순위를 나타내는 매개변수
-
메시지 큐에 보내야 하는 데이터를 삽입하는 함수는
mq_send
이다.
ssize_t mq_receive(mqd_t mqd, char *ptr, size_t len, unsigned int *prio);
-
mqd: 접근할 메시지 큐를 지정하기 위한 디스크립터
-
ptr: 전송받는 데이터의 시작 시점을 가리키는 포인터
-
len: 전송받는 데이터의 길이를 나타내는 매개변수
-
prio: 메시지의 우선순위를 나타내는 매개변수
-
반면 메시지 큐에서 데이터를 읽어오는 함수는
mq_receive
함수이다.
예제
- 부모와 자식 프로세스 사이에서 간단한 문자열을 전송하는 프로그램을 작성해보자.
- 프로그램은 자식 프로세스를 하나 생성한다.
- 자식 프로세스는 사용자에게 문자열을 입력 받은 후에 메시지 큐를 이용하여 부모 프로세스에게 전송한다.
- 부모 프로세스는 화면에 전송받은 문자열을 출력한다.
#include <stdio.h>
#include <mqueue.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define MQ_NAME "/test_mq"
int main(int argc, char **argv)
{
mqd_t mqfd;
int pid;
unsigned int priority = 10;
char send_buff[50];
void *read_buff;
int read_len;
struct mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 10;
mqfd = mq_open(MQ_NAME, O_CREAT|O_RDWR, 644, &attr);
if (mqfd == (mqd_t)-1)
{
perror("mq_open failure from main");
printf("Errno = %d\n",errno);
exit(0);
}
pid = fork();
if (pid == 0) {
printf("child: ");
scanf("%s", send_buff);
if (mq_send(mqfd, send_buff, strlen(send_buff), priority) == -1) {
fprintf(stderr, "MQ SEND ERROR\n");
exit(1);
}
} else if (pid < 0) {
fprintf(stderr, "FORK FAILURE\n");
exit(1);
} else {
if (mq_getattr(mqfd, &attr) == -1) {
fprintf(stderr, "MQ_GET_ATTR ERROR \n");
exit(1);
}
read_buff = malloc(attr.mq_msgsize);
read_len = mq_receive(mqfd, read_buff, attr.mq_msgsize, &priority);
printf("parent receives: %s\n", (char*)read_buff);
}
return 0;
}
-
정상적으로 자식 프로세스에서 보낸 문자열이 부모 프로세스로 전달된 것을 확인할 수 있다.
-
한가지 주의할 점은
struct mq_attr
구조체의 값을 설정할 때 현재 시스템에서 허용 가능한 값이 정해져있으므로 시스템에서 정한 값을 넘지 않도록 주의해야한다. -
시스템 설정값은
/proc/sys/fs/mqueue/
위치에 있다.
참고 문헌
>> Home