자격증/정보보안기사

커널의 종류

romance penguin 2017. 2. 7. 02:14
반응형

모놀리딕 - 커널과 동일한 메모리공간에 입출력,네트워크,장치 드라이버 적재 linux

마이크로 - 기본적인 기능만 적재, 필요에 따라 추가 window

하이브리드 - 모놀리딕+마이크로


모놀리딕

가상 파일 시스템

ipc, 파일 시스템

스케줄러, 가상 메모리

장치드라이버, 디스패쳐  


마이크로

ipc기본

가상메모리

스케줄링

ap ipc,장치드라이버,파일서버 -> 사용자모드 에서 동작한다.

window에선 각종 장치드라이버를 따로 설치 해야 하는것은 쓰다보면 알수있다.


ipc란? (Inter-Process Communication)

프로세스간 통신

리눅스에서 지원하는 c언어 api를 이용해 코딩 해보자.



1. fork함수 이해

fork 함수는 코드를 그대로 복사해 실행한다고 보면 된다.

즉 프로세스가 하나 더 생기는것. 이때 복사한 프로세스를 자식프로세스라 한다.

부모 프로세스는 양수인 pid값을 부여받고 자식프로세스는 0을 부여받는다.

*pid는 os에서 프로세스를 식별하는 id값이며 PCB에 저장된다.


이 코드를 실행하면 메모리에는 실제로 같은 두개의 코드가 메모리에 존재하는것 이다.

출력결과를 보자면 oxoxoxox이런식이 아닌 oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxoooooooo............이런식으로 출력이 된다.

1) cpu는 하나의 프로세스만 실행하기 때문에 연속적인 출력을 하고

2) cpu는 하나의 프로세스를 무한정 실행시키지 않는다. os는 독점을 방지하기 위해 일정시간이 지나면 다른 프로세스에 cpu를 할당한다.


*자식프로세스가 fork함수로 인해 자식의 자식 프로세스를 무한정 생성하지 않을까?

os는 fork함수는 부모프로세스에서 한번만 실행되게 한다.

즉 자식 프로세스는 fork함수로 프로세스 복제를 안하고 pid만 부여 받는다.


프로세스 vs 실행중인 프로그램

- cpu를 할당의 차이. 보통 일반가정집의 cpu는 하나이기 때문에 하나의 프로세스만 처리 가능하다.

-메모리에는 여러개의 프로세스가 존재한다.

-실제 메모리 크기보다 더 많은 프로세스를 배치하기 위하여 사용하는것이 가상메모리 기법이다.



2. pipe함수 이해


파일 디스크립터 - 프로세스가 파일을 구별하는 id값(식별자) 이다. os가 할당해준다.

-리눅스의 경우는 소켓과 파일을 구별하는 디스크립터를 구분 하지 않는다.

-파일 디스크립터를 이용해 FCB(file control block : 파일정보)에 접근한다.

-표준입출력,에러 많이 쓰이는 파일은 0,1,2로 정해져 있다.



int pipe(int filedes[2]);

 

인자 : filedes[2] - 배열 인덱스 0은 수신파일의 파일디스크립터, 배열 인덱스 1은 발신파일의 파일디스크립터이다.

         사용자는 이 파일 디스크립터를 이용하여 송.수신을 한다.

반환 값 : 성공시 0, 실패시 -1


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

int main()
{
    int n, fd[2];
    char buf[255];
     int pid;

     if (pipe(fd) < 0) //송수신 파일 디스크립터를 할당 받는다.

//송신 파이프

//수신 파이프

//파이프도 파일이다

    {
        perror("pipe error : ");
        exit(0);
    }

    // 파이프를 생성한다.
    if ((pid = fork()) < 0) //자식프로세스는 fork 함수를 실행하지 않는다. id만 부여받는다.
    {
        perror("fork error : ");
        exit(0);
    }

    // 만약 자식프로세스라면 파이프에 자신의 PID 정보를 쓴다.
    else if (pid == 0)
    {
        close(fd[0]); // 수신 파일은 미사용
        while(1)
        {
            memset(buf, 0x00, 255);
            sprintf(buf, "Hello Mother Process. My name is %d\n", getpid());
            write(fd[1], buf, strlen(buf));
            sleep(1); //프로세스를 대기상태로 일정시간 동안 만든다.
            }
        }

        // 만약 부모프로세스라면 파이프에서 데이타를 읽어들인다.
        else
        {
            close(fd[1]); //송신 파일은 미사용
            while(1)
            {
                memset(buf, 0x00, 255);
                n = read(fd[0], buf, 255);
                fprintf(stderr, "%s", buf);
            }
        }
}

