ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 뇌자극 TCP/IP 11강 요약
    C_C++ 프로그래밍/뇌를 자극하는 TCP_IP 2019. 6. 2. 19:22




    IPC = Inter process Communications

    네트워크 프로그래밍이 아닌 시스템 프로그래밍에 가까운 부분이다.


    소켓 함수는 20개 내외로 제한적이기 때문에, 응용 프로그램 개발을 할 시에는 시스템 프로그래밍 기술이 매우 중요하다.

    네트워크 프로그램도 시스템 위에서 작동한다.



    프로세스간의 통신을 위해서 사용한다.
    안정적인 작동이 가능한다.
    최근에는 쓰레드 기반을 사용한다. (IPC가 너무 난해하기 때문에)



    System V IPC 계열과 POSIX IPC가 존재한다.



    PIPE
    단방향의 데이터 통신용으로 사용한다.
    => 양방향을 사용하기 위해서는 2개를 생성

    부모 프로세스와 자식 프로세스간의 통신을 위해서 사용한다.

    이름이 없는 파이프와 이름이 있는 파이프로 나뉨

    #include<unistd.h>
    int pipe(int filedes[2]);

    Named PIPE (이름이 있는 파이프)
    마치 파일처럼 사용할 수 있다. (이름이 존재)


    Unix Domain Socket

    유닉스 영역의 통신에서만 사용한다.
    유닉스 영역에 서버/클라이언트 환경을 만들 수 있다.
    소켓과 거의 동일하다.
    중대형 어플리케이션 만들기 위해서 용이하다. (mysql)

    struct sockaddr_un sockaddr;
    socket(AF_UNIX, SOCK_STREAM, 0);
    sprintf(sockaddr.sun_path, "filename.sock");


    공유 메모리

    PIPE와 Unix Domain Socket는 메시지 기반의 IPC로 공유 메모리를 사용할 수 있다.

    메모리 공간을 공유하며, 빠르고 효율적이다. 

    하지만, 접근제어가 필요하게 된다 => Mutex 혹은 Semaphores가 필요함




    공유 메모리 생성

    shmget 함수로 공유 메모리 생성이 가능하다.

    shmid = shmget((key_t) key, int size, int shmflg);

    1. key : 공유 메모리는 커널에서 관리를 한다. 각 프로세스는 이를 이용해 접근할 공유 메모리를 식별한다.

    2. size : 커널에게 요청할 메모리의 크기

    3. shmflg
    IPC_CREAT : 공유 메모리를 새로 생성한다.
    IPC_EXCL    : IPC_CREAT와 함께 사용하며, key 값을 가지는 공유 메모리 영역이 존재하면 에러가 난다.



    공유 메모리 첨부와 분리하기

    shmdt(const void *shmaddr)

    shmaddr : 분리할 공유 메모리를 가리키는 포인터로 shmat에서 사용했던 shmaddr를 그대로 사용한다.


    shmat(int shmid, const void *shmaddr, int shmflg)

    shmid : shmget 함수로 만든 공유 메모리 식별자

    shmaddr : 공유 메모리 영역을 가리키는 주소이다. NULL인 경우 운영체제가 알아서 찾아서 반환해준다.

    shmflg : 쓰기 전용을 지정할 수는 없고, 값을 지정하게 되면 읽기 전용이 된다.






    공유 메모리 사용 예제

    produce.c

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

    int main(int argc, char **argv){
            int shmid;

            int *cal_num;
            void *share_mem = NULL;

            // 0666 => 110110110 rwxrwxrwx
            shmid = shmget((key_t)1234, sizeof(int), 0666|IPC_CREAT);
            if(shmid == -1){
                    perror("shmget fail");
                    return 1;
            }
            // *share_mem --> attached mem
            share_mem = shmat(shmid, NULL, 0);
            if(share_mem == (void *)-1){
                    perror("shmat fail");
                    return 1;
            }

            cal_num = (int *)share_mem;
            while(1){
                    *cal_num = *cal_num + 2;
                    sleep(1);
            }
            return 1;
    }


    consumer.c

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

    int main(int argc, char **argv){
            int shmid;
            int *cal_num;
            void *share_mem = NULL;

            shmid = shmget((key_t)1234, sizeof(int), 0);
            if(shmid == -1){
                    perror("shmget fail");
                    return 1;
            }
            // *share_mem --> attached mem
            share_mem = shmat(shmid, NULL, 0);
            if(share_mem == (void *) -1){
                    perror("shmat fail");
                    return 1;
            }

            cal_num = (int *) share_mem;

            while(1){
                    sleep(1);
                    printf("Read Data : %d\n", *cal_num);
            }
            return 1;
    }





    하지만, 공유 데이터에 서로 접근하여 사용하게 되기 때문에

    접근 제어가 필요하게 된다.

    => critical section (임계영역)이 필요


    세마포어 (Semaphores) 생성

    int semget(key_t key, int nsems, int semflg);

    key : 공유 메모리와 같이 식별하여 생성할 수 있다.

    nsems : 세마포어는 배열로 만들어진다. 이때 그 크기를 지정한다.

    semflg : 세마포어의 생성 방식을 결정한다.
    IPC_CREAT : 커널에 key 값의 세마포어가 없다면 새로 생성한다.
    IPC_EXCL : IPC_CREAT와 함께 사용한다. key가 이미 존재하면 에러 발생


    세마포어 임계영역 관리

    int semop(int semid, struct sembuf *sops, unsigned nsops)

    semid : semget 함수로 생성한 세마포어 식별자이다.

    sops : 세마포어 제어를 위해 사용하는 세마포어 구조체이다.

    nsops : 세마포어 집합의 개수이다. 하나만 접근이 가능할려면 1을 사용



    간단한 세마포어 예제

    producer.c

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

    union semun{
            int val;
    };

    int main(int argc, char **argv){
            int shmid;
            int semid;

            int *cal_num;
            void *share_mem = NULL;
            union semun sem_union;

            struct sembuf semopen = {0,-1,SEM_UNDO};
            struct sembuf semclose = {0,1,SEM_UNDO};

            // Get share memory
            shmid = shmget((key_t)1234, sizeof(int), 0666|IPC_CREAT);
            if(shmid == -1){
                    return 1;
            }

            // let's make semaphores
            semid = semget((key_t)3477, 1, IPC_CREAT|0666);
            if(semid == -1){
                    return 1;
            }

            // connect to share mem
            share_mem = shmat(shmid, NULL, 0);
            if(share_mem == (void *) -1){
                    return 1;
            }

            // *cal_num --> share_memory
            cal_num = (int *)share_mem;


            sem_union.val = 1;
            // init semaphores
            if(-1 == semctl(semid, 0, SETVAL, sem_union)){
                    return 1;
            }

            while(1){
                    int local_var = 0;
                    // critical section
                    if(semop(semid, &semopen, 1) == -1){
                            return 1;
                    }
                    local_var = *cal_num + 1;
                    sleep(1);
                    *cal_num = local_var;
                    printf("%d\n", *cal_num);
                    semop(semid, &semclose, 1);
                    // end
            }
            return 1;
    }


    consumer.c

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

    int main(int argc, char **argv){
            int shmid;
            int semid;

            int *cal_num;
            void *share_mem = NULL;

            // semaphores open ans close data
            struct sembuf semopen = {0, -1, SEM_UNDO};
            struct sembuf semclose = {0, 1, SEM_UNDO};

            // connect share mem
            shmid = shmget((key_t)1234, sizeof(int), 0666);
            if(shmid == -1){
                    perror("shmget fail");
                    return 1;
            }

            // acees key = 3477, access = 0, auth 666
            semid = semget((key_t)3477, 0, 0666);
            if(semid == -1)
            {
                    perror("semget fail");
                    return 1;
            }

            // connet share mem
            share_mem = shmat(shmid, NULL, 0);
            if(share_mem == (void *)-1){
                    perror("shmat fail");
                    return 1;
            }

            // cal_num ==> share memory
            cal_num = (int *) share_mem;

            while(1){
                    // local int
                    int local_val = 0;
                    // critical section open
                    if(semop(semid, &semopen, 1) == -1){
                            perror("semop error :");
                    }
                    local_val = *cal_num+1;
                   sleep(2);
                    *cal_num = local_val;
                    printf("count %d\n", *cal_num);
                    semop(semid, &semclose, 1);
                    // close
            }
            return 1;
    }



    시그널 함수

    시그널 함수를 사용하여 프로세스의 종료를 무시할 수 있는 등

    다양한 처리가 가능하지만, 마지막 시그널만 기억한다. (덮어쓰기)

    => 리얼타임 시그널을 사용하면 시그널의 장점을 유지하면서 대기열까지 제공한다.

    ※ 본 글은 개인 포트폴리오 혹은 공부용으로 사용하기 때문에, 무단 복사 유포는 금지하지만, 개인 공부 용도로는 얼마든지 사용하셔도 좋습니다



    반응형
Designed by Tistory.