[리눅스 프로그래밍] - (IPC) SYSV Message Queue 다루기

Yoon Yeoung-jin·2022년 7월 3일
0

Linux

목록 보기
8/13

01. sysv message queue

  • 메세지 기반 커뮤니케이션으로 pipe 나 Named pipe와는 달리 하나의 메세지를 기준으로 전송한다.
  • IPC Key를 기반으로 데이터를 전송한다.
  • POSIX와는 달리 mtype을 사용하여 메세지 큐에 있는 데이터를 구분해서 받을 수 있다.
  • 관련 툴
    • ipcs, ipcrm

02. 사용 API

  • 사용 헤더
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/msg.h>
  • 사용 함수
    • int msgget(key_t key, int msgflg);: Message queue ID를 구하는 함수. 옵션에 따라 생성도 가능
      파라미터
      • key: IPC object Key or IPC_PRIVATE
      	  ‐ IPC_PRIVATE: 지정 시 새로운 message queue ID 생성 • msgflg: permission + mask
      		‐ IPC_CREAT: key에 매치되는 message queue ID 없으면 생성
      		‐ IPC_EXCL: key에 매치되는 message queue ID가 있으면 에러 발생
      반환값
      • 성공: message queue ID 
      • 실패: -1 
    • key_t ftok(const char *pathname, int proj_id);: ipc key 값을 구하는 함수
      파라미터
      • pathname
      		‐ 조합할 파일 경로
      		‐ 파일이 존재해야 하고, readable해야 함 
      • proj_id
      	- 임의의 project ID (int 형이여야 함)
      반환값
      • 성공: IPC Key
      • 실패: -1
    • int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); : 메세지 전송 함수
      파라미터
      • msqid: message queue id
      • msgq: 전송할 메시지 버퍼
      • msgsz: 전송 메시지 사이즈(mtext의 길이, in bytes)
      • msgflg
      	‐ IPC_NOWAIT: non-blocking I/O
      반환값
      • 성공: 0
      • 실패: -1
      • 해당 함수를 사용하는데 msgp 형식을 아래 구조체와 같은 형식으로 만든 후 전송해야 한다.
        struct msgbuf {
        	long mtype; /* message type, must be > 0 */ 
        	char mtext[1]; /* message data */
        };
    • ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); : 메세지 수신 함수
      파라미터
      msqid: message queue id
      msgp: message 수신 버퍼
      msgsz: 최대 수신 길이(mtext의 길이, in bytes) msgtyp: 수신할 message type
      	‐ 0: 첫번째 메시지 수신
      	‐ 양수: msgtype에 매치되는 첫번째 메시지 수신
      	‐ 음수: 지정된 절대값보다 작거나 같은 msgtype에 매치되는 첫번째 메시지 수신
      msgflg
      	‐ IPC_NOWAIT: non-blocking I/O
      	‐ MSG_COPY
      		▫ n번째 메시지를 복사해서 수신(msgtyp이 index로 사용됨)
      		▫ 반드시 IPC_NOWAIT와 같이 사용해야 함
      	‐ MSG_EXCEPT: msgtyp과 매치되지 않는 메시지를 수신
      	‐ MSG_NOERROR: 메시지 사이즈가 msgsz보다 크다면 truncate 시킴
      반환값
      • 성공: 실제로 받은 데이터 길이(mtext의 길이, in bytes) 
      • 실패: -1
    • int msgctl(int msqid, int cmd, struct msqid_ds *buf);: message queue 제어 함수
      파라미터
      • msqid: message queue id • cmd
      	‐ IPC_STAT: kernel의 msgid_ds 정보 습득
      	‐ IPC_SET: kernel의 msgid_ds에 설정
      	‐ IPC_RMID: message queue 제거
      • buf
      반환값
      • 성공: 0
      • 실패: -1
      
      struct msqid_ds {
                     struct ipc_perm msg_perm;     /* permission에 대한 정보가 있는 변수 */
                     time_t          msg_stime;    /* 가장 최근에 send를 한 시간 */
                     time_t          msg_rtime;    /* 가장 최근에 recv를 한 시간 */
                     time_t          msg_ctime;    /* 가장 최근에 변경된 시간 */
                     unsigned long   __msg_cbytes; /* message queue의 max byte */
                     msgqnum_t       msg_qnum;     /* queue에 있는 메시지 개수 */
                     msglen_t        msg_qbytes;   /* queue에서 허용하는 메시지의 최대 개수 */
                     pid_t           msg_lspid;    /* 마지막으로 send한 프로세스의 pid*/
                     pid_t           msg_lrpid;    /* 마지막으로 recv한 프로세스의 pid */
                 };
      struct ipc_perm {
                     key_t          __key;       /* Key supplied to msgget(2) */
                     uid_t          uid;         /* Effective UID of owner */
                     gid_t          gid;         /* Effective GID of owner */
                     uid_t          cuid;        /* Effective UID of creator */
                     gid_t          cgid;        /* Effective GID of creator */
                     unsigned short mode;        /* Permissions */
                     unsigned short __seq;       /* Sequence number */
                 };