pipe는 반이중통신이라

전이중 통신으로 만들려면 코드가 복잡해진다.



3.메세지큐 사용


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

int msgget(key_t key, int msgflg); //메세지큐 생성(os에서 식별하는 메세지큐, 권한설정)

//반환 큐식별자값


int msgsnd (int msqid, (void *)msgp, size_t msgsz, int msgflg)

ssize_t msgrcv (int msqid, struct  msgbuf  *msgp,  size_t msgsz, 
                long msgtyp, int msgflg)

  • msqid : msgget를 이용해서 생성된 메시지큐 지시번호.
  • msgp : 보내고자 하는데이터.
  • msgsz : 보내고자 하는데이터의 크기
  • msgtyp : 읽고자하는 메시지의 타입.
    • msgtyp이 0이라면 큐의 첫번째 데이터를 읽어들인다.
    • msgtyp가 0보다 크면, 커널은 큐에서 msgtyp 번호를 가지는 가장 오래된 메시지를 찾아내서 되돌려진다.
  • msgflg : IPC_NOWAIT가 지정되면 비봉쇄모드로 작동한다. 즉 이용가능한 메시지가 없으면 기다리지 않고 바로 ENOMSG 를 반환한다. 그렇지 않으면 큐에 읽을 데이터가 쌓일때까지 기다린다.

struct msgbuf
{
    long mtype;             // 메시지 타입
    char mtext[BUFF_SIZE];  // 보내고자 하는 데이터
}



송신측

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

typedef struct {
    long mtype;     /* message type, must be > 0 */
    char mtext[16];  /* message data */
} MsgType;

void main(){

    key_t key = 4499;

    int que_id = msgget(key, IPC_CREAT | 0600);

    char mtext[6] = "hello";
    MsgType msg;
    int msg_size = 0;

    msg.mtype = 100; // pid = 생성한 process id 중 하나.

    strcpy(msg.mtext, "hello!!");

    msg_size = sizeof(msg) - sizeof(msg.mtype);

    // que_id는 msgget()을 통해 얻은 값
    int rtn = msgsnd(que_id, &msg, msg_size, 0);

    if (rtn == -1) {
        printf("msgsnd() fail\n");
    }
}

생성한 메세지큐는 ipcs -q 명령어로 확인한다.



수신측

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

typedef struct {
    long mtype;     /* message type, must be > 0 */
    char mtext[16];  /* message data */
} MsgType;

void main(){

    key_t key = 4499;

    int que_id = msgget(key, IPC_CREAT | 0600);

    MsgType msg;
    ssize_t nbytes = 0;
    int msg_size = 0;

    msg_size = sizeof(msg) - sizeof(msg.mtype);

    // pid = 자신의 process id, getpid() 함수로 얻을 수 있다.
    nbytes =  msgrcv(que_id, &msg, msg_size, 100, IPC_NOWAIT);

    if (nbytes > 0)
    {
        printf("recv msg form msgque, bytes(%d)\n", nbytes);
        // 수신한 메시지 처리.. 함수는 알아서 구현~~
        //procIpcMsg(msg);
        printf("recv : %s\n",msg.mtext);
    }
    else
    {
        if (nbytes == 0)
        {
            printf("no exist msg\n");
        }
        else
        {
            printf("msgrcv() error\n");
            return ;
        }
    }
}




이외에도 공유메모리,메모리맵,세마포어 가 있다 . 난중에 추가예정..

https://www.joinc.co.kr/w/Site/system_programing/Book_LSP/ch08_IPC 참조

반응형