본문 바로가기

컴퓨터공학/시스템 프로그래밍

IPC(파이프, 메시지큐, 공유 메모리, 시그널)

반응형

파이프

:부모의 프로세스가 생성된 자식 프로세스에게 단방향으로 데이터를 전달하는 방법파이프 기법은 부모 프로세스가 자식 프로세스에게 전달하는 기법(단방향 통신) pipe로 먼저 생성 후 fork 로 자식 프로세스 생성하고 부모가 write(fd[1], 메시지내용, 크기) 자식은 read (fd[0], 받은버퍼, 크기)로 하여 통신한다

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MSGSIZE 255

char* msg = "Hello Child Process!";
int main()
{
    char buf[255];
    int fd[2], pid, nbytes;
    if (pipe(fd) < 0)  // pipe(fd) 로 파이프 생성 
        exit(1);
    pid = fork(); // 이 함수 실행 다음 코드부터 부모/자식 프로세스로 나뉘어짐
    if (pid > 0) {  // 부모 프로세스에는 자식 프로세스 pid값이 들어감
        printf("parent PID:%d, child PID:%d\n", getpid(), pid);
        write(fd[1], msg, MSGSIZE); //fd[1]에 씁니다.
        exit(0);
    }
    else {  // 자식 프로세스에는 pid값이 0이 됨
        printf("child PID:%d\n", getpid());
        nbytes = read(fd[0], buf, MSGSIZE); // fd[0]으로 읽음
        printf("%d %s\n", nbytes, buf);
        exit(0);
    }
    return 0;
}

 

메세지큐 :

메시지큐는 프로세스간 양방향 통신(심지어 자기자신에게도 보내고 받을수 있음)

 

  1. 생성 : msgget(키,생성 상수|권한) *권한이라고 하면 0644같은걸 줘서 rw-r 이런식으로
  2. 보내기 : msgsnd(키,보낼데이터,텍스트크기, 플래그) *보낼데이터는 구조체로 타입과 텍스트가 있어야함, 텍스트 크기는 보낼데이터의 텍스트 크기, 플래그는 블럭, 노블럭인데 블럭은 해당 함수를 실행할까지 멈춰있는것, 노블럭은 실행하지 못하더라도 다음문장 실행
  3. 받기 : msgrcv(키, 받을데이터, 텍스트크기, 타입, 플래그) * 나머지 내용은 보내기랑 같고 타입은 보내기에서 보낼데이터에 적힌 타입을 의미

 

// messageQueue Send

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>

typedef struct msgbuf {
    long type;
    char text[50];
} MsgBuf;

int main(void) {
    int msgid, len;
    MsgBuf msg;
    key_t key = 1234; 
    msgid = msgget(key, IPC_CREAT|0644); 
    if(msgid == -1) {
        perror("msgget");
        exit(1);
    }
    msg.type = 1;
    strcpy(msg.text, "Hello Message Queue\n"); 
    if(msgsnd(msgid, (void *)&msg, 50, IPC_NOWAIT) == -1) { 
        perror("msgsnd");
        exit(1);
    }
    return 0;
}

 

// messageQueue Receive

#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct msgbuf {
    long type;
    char text[50];
} MsgBuf;

int main(void) {
    MsgBuf msg;
    int msgid, len;
    key_t key = 1234;
    if((msgid = msgget(key, IPC_CREAT|0644)) < 0) {
        perror("msgget");
        exit(1);
    }
    len = msgrcv(msgid, &msg, 50, 0, 0);
    printf("Received Message is [%d] %s\n", len, msg.text);
    return 0;
}

*메시지큐에 전송되는 데이터 구조 (type의 자료형이 long이니 반드시 유의해야 한다)

 

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; }

 

*ipcs : 현재 사용중인 메시지 큐, 공유 메모리 보기

 

공유 메모리

: 변수에 할당하듯이 커널에 메모리 공간을 할당하여 사용하는 방식이다

 #include <sys/types.h>
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>

 int main(void) {
     int shmid, pid;
     char *shmaddr_parent, *shmaddr_child;
     key_t key = ftok(".",1);
     printf("key : %d\n",key);
     shmid = shmget((key_t)key, 10, IPC_CREAT|0644);
     if(shmid == -1) {
         perror("shmget error\n");
         exit(1);
     }
     pid = fork();
     if (pid > 0) {  // parent process
         wait(0);    // wait for child process exit
         shmaddr_parent = (char *)shmat(shmid, (char *)NULL, 0);
         printf("%s\n", shmaddr_parent);
         shmdt((char *)shmaddr_parent);
     }
     else {  // child process
         shmaddr_child = (char *)shmat(shmid, (char *)NULL, 0);
         strcpy((char *)shmaddr_child, "Hello Parent!");
         shmdt((char *)shmaddr_child);
         exit(0);
     }
     shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
     return 0;
 }
  1. 공유 메모리 생성 : shmget
  2. 공유 메모리 연결 : shmat
  3. 공유 메모리 분리 : shmdt (현재 프로세스와 공유 메모리 분리)
  4. 공유 메모리 삭제 : shmctl
ftok 패스경로의 inode의 값("."를 쓰면 현재경로), id를 넣으면 알아서 key를 생성해주는 함수
shmat 공유 메모리 연결
shmdt 현재 프로세스와 공유 메모리 분리
shmctl 공유 메모리 삭제

 

시그널

: 시그널 매크로에 사용자 정의나 블럭을 하여 다른 프로세스간에 통신하는 기법

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

static void signal_hanlder(int signo){
    printf("Catch SIGINT!, but no stop\n");
}

int main(void){
    if(signal(SIGINT,signal_hanlder) == SIG_ERR){
        printf("Can't catch SIGINT!\n");
        exit(1);
    }
    for(;;)
        pause();
    return 0;
}

SIGINT 라는 프로세스에 인터럽트를 보내서 프로세스를 죽이는 시그널을 사용자 정의 함수로 바꾸는 코드

#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
int main(int argc,char *argv[]){
    printf("sigkill start\n");
    int pid = atoi(argv[1]);
    int sig_num = atoi(argv[2]);
    if(kill(pid,sig_num)<0)
    {
        perror("To send Signal is failed\n");
        exit(1);
    }
    return 0;
}

*kill 함수는 쉘명령어와 다르게 시그널을 전송하는 함수이다.

*kill 함수 정의

출처 http://forum.falinux.com/zbxe/index.php?category=520920&document_srl=413771&mid=C_LIB

 

실행 결과

프로세스가 종료되는것이 아니라 사용자가 정의된 함수로 실행된다

 

 

 

시그널과 프로세스

 

반응형

'컴퓨터공학 > 시스템 프로그래밍' 카테고리의 다른 글

시스템콜 , 프로세스 생성  (0) 2019.11.30
프로세스 ID  (0) 2019.11.30
ABI와 표준  (0) 2019.11.30
하드링크와 소프트링크  (0) 2019.11.29
foreground, background, 프로세스 관리  (0) 2019.11.29