C언어 메시지 큐 생성 함수 msgget()

2020. 3. 16. 08:02 컴퓨터/프로그래밍

C함수 메시지 큐 생성 msgget()

메시지 큐를 생성합니다.

  • 헤더: sys/types.h, sys/ipc.h, sys/msg.h
  • 형태: int msgget ( key_t key, int msgflg )
  • 인수: key_t key 시스템에서 다른 큐와 구별되는 번호
    int msgflg 옵션
  • 반환: -1 == 실패, 이외는 메시지 큐 식별자

메시지 큐는 IPC 방법 중에 하나로 자료를 다른 프로세스로 전송할 수 있습니다. 전송되는 자료도 큐의 용량이 허용하는 한, 상대편이 가져가지 않는다고 하더라도 계속 전송할 수 있으며, 나중에 다른 프로세스가 큐가 비워질 때까지 계속 읽어 들일 수 있습니다.

또한 메시지 큐는 전송한는 자료를 커널이 간직하기 때문에 전송한 프로세스가 종료되었다고 하더라고 자료가 사라지지 않습니다. 즉, 전송 프로세스가 데이터를 전송한 후 종료해도, 나중에 다른 프로세스가 메시지 큐의 데이터를 가져 올 수 있습니다.

또한 전송되는 큐의 자료는 순자적으로 가져 갈 수도 있지만 데이터 타입에 따라 원하는 자료만 가져 갈 수 있습니다. 즉, 메시지 큐에 전송되는 데이터 구조는 아래와 같습니다.

struct {
   long  data_type;
   char  data_buff[BUFF_SIZE];
}

또는,

struct {
   long  data_type;
   int   data_num;
   char  data_buff[BUFF_SIZE];
}

또는,

struct {
   long  data_type;
   int   data_num;
}

이런 식으로 구성할 수 있습니다. 즉, 데이터 타입을 나타내는 long 값을 첫번째로 놓는다면 이후의 구조는 자유롭게 구성할 수 있다는 것입니다.

그리고 나중에 자료를 수신하는 쪽은 data_type 값 중에 특정 값으로 설정된 자료만 뽑아서 가져갈 수 있으면, 가져간 자료는 당연이 메시지 큐에서 제거됩니다.

예제에서는 data_type 2 인 것만 뽑아 가다가 나중에는 모든 데이터를 가져가는 방법을 보여 주고 있습니다.

msgget()은 이와 같은 메시지 큐를 생성합니다.

int msgget ( key_t key, int msgflg )

key_t key는 다른 큐와 구별하기 위한 번호입니다. 큐에 대한 번호를 알고 있다면 알고 있는 프로세스끼리 같은 번호의 큐를 사용할 수 있습니다.

int msgflg는 메시지 큐를 만들기 위한 옵션으로 아래와 같은 값을 사용할 수 있습니다.

msgflg 의미
IPC_CREAT key에 해당하는 큐가 있다면 큐의 식별자를 반환하며, 없으면 생성합니다.
IPC_EXCL key에 해당하는 큐가 없다면 생성하지만 있다면 -1을 반환하고 복귀합니다.

예제

////////////////////////// main_receiver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define  BUFF_SIZE   1024

typedef struct {
   long  data_type;
   int   data_num;
   char  data_buff[BUFF_SIZE];
} t_data;

int main( void)
{
   int      msqid;
   t_data   data;

   if ( -1 == ( msqid = msgget( (key_t)1234, IPC_CREAT ¦ 0666))){
      perror( "msgget() 실패");
      exit( 1);
   }
   while( 1 ){
      // 메시지 큐 중에 data_type 이 2 인 자료만 수신
      if ( -1 == msgrcv( msqid, &data, sizeof( t_data) - sizeof( long), 2, 0)){
         perror( "msgrcv() 실패");
         exit( 1);
      }
      printf( "%d - %s\n", data.data_num, data.data_buff);
   }
}

////////////////////////// main_sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define  BUFF_SIZE   1024

typedef struct {
   long  data_type;
   int   data_num;
   char  data_buff[BUFF_SIZE];
} t_data;

int main( void)
{
   int      msqid;
   int      ndx   = 0;
   t_data   data;

   if ( -1 == ( msqid = msgget( (key_t)1234, IPC_CREAT ¦ 0666))){
      perror( "msgget() 실패");
      exit( 1);
   }

   while( 1 ){
      data.data_type = ( ndx++ % 3) +1;   // data_type 는 1, 2, 3
      data.data_num  = ndx;
      sprintf( data.data_buff, "type=%ld, ndx=%d, http://badayak.com", data.data_type, ndx);

      if ( -1 == msgsnd( msqid, &data, sizeof( t_data) - sizeof( long), 0)){
         perror( "msgsnd() 실패");
         exit( 1);
      }
      sleep( 1);
   }
}
receiver sender
]$ gcc receiver.c -o receiver.out
]$ ./receiver.out
2 - type=2, ndx=2, http://badayak.com
5 - type=2, ndx=5, http://badayak.com
8 - type=2, ndx=8, http://badayak.com
11 - type=2, ndx=11, http://badayak.com
14 - type=2, ndx=14, http://badayak.com

여기서 멈춤이 일어 납니다. 왜냐하면 receiver 가 data_type 가 2 인 것만 가져 갔기 때문에 메시지 큐가 포화되었기 때문입니다. 그래서 Ctrl-C 키로 receiver를 종료한 후에 main_reciever.c의 msgrcv() 인수 중 data_type를 0으로 변경한 후 다시 실행하면 큐에 쌓인 자료를 다시 읽어 들여서 큐를 비우게 되고 sender에서 다시 전송을 계속하게 되고 receiver도 수신을 계속하게 됩니다.

]$ gcc sender.c -o sender.out
]$ ./sender.out

main_reciever.c의 msgrcv()의 인수 중 data_type 를 0 으로 변경한 후 다시 실행해 보겠습니다.

////////////////////////// main_receiver.c
         :
   while( 1 ){
      // 메시지 큐 중에 data_type이 0 인 자료만 수신
      if ( -1 == msgrcv( msqid, &data, sizeof( t_data) - sizeof( long), 0, 0)){
         perror( "msgrcv() 실패");
         exit( 1);
      }
receiver sender
]$ gcc receiver.c -o receiver.out
]$ ./receiver.out
1 - type=1, ndx=1, http://badayak.com
2 - type=2, ndx=2, http://badayak.com
3 - type=3, ndx=3, http://badayak.com
4 - type=1, ndx=4, http://badayak.com
5 - type=2, ndx=5, http://badayak.com
6 - type=3, ndx=6, http://badayak.com
7 - type=1, ndx=7, http://badayak.com
8 - type=2, ndx=8, http://badayak.com
9 - type=3, ndx=9, http://badayak.com
10 - type=1, ndx=10, http://badayak.com
11 - type=2, ndx=11, http://badayak.com
12 - type=3, ndx=12, http://badayak.com
13 - type=1, ndx=13, http://badayak.com
                 :
]$ gcc sender.c -o sender.out
]$ ./sender.out

이 댓글을 비밀 댓글로