03. 예제 코드

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#include<fcntl.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define SHARED_PATH "/home/alwns28/example_folder/sysv_example/pw_file"
#define PROJ_ID 1234

#define MAX_BUF_LEN 1024

typedef struct msgbuf {
    long mtype;
    char mtext[MAX_BUF_LEN];
} SYSV_BUF;

static void print_help(char *program_name)
{
    printf("Usage: %s (s mtype |r mtype)\n", program_name);
} 

SYSV_BUF sysv_buf_setting(const char *msg, long mtype)
{
    SYSV_BUF buf;
    memset((void *)&buf, 0, sizeof(SYSV_BUF));
    strcpy(buf.mtext, msg);
    buf.mtype = mtype;
    return buf;
}

static int sysv_mqid_setting(int *mq_id)
{
    /* Gen ipc key */
    key_t key;
    printf(" = Create IPC key ");
    key = ftok(SHARED_PATH, PROJ_ID);
    if(key == -1){
        printf(" => FAIL \n");
        perror("ftok()");
        return -1;
    }
    printf(" => SUCCESS, key: %d\n", key);

    printf(" = Create Message Queue ID ");
    *mq_id = msgget(key, IPC_CREAT);
    if(*mq_id == -1){
        printf(" => FAIL \n");
        perror("msgget()");
        return -1;
    }
    printf(" => SUCCESS, ID: %d\n", *mq_id);
    return 0;

}

int send_data(long mtype){

    int mq_id;
    char buf[MAX_BUF_LEN];
    SYSV_BUF mq_buf;

    if(sysv_mqid_setting(&mq_id) == -1){
        printf("FAIL setting mq id\n");
        return -1;
    }

    memset((void *)buf, 0, sizeof(buf));
    snprintf(buf, sizeof(buf), "Hello world");
    mq_buf = sysv_buf_setting(buf, mtype);

    printf(" = Send Message [%s] ", mq_buf.mtext);
    if(msgsnd(mq_id, (const void *)&mq_buf, sizeof(mq_buf.mtext), 0) == -1){
        printf(" => FAIL \n");
        perror("msgsnd()");
        return -1;
    }
    printf("  => SUCCESS \n");

    return 0;
}

int recv_data(long mtype){
    int mq_id;
    SYSV_BUF mq_buf;

    /* Gen ipc key */
    if(sysv_mqid_setting(&mq_id) == -1){
        printf("FAIL setting mq id\n");
        return -1;
    }

    if(msgrcv(mq_id, (void *)&mq_buf, sizeof(mq_buf.mtext), mtype, 0) == -1){
        printf(" => FAIL \n");
        perror("msgrcv()");
        return -1;
    }
    printf(" = Recv Messagae => SUCCESS , Recv Data: %s\n", mq_buf.mtext);

    return 0;
}

int main(int argc, char **argv)
{
    long mtype;
    if(argc < 3){
        print_help(argv[0]);
        return -1;
    }

        
    int fd = open(SHARED_PATH, O_CREAT, 0644);
    close(fd);

    mtype = strtol((const char *)argv[2],NULL,10);
    
    if(!strcmp(argv[1], "s")){
        if(send_data(mtype) == -1){
            printf("메세지 전송을 실패하였습니다.\n");
            return -1;
        }

    }else if(!strcmp(argv[1], "r")) {
        if(recv_data(mtype) == -1){
            printf("메세지 수신을 실패하였습니다.\n");
            return -1;
        }

    } else {
        print_help(argv[0]);
    }

    return 0;
}
profile
신기한건 다 해보는 사람

0개의 댓글