390 likes | 659 Views
Linux System Programming. Lecture #9 – 메시지 큐 (Message Queue). 동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도 분류하기도 함. IPC(Inter-Process Communication) (1). 프로세스 통신 도구 (IPC Facilites) : 비동기적으로 동작하는 프로세스간의 통신을 위하여 운영체제가 제공하는 도구 종류 : Signal( 신호 ) Pipe( 파이프 ) Message Queue( 메시지 큐 )
E N D
Linux System Programming Lecture #9 –메시지 큐(Message Queue)
동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도 분류하기도 함 IPC(Inter-Process Communication) (1) • 프로세스 통신 도구(IPC Facilites) : • 비동기적으로 동작하는 프로세스간의 통신을 위하여 운영체제가 제공하는 도구 • 종류: • Signal(신호) • Pipe(파이프) • Message Queue(메시지 큐) • Semaphore(세마포어) • Shared Memory(공유 메모리) • Socket(소켓) Linux System Programming
IPC(Inter-Process Communication) (2) • 프로세스 통신 도구 (IPC Facilites): • 세마포어(Semaphore) • 프로세스 동기화와 자원 관리에 사용 • 프로세스간의 상호배제 문제 해결에 사용 • 공유 메모리(Shared Memory) • 가장 빠른 프로세스 통신 도구 • 하나 이상의 프로세스에 부착하여 서로 공유하여 접근 가능 • 프로세스간의 공유 메모리 접근을 위해 동기화가 필요 • 메시지 큐(Message Queue) • 프로세스들간에 이산적인 양의 데이터 송수신을 위해 사용 • 전송할 데이터를 메시지 형태로 생성하여 전달하고 메시지 수신을 통해 데이터 수신이 가능 • 인터넷 메일 서비스와 개념이 유사 Linux System Programming
IPC(Inter-Process Communication) (3) • IPC와 관련한 시스템 호출 함수: • IPC 시스템 호출 함수: Linux System Programming
IPC(Inter-Process Communication) (4) • IPC와 관련한 시스템 호출 함수: • get 시스템 호출 • 파일 열기 시스템 호출 open과 유사 • 새롭게 통신 도구를 생성하거나 이미 생성된 통신 도구에 대한 id를 반환하여 접근 가능하게 함 • 반환된 id는 파일 디스크립터와 비슷하게 동작 • 접근 허가 또한 파일 접근 허가와 비슷하게 규정 • ctl 시스템 호출 • 통신 도구에 관한 상태 정보 읽기 • 몇몇 상태 정보(소유자, 그룹, 접근 허가 등)에 대한 변경 • 통신 도구의 제거 기능 • op 시스템 호출 • 프로세스간의 데이터 전송을 실행 • 파일 시스템 호출 read/write와 유사 • Shmat는 파일의 open과 유사하고, shmdt는 파일의 close와 유사 Linux System Programming
key_t char device Inode # of file IPC(Inter-Process Communication) (5) • IPC 도구 식별자: • IPC 도구 식별자 – IPC key • 파일을 식별하기 위해 파일 이름을 사용하듯이 IPC 객체를 식별하기 위해 사용하는 정수형 숫자 • 프로세스들은 IPC key를 이용하여 IPC 자원을 공유 • 자료형: key_t (<sys/types.h>에 정의) • IPC key 변환 시스템 호출 – ftok(file_to_key) • IPC 도구의 공유를 편리하게 지원하기 위해 파일 경로명과 식별자를 IPC 도구에 부여하고, 이를 IPC key 값으로 변환하는 시스템 호출 Linux System Programming
IPC(Inter-Process Communication) (6) • IPC 도구 식별자: • IPC key 변환 시스템 호출 – ftok(file_to_key) Linux System Programming
IPC(Inter-Process Communication) (7) • IPC 도구의 상태 자료 구조: • IPC 도구의 상태 구조 • 생성된 IPC 객체에 대한 상태 정보를 저장하는 구조체 • IPC 도구 유형별로 별도의 상태 구조체를 지원하나 다음의 접근 허가 구조를 공통으로 포함한다 • IPC 도구의 접근 허가 구조: struct ipc_perm • 파일의 접근 허가와 유사한 기능을 지원 • 접근 모드에서 실행 모드는 무의미함 Linux System Programming
IPC(Inter-Process Communication) (8) • IPC 도구의 상태 자료 구조: • IPC 도구 테이블 • IPC 도구 유형별로 생성된 IPC 객체를 관리하기 위해 운영체제가 유지하는 테이블 • IPC 도구 유형별로 각각의 테이블을 유지 • 파일 테이블과 유사한 개념 Linux System Programming
IPC(Inter-Process Communication) (9) • IPC 도구 관리 명령: • ipcs 명령 • 현재 사용중인 IPC 도구들의 상태(status)를 보여주는 명령 • IPC 타입, 사용자 ID, key 값 그리고 접근 허가 등을 볼 수 있음 • 옵션을 사용하여 지정된 유형의 IPC 도구 상태 정보만을 접근 가능 • -q : 메시지 큐, -m : 공유 메모리, -s : 세마포어 • ipcrm 명령 • IPC 객체를 제거하는 명령 • IPC 도구 유형 및 key 값을 지정하는 원하는 IPC 객체를 제거 Linux System Programming
메시지 큐(Message Queue) (1) • 메시지 큐: • 프로세스간에 이산적인 데이터를 메시지 형태로 전송하는 통신 도구 • 파이프와 같이 FIFO 타입의 데이터 전송을 지원 • 메시지는 메시지와 바이트(byte)들의 모임으로 구성 • 메시지 유형은 정수값으로 여러가지 메시지 형태에 id를 부여하여 구별하기 위해 사용 • 바이트 모임은 전송하는 데이터를 의미하는 것으로 문자, 그림 또는 일련의 구조체 데이터 등을 전송하기 위햇 사용 • 관련 시스템 호출 함수 • msgget() –메시지 큐를 생성 • msgsnd()/msgrcv() –메시지 전송 및 수신 • msgctl() –메시지 큐 제어 Linux System Programming
메시지 큐(Message Queue) (2) • 메시지 큐의 구조: • 메시지 큐의 상태 구조체 : msgid_ds • 메시지 큐 객체의 상태 정보를 저장하는 구조체 • 하나의 메시지 큐가 생성되면 하나의 msgid_ds 구조체가 생성 Linux System Programming
메시지 큐(Message Queue) (3) • 메시지 큐의 동작: • 전송 프로세스가 전송할 데이터를 메시지 형태로 만들어 메시지를 전송하면 전송된 메시지는 메시지 큐의 마지막에 연결된다 • 수신 프로세스는 메시지 큐에 존재하는 메시지를 선택적으로 수신할 수 있다. • 수신 프로세스에서는 메시지를 수신할 때에 다음의 수신 정책 중에 하나를 지정하여야 한다. • 메시지 큐에서 첫번째 메시지 • 메시지 큐에서 지정된 타입의 첫번째 메시지 • 메시지 큐에 있는 타입들의 범위들로 부터 첫번째 메시지 Linux System Programming
메시지 큐(Message Queue) (4) • 메시지 큐의 생성: msgget • msgget –메시지 큐 생성 시스템 호출 • 주어진 key를 갖는 메시지 큐가 존재하면 메시지 큐의 id를 반환하고, 그렇지 않으면 새롭게 메시지 큐를 생성하고 id를 반환 Linux System Programming
메시지 큐(Message Queue) (5) • 메시지 큐의 생성: msgget • 메시지 큐 구조체: msqid_ds Linux System Programming
메시지 큐(Message Queue) (6) • 메시지 큐의 생성: msgget • 메시지 큐 구조체의 초기값 Linux System Programming
메시지 큐(Message Queue) (7) • 메시지 큐의 생성: msgget • msgget 시스템 호출의 flag 옵션 Linux System Programming
메시지 큐(Message Queue) (8) • 메시지 큐의 제어: msgctl • msgctl - 메시지 큐 제어 시스템 호출 • 메시지 큐의 상태를 질의하거나 상태 정보를 변경, 또는 메시지 큐를 제거하는 기능을 지원 Linux System Programming
메시지 큐(Message Queue) (9) • 메시지 큐의 제어: msgctl • msgctl 시스템 호출의 명령어 Linux System Programming
메시지 큐(Message Queue) (10) • msgctl 시스템 호출의 사용 예 • 메시지 큐 관련 자료 구조 선언 • 메시지 큐의 제거 • 메시지 큐의 소유자 변경 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msqid; struct msqid_ds ds; msgctl(msqid, IPC_RMID, (struct msqid_ds *)0); msgctl(msqid, IPC_STAT, &ds); ds.msg_perm.uid = 51; msgctl(msqid, IPC_SET, &ds); Linux System Programming
메시지 큐(Message Queue) (11) • msgctl 시스템 호출의 사용 예 • 메시지 큐의 접근 허가 변경 • 메시지 큐의 메시지 크기 변경 msgctl(msqid, IPC_STAT, &ds); ds.msg_perm.mode = 0660; msgctl(msqid, IPC_SET, &ds); msgctl(msqid, IPC_STAT, &ds); ds.msg_qbytes = 5000; msgctl(msqid, IPC_SET, &ds); Linux System Programming
메시지 큐(Message Queue) (12) • 메시지 큐의 연산: msgsnd, msgrcv • 메시지 구조체 : • 메시지 유형은 전송되는 여러가지 유형의 메시지 형태를 분류하여 지정 • 메시지 텍스트는 전송하는 데이터를 저장 • 메시지 텍스트의 크기는 최소 0에서 최대 64 KB 이내이며, 묵시적으로 2048 바이트로 사용 #include <sys/msg.h> struct msgbuf { long mtype; /* 메시지 유형 */ char mtext[1]; /* 메지시 텍스트 */ } Linux System Programming
메시지 큐(Message Queue) (13) • 메시지 큐의 연산: msgsnd, msgrcv • 메시지 송신 시스템 호출 : msgsnd Linux System Programming
메시지 큐(Message Queue) (13) • 메시지 큐의 연산: msgsnd, msgrcv • msgsnd 시스템 호출에 의한 메시지 큐 구조체 변경 Linux System Programming
메시지 큐(Message Queue) (14) • 메시지 큐의 연산: msgsnd, msgrcv • 메시지 수신 시스템 호출 : msgrcv Linux System Programming
메시지 큐(Message Queue) (15) • 메시지 큐의 연산: msgsnd, msgrcv • msgrcv 시스템 호출에서의 메시지 타입 지정 • msgrcv 시스템 호출에 의한 메시지 큐 구조체 변경 Linux System Programming
예제 프로그램 (1) • 예제 9-1 • 하나의 메시지를 전송하고 수신하는 프로그램을 작성하여라 // file name : ex9-1a.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct { long t; char a[60]; } x = {11L,"hello"}; main() { int mid; mid = msgget(11L,IPC_CREAT| 0666); msgsnd(mid,&x,strlen(x.a)+1,0); sleep(60); msgctl(mid,IPC_RMID,0); } Linux System Programming
예제 프로그램 (2) // file name : ex9-1b.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct { long t; char a[60]; } x ; main() { int mid,rtn; mid = msgget(11L,0); rtn=msgrcv(mid,&x,60,0L,0); printf("rtn=%d type=%d text=%s\n",rtn,x.t,x.a); } Linux System Programming
예제 프로그램 (3) • 예제 9-2 • 예제 9-1을 개선하여 여러 개의 메시지를 송수신하는 프로그램을 작성하여라. // file name : ex9-2a.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SEND_SZ 30 #define DONE 99L main() { void perror(); key_t key; int mid; static struct { long mtype; char mtext[MAX_SEND_SZ]; } buf; Linux System Programming
예제 프로그램 (4) static char *string[3] = { "hello", "how are you", "good-bye"}; int i,rtn; if((key= ftok(".",'a'))==-1) { perror("Can\'t form key"); exit(1); } mid = msgget(key,IPC_CREAT| 0660); if(mid == -1) { perror("Sender can not make msg queue!"); exit(2); } Linux System Programming
예제 프로그램 (5) buf.mtype = 1L; for(i=0;i<3;i++) { strcpy(buf.mtext,string[i]); if(msgsnd(mid,&buf,strlen(buf.mtext)+1,0)==-1) { perror("Sender can not msgsnd!"); exit(3); } } rtn = msgrcv(mid,&buf,MAX_SEND_SZ,DONE,0); if(rtn == -1) { perror("Sender can not msgrcv"); exit(4); } msgctl(mid,IPC_RMID,0); } Linux System Programming
예제 프로그램 (6) // file name : ex9-2b.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_RECV_SZ 60 #define FIFO 0L #define ZERO_LEN 0 #define DONE 99L static struct { long mtype; char mtext[MAX_RECV_SZ]; } buf; key_t key; int mid; int rtn; Linux System Programming
예제 프로그램 (7) main(int argv,char *argc[]) { void perror(); if((key= ftok(".",'a'))==-1) { perror("Can\'t form key"); exit(1); } mid = msgget(key,0); if(mid == -1) { perror("Receiver can not access msg queue!"); exit(2); } while(1) { rtn = msgrcv(mid,&buf,MAX_RECV_SZ,FIFO,0); printf("rtn=%d buf.mtype=%ld buf.mtext=%s\n", rtn,buf.mtype,buf.mtext); if(!strcmp(buf.mtext,"good-bye")) break; } buf.mtype = DONE; msgsnd(mid,&buf,ZERO_LEN,0); } Linux System Programming
예제 프로그램 (8) • 예제 9-3 • 메시지 송신 프로그램가 키보드 입력을 메시지로 만들어 여러 개의 수신 프로그램에 전달하는 프로그램을 작성하여라. • 송신 프로그램은 fork()/exec() 시스템 호출을 통하여 수신 프로세스를 생성하고, 수신 프로세스는 수신된 메시지를 표준 출력으로 출력하도록 한다. // file name : ex9-3a.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 #define NCHILD 3 Linux System Programming
예제 프로그램 (9) #define WAIT_SOLE_USE(MSGQID) { \ int still_active = NCHILD; \ int i; \ long s_pid; \ s_pid = getpid(); \ while(still_active) { for(i=0;i<NCHILD;i++) \ if(msgrcv(MSGQID,&buf,MAX_SZ,s_pid,IPC_NOWAIT) != -1) \ if(!strncmp(buf.mtext,"DONE",4)) still_active--; \ sleep(2); \ } \ } main() { void perror(); key_t ftok(); int msgqid; struct { long mtype; char mtext[MAX_SZ]; } buf; Linux System Programming
예제 프로그램 (10) int msg_length; static char qid_evar[40]; static char *envp[2] = { qid_evar }; int this_fork, child; long r_pid[NCHILD]; char child_name[20]; int eof = 0; if((msgqid = msgget(IPC_PRIVATE,IPC_CREAT | 0660)) == -1) { perror("Sender can't make message queue!"); exit(1); } sprintf(qid_evar,"MQID=%d",msgqid); for(child=0;child<NCHILD;child++) { this_fork = fork(); if(this_fork == -1) { perror("fork failed"); exit(2); } else if(this_fork == 0) { sprintf(child_name,"mwall_r%d",child); execle("ex9-3b",child_name,0,envp); perror("exec failed"); exit(3); } else r_pid[child] = (long) this_fork; } Linux System Programming
예제 프로그램 (11) setbuf(stdout,(char *) 0); while(1) { fprintf(stdout, "Enter message to be sent to all receivers:"); if(gets(buf.mtext) == (char *) 0) { fprintf(stdout,"\n"); eof++; strcpy(buf.mtext,"EOF"); } msg_length = strlen(buf.mtext) +1; for(child=0;child<NCHILD;child++) { buf.mtype = r_pid[child]; if(msgsnd(msgqid,&buf,msg_length,0) == -1) { perror("Producer msgsnd error"); exit(4); } } if(eof) break; sleep(1); } WAIT_SOLE_USE(msgqid); msgctl(msgqid,IPC_RMID,0); } Linux System Programming
예제 프로그램 (12) // file name : ex9-3a.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 main(int argc, char *argv[]) { void perror(); char *getenv(); long pid; char *valuep; int msgqid; struct { long mtype; char mtext[MAX_SZ]; } buf; Linux System Programming
예제 프로그램 (13) pid = (long) getpid(); if((valuep = getenv("MQID")) == NULL) { fprintf(stderr,"%s:can't get env MQID\n",argv[0]); exit(1); } else sscanf(valuep,"%d",&msgqid); while(1) { msgrcv(msgqid,&buf,MAX_SZ,pid,MSG_NOERROR); printf("%s received '%s'\n",argv[0],buf.mtext); if(!strcmp(buf.mtext,"EOF")) break; } buf.mtype = (long) getppid(); strcpy(buf.mtext,"DONE"); if(msgsnd(msgqid,&buf,strlen(buf.mtext),0) == -1) { fprintf(stderr,"%s:msgsnd error\n",argv[0]); exit(2); } exit(0); } Linux System Programming