Facebook Joinc 그룹   Joinc QA 사이트

1 IPC

1.1 IPC 소개

위의 그림은 2장에서 간단히 설명했던 리눅스 커널 구조그림이다. 이번장에는 이중 IPC 에 대해서 다룰 것이다.

   

그림에서 처럼 Process는 완전히 독립된 실행객체이다. 서로 독립되어있다는 것은 다른 프로세스의 영향을 받지 않는다는 장점이 있다. 그러나 독립되어 있으니 만큼 별도의 설비가 없이는 서로간에 통신이 어렵다는 문제가 있다. 이 문제는 이 전장의 쓰레드와 비교해보면 두드러진다.

   

이를 위해서 커널영역에서 IPC라는 내부 프로 세스간 통신 - Inter Process Communication -을 제공한다. 프로세스는 커널이 제공하는 IPC설비를 이용해서 프로세스간 통신을 할 수 있다.

   

1.2 System V IPC 와 POSIX IPC

IPC에는 두 가지 표준이 있다. 하나는 오래된 버전의 System V IPC이고, 다른 하나는 비교적 최근에 개발된 POSIX IPC다. System V IPC는 오랜 역사를 가진 만큼 이 기종간 코드 호환성을 확실히 보장해 주지만, API가 좀 구식이며 함수명도 명확하지 않다. POSIX IPC는 직관적으로 API가 구성되어 있어서 좀 더 사용하기 쉽다.

   

우선은 System V IPC를 다루고 나중에 시간이 되면 POSIX IPC를 다루도록 하겠다. 메커니즘은 동일 하므로 어느 것을 배우든 큰 문제는 되지 않을 것이다. 필요하면 System V IPC와 대응하는 POSIX IPC 함수들을 설명하도록 하겠다.

   

2 IPC 설비들

현실에서도 필요에 따라 다양한 통신 설비들이 존재하는 것처럼 IPC에도 다양한 설비들이 존재한다. 각각의 필요에 따라 적당한 통신설비들이 준비되어야 하는 것과 마찬가지로 내부 프로세스간 통신에도 그 상황에 맞는 IPC 설비를 선택할 필요가 있다.

   

상황에 맞는 IPC의 선택은 특히 fork를 이용해서 만들어진 멀티프로세스의 프로그램에 있어서 중요하다. 잘못된 IPC 설비의 선택은 코딩과정을 어렵게 만들거나 프로그램의 작동을 효율적이지 못하게 만들 수 있기 때문이다.

   

여기에서는 커널이 제공하는 각각의 IPC 설비들의 사용법과 장점및 단점 어떤 경우에 써야하는지에 대해서 설명할 것이다.

   

2.1 PIPE

pipe는 우리가 생각하는 그 파이프와 비슷하게 작동한다고 보면된다. 즉 수도 파이프와 같은 작동 원리다.

   

위 그림은 pipe의 작동원리를 보여주고 있다. 파이프는 두개의 프로세스를 연결한다. 하나의 프로세스는 단지 데이터를 쓰기만 하고 다른 하나의 프로세스는 단지 읽기만 할 수 있다. 한쪽 방향으로만 통신이 가능한 이러한 파이프의 특징 때문에 Half-duplex 통신 (반이중 통신) 라고 부르기도 한다. 이와 달리 하나의 통신선로를 이용해서 송신과 수신을 모두 할 수 있는 방식을 Full-duplex 통신 (전이중 통신)이라고 부른다.

   

pipe와 같은 반이중 통신의 경우 하나의 통신선로는 읽기나 쓰기 중 하나만 가능하기 때문에 만약 읽기와 쓰기 즉 송수신을 모두 하길 원한다면 아래처럼 두개의 pipe를 만들어야만 한다.

   

2.1.1 pipe의 사용

pipe는 pipe(2)라는 함수를 이용해서 만들 있다.

#include <unistd.h>

int pipe(int filedes[2]);

함수의 인자로 int형 배열이 들어가는 점에 유의하자. 배열이 넘어가는 이유는 이 함수가 읽기전용의 파이프와 쓰기전용의 파이프 2개를 리턴해 주기 때문이다. 배열의 0번째에는 읽기를 위한 파이프, 1번째에는 쓰기를 위한 파이프의 지시번호가 들어간다.

   

   

다음은 pipe를 통해서 통신을 하는 간단한 프로그램이다.

001 #include <unistd.h>
002 #include <stdlib.h>
003 #include <stdio.h>
004
005 int main()
006 {
007 int n, fd[2];
008 char buf[255];
009 int pid;
010
011 if (pipe(fd) < 0)
012 {
013 perror("pipe error : ");
014 exit(0);
015 }
016
017 // 파이프를 생성한다.
018 if ((pid = fork()) < 0)
019 {
020 perror("fork error : ");
021 exit(0);
022 }
023
024 // 만약 자식프로세스라면 파이프에 자신의 PID 정보를 쓴다.
025 else if (pid == 0)
026 {
027 close(fd[0]);
028 while(1)
029 {
030 memset(buf, 0x00, 255);
031 sprintf(buf, "Hello Mother Process. My name is %d\n", getpid());
032 write(fd[1], buf, strlen(buf));
033 sleep(1);
034 }
035 }
036
037 // 만약 부모프로세스라면 파이프에서 데이타를 읽어들인다.
038 else
039 {
040 close(fd[1]);
041 while(1)
042 {
043 memset(buf, 0x00, 255);
044 n = read(fd[0], buf, 255);
045 fprintf(stderr, "%s", buf);
046 }
047 }
048 }
049

  1. pipe(2)함수를 이용해서 파이프를 생성했다.
  2. fork(2)함수를 이용해서 자식프로세스를 생성한다.
    25~35. pid == 0 즉 자식 프로세스인 경우 실행될 코드다. 자식프로세스는 부모로부터 파일을 물려받는다 - 파이프도 파일이다 -. 여기에서 만들 자식프로세스는 단지 쓰기만 할 것이다. 그러므로 읽기를 위한 파이프는 close(2)를 이용해서 닫아버렸다. 이제 1초 간격으로 write(2)함수를 이용해서 쓰기파이프에 문자열을 쓴다.
    38~47 부모프로세스는 단지 읽기만 할 것이다. 그래서 쓰기파이프는 닫아버렸다. 그리고 read(2)함수를 이용해서 읽기 파이프에 읽을 데이터가 있는지를 기다린다.

   

2.1.2 pipe의 장점과 단점

pipe는 매우 간단하게 사용할 수 있다는 장점이 있다. 만약 한쪽 프로세스가 단지 읽기만 하고 다른 쪽 프로세스는 단지 쓰기만 하는 단순한 데이터 흐름을 가진다면 고민 없이 pipe를 사용하면 된다.

   

단점은 반이중 통신이라는 점이다. 만약 프로세스가 읽기와 쓰기 통신 모두를 해야 한다면 pipe를 두개 만들어야 하는데, 구현이 꽤나 복잡해 질 수 있다. readwrite가 기본적으로 block(봉쇄)로 작동하기 때문으로 프로세스가 read대기중이라면 read가 끝나기 전에는 write를 할수가 없게 된다. 만약 두개의 프로세스가 모두 read 중이라면 영원히 block되게 될 것이다.

   

이러한 문제는 fork를 이용해서 읽기 전용 프로세스와 쓰기 전용 프로세스 2개를 만들거나 혹은 (나중에 다루게 될)입출력 다중화를 이용해서 해결해야 한다. 어떤 방법을 쓰더라도 구현이 복잡해지는 걸 피할 수 없다.

   

만약 전이중 통신을 고려해야될 상황이라면 pipe 는 좋은 선택이 아니다.

   

2.2 FIFO

FIFO는 First In First Out 의 줄임말이다. 먼저 입력된게 먼저 출력되는 선입선출의 데이터 구조를 의미한다. IPC 설비로써의 FIFO 라면 먼저 입력된 데이터가 먼저 전달되는 내부통신 설비로 해석할 수 있을 것이다. 그러나 이러한 해석은 사용자를 혼란시키는 측면이 있다. 앞서의 pipe 역시 선입선출의 데이터 전달 메커니즘을 따르기 때문이다.

   

그러니 FIFO는 선입선출이라는 데이터구조로써의 범주가 아닌 named pipe라는 구조적 측면으로써 바라보도록 한다. 이하 FIFO는 named pipe라고 부르기로 하겠다.

   

2.2.1 pipe 와 named pipe

앞서 이미 배운 pipe와 named pipe의 차이점에 대해서 알아보도록 하자. 먼저 입력된 데이터가 먼저 전달되는 흐름을 가진다는 측면에서 동일한 데이터 흐름 메커니즘을 가진다.

   

차이점이라면 named pipe 는 사용할 pipe를 명명할 수 있다는 점이 될 것이다. pipe는 사용할 파이프를 명명할 수가 없다. 이런 의미에서 pipe는 때때로 익명 pipe라고 부르기도 한다.

   

그럼 파이프를 익명으로 만드는 것과 명명 - named - 해서 사용하는 것의 차이점에 대해서 알아보도록 하자.

   

익명 파이프는 데이터 통신을 할 프로세스가 명확하게 알 수 있을 때 사용한다. 송신할 프로세스는 수신할 프로세스를 알고, 수신할 프로세스는 송신할 프로세스를 아는 경우다. 가장 대표적인 예는 부모프로세스와 자식프로세스간에 데이터 통신을 하고자 하는 경우다. 자식 프로세스와 부모 프로세스는 서로를 명확히 알고 있으므로 굳이 파이프에 이름을 줄필요가 없을 것이다. 부모와 자식간이니 굳이 이름이 없어도 대화가 통하지 않겠는가 ?

   

반면, 자식과 부모프로세스가 아닌 즉 전혀 모르는 프로세스들 사이에서 pipe를 이용해서 통신을 해야하는 경우를 생각해보자. 생판 모르는 사람과 대화를 하려면 이름을 알고 있어야 하듯이, 전혀 관련없는 프로세스들 사이에서 pipe를 이용해서 통신을 하려면 pipe에 이름이 주어져야 한다. named pipe 를 만든 이유다.

   

이제 named pipe 가 존재하는 방식을 알아보도록 하자. 복잡하게 생각할 것 없다. 리눅스에서 모든 것은 파일로 통한다고 한 것을 기억하고 있을 것이다. named pipe도 파일로 존재한다. pipe 파일이 존재하고, 이 파일의 이름이 바로 pipe의 name이 된다. 파일은 시스템 전역적으로 관리하는 객체이니, 이름만 안다면 어떤 프로세스라도 접근이 가능하다. 이제 서로 관련없는 프로세스들도 named pipe를 이용해서 통신을 할 수 있게 되었다.

   

2.2.2 시스템 명령을 이용한 named pipe의 생성

named pipe는 파일의 형태로 존재하며 프로세스와 전혀 관련이 없기 때문에, 프로세스와 관련없이 독자적인 파일의 형태로 존재하게 할 수 있다. 해서 반드시 프로세스 생성후에 통신선로가 개설되는 pipe와 달리 named pipe는 미리 파일로 만들어 둘 수 있다. 일단 파일로 만들어 둔 다음에, 쓰고 싶은 프로세스가 파이프를 열어서 통신을 하는 방식이다. 공중전화와 비슷하다고나 할 수 있을 것 같다.

   

리눅스는 mkfifo 라는 시스템 명령어를 이용해서 named pipe를 생성할 수 있다.

# mkfifo mypipe

ls 를 이용해서 파일의 특성을 알아보도록 하자.

# ls -al mypipe
prw-r--r-- 1 yundream yundream 0 2009-04-16 19:23 mypipe

가장 앞의 p는 이 파일이 pipe 임을 의미한다. 성공적으로 mypipe라는 이름을 가지는 pipe가 생성되었음을 확인할 수 있다.

   

2.2.3 리눅스 표준라이브러리 함수를 이용한 named pipe의 생성

시스템 명령을 이용해서 named pipe (이하 파이프)를 생성할 수 있지만 이걸로는 좀 부족하다. 우리는 시스템 프로그래머 이니, 프로그램내에서 파이프를 생성할 수 있어야 한다. 리눅스는 표준 라이브러리에서 mkfifo(3)이라는 파이프 생성 함수를 제공한다.

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo ( const char *pathname, mode_t mode );

다음은 인자로 주어진 문자열을 이름으로 가지는 파이프를 생성하는 간단한 프로그램이다.

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
int state;
if (argc !=2 )
{
fprintf(stderr,"Usage : %s [filename]\n", argv[0]);
return 1;
}
state = mkfifo("/tmp/myfifo", S_IRUSR|S_IWUSR);
if (state < 0)
{
perror("mkfifo error \n");
return 1;
}
return 0;
}

2.2.4 mknod 시스템 호출을 이용한 파이프 생성

앞서 mkfifo(3)을 이용해서 간단하게 파이프를 생성해 보았다. 그러나 왠지 기분이 석연치 않다. 표준 라이브러리에서 제공하는 함수를 이용했기 때문이다. 그래도 시스템 프로그래밍이니 이왕이면, 시스템콜을 이용해서 저수준에서 접근을 해보아야만 할 것 같은 기분이 든다.

   

리눅스는 mknod(2)라는 시스템콜을 제공한다. mknod는 특수파일의 생성을 위해서 커널에서 제공하는 함수로 사용방법은 다음과 같다.

include <sys/stat.h>

int mknod(const char *path, mode_t mode, dev_t dev);

아래는 mknod를 이용해서 named pipe를 생성하는 간단한 프로그램이다.

#include <sys/stat.h>

int main(int argc, char **argv)
{
mknod(argv[1], S_IFIFO, 0);
return 0;
}

mknod는 named pipe 외에도 문자장치파일, 블럭장치파일, Unix Domain Socket등의 파일들도 생성할 수 있다. 자세한 내용은 mknod(2) 메뉴얼 문서를 참고하기 바란다.

   

2.2.5 named pipe를 이용한 데이터 통신

named pipe를 이용하면 전형적인 서버/클라이언트 모델을 따르는 프로그램의 작성이 가능하다. 클라이언트는 요청을 하는 프로그램이고 서버는 요청을 받아서 처리하고 그 결과를 되돌려주는 프로그램이다. 서버/클라이언트 모델은 일반적으로 인터넷 서비스에 매우 익숙한 방식이다. apache와 같은 웹서버firefox, ie 와 같은 클라이언트 프로그램이 대표적인 예이다.

   

시스템 프로그래밍에서도 이러한 서버/클라이언트 모델은 매우자주 사용된다. 인터넷에서의 서버/클라이언트 보다 그 역사도 오래되었다고 볼 수 있다.

   

여기에서는 간단한 계산 프로그램을 named pipe를 이용해서 만들어 보도록 하겠다. 이들 프로그램은 서버/클라이언트 모델을 따르도록 할 것이다. 서버프로그램의 이름은 calc_server.c 이고 클라이언트 프로그램의 이름은 calc.c 이다. calc.c 가 두개의 숫자를 named pipe를 이용해서 calc_server에 넘기면, calc_server 는 계산을 해서 calc로 넘겨주도록 할 것이다.

   

2.3 Message Queue

Queue(큐)는 선입선출의 자료구조를 가지는 통신설비로 커널에서 관리한다. 입출력 방식으로 보자면 named pipe와 동일하다고 볼 수 있을 것이다. named pipe와 다른 점이라면 name pipe가 데이터의 흐름이라면 메시지큐는 메모리공간이라는 점이다. 파이프가 아닌, 어디에서나 물건을 꺼낼수 있는 컨테이너 벨트라고 보면 될 것이다.

   

메시지큐의 장점은 컨테이너 벨트가 가지는 장점을 그대로 가진다. 컨테이너 벨트에 올라올 물건에 라벨을 붙이면 동시에 다양한 물건을 다룰 수 있는 것과 같이, 메시지큐에 쓸 데이터에 번호를 붙임으로써, 여러개의 프로세스가 동시에 데이터를 쉽게 다룰 수 있다.

   

2.3.1 메시지 큐의 생성

메시큐의 생성과 접근은 msgget(2) 함수를 통해서 이루어진다.

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

int msgget(key_t key, int msgflg);

  • key
    메시지큐는 커널에서 관리하는 자원으로 여러개의 메시지큐를 가질 수 있다. 그러므로 메시지큐를 실벽할 수 있는 key가 필요하다. 메시지큐는 이 key를 유일한 번호로 가지고 생성된다.
  • msgflg
    IPC_CREAT
    , IPC_EXEL와 권한을 설정하기 위해서 사용한다. IPC_CREAT는 메시지큐를 생성할 때 사용한다. IPC_CREATIPC_EXEL을 함께 사용하면, key를 가진 메시지큐가 존재 할때 에러를 리턴한다.

   

2.3.2 데이터 쓰기와 읽기

리눅스 커널은 쓰기와 읽기를 위해서 각각 msgsnd(2) 와 msgrcv(2) 함수를 제공한다.

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

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 를 반환한다. 그렇지 않으면 큐에 읽을 데이터가 쌓일때까지 기다린다.

   

보내고자 하는 데이터는 msgp를 이용해서 보내는데, 데이터 구조는 다음과 같다.

   

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

보내고자 하는 데이터는 어느정도 정형화 되어 있는 측면이 있다. 즉 mtype을 가져야 하는데, 이것을 이용해서 자기가 읽고 싶은 메시지 만을 읽어올 수 있다. mtype을 이용하면, 여러개의 데이터 큐가 있는 것처럼 사용할 수 있다.

   

2.4 공유메모리 - Shared Memory

데이터를 공유하는 방법에는 크게 두가지가 있다. 하나는 통신을 이용해서 데이터를 주고 받는 것이고, 다른 하나는 데이터를 아예 공유 w즉 함께 사용하는 것이다. pipe, named pipe, message queue가 통신을 이용한 설비라면 공유메모리가 데이터 자체를 공유하도록 지원하는 설비다.

   

프로세스는 자신만의 메모리영역을 가지고 있다. 이 메모리 영역은 다른 프로세스가 접근해서 함부로 데이터를 읽거나 쓰지 못하도록 커널에 의해서 보호가 된다. 만약 다른 다른 프로세스의 메모리 영역을 침범하려고 하면 커널은 침범 프로세스에 SIGSEGV 경고 시그널을 보내게 된다.

   

다수의 프로세스가 동시에 작동하는 linux 운영체제의 특성상 프로세스의 메모리영역은 반드시 보호되어야 할것이다. 그렇지만 메모리영역에 있는 데이터를 다른 프로세스도 사용할 수 있도록 해야할 경우도 있을 것이다. 물론 pipe등을 이용해서 데이터 통신을 이용해서 데이터를 전달하는 방법도 있겠지만 thread에서 처럼 메모리영역을 공유한다면 더 편하게 데이터를 함께 사용할 수 있을 것이다.

   

공유메모리는 프로세스간 메모리 영역을 공유해서 사용할 수 있도록 허용한다. 프로세스가 공유메모리 할당을 커널에 요청하면 커널은 해당 프로세스에 메모리 공간을 할당한다. 이후 어떤 프로세스든지 해당 메모리영역에 접근할 수 있다.

   

공유메모리는 중개자가 없이 곧바로 메모리에 접근할 수 있기 때문에 다른 모든 IPC들 중에서 가장 빠르게 작동한다.

   

   

2.4.1 공유메모리 함수들

공유메모리는 공간은 커널이 관리한다. 그러므로 프로세스가 종료되면 반환되는 메모리영역과는 달리 생선한 프로세스가 종료하더라도 공유메모리는 그대로 남아있게 된다.

   

공유메모리는 다음과 같은 과정을 거쳐서 사용한다.

  1. 공유메모리 영역을 생성을 요청한다.
  2. 공유메모리를 자신의 프로세스에서 맵핑해서 사용할 수 있도록 요청한다.
  3. 공유메모리를 사용한다.

이를 위해서 linux는 다음과 같은 함수를 제공한다.

#include <sys/types.h>
#include <sys/shm.h>

int shmget(key_t key, int size, int shmflg)
void *shmat( int shmid, const void *shmaddr, int shmflg )
int shmdt( const void *shmaddr)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)

shmget : 이 함수를 이용해서 공유메모리공의 생성을 요청할 수 있다.

  • key : 공유메모리는 커널에 의해서 관리되며, 각각 고유한 식별번호인 key를 가지고 있다. 이 key 번호를 이용해서 사용할 공유메모리를 명시할 수 있다.
  • size : 공유메모리의 최소 크기다. 만약 이미 생성된 공유메모리를 재사용하고자 한다면 크기를 0으로 한다.
  • shmflg : 공유메모리는 다른 프로세스도 접근할 수 있다. 그러므로 접근을 제어할 필요가 있는데, shmflag를 이용해서 접근권한을 명시할 수 있다. 또한 IPC_CREATIPC_EXCL을 이용해서, 생성방식을 명시할 수 있다.
    • IPC_CREAT : key를 식별번호로 가지는 공유메모리 공간을 생성한다.
    • IPC_EXCL : IPC_CREAT와 같이 사용되며, 만약 공유메모리 공간이 이미 존재할 경우 error를 리턴한다.

   

shmat : 이 함수를 이용해서 프로세스가 생성한 메모리를 생성된 공유메모리 영역으로 맵핑시킬 수 있다.

  • shmid : shmget을 이용해서 생성된 공유메모리의 식별번호.
  • shmaddr : 맵핑시킬 공유메모리영역의 주소
  • shmflg : 읽기전용, 읽고쓰기전용, 쓰기전용등의 접근방식을 정의할 수 있다.

   

shmdt : 프로세스가 더이상 공유메모리를 사용할 필요 없다면 이 함수를 이용해서 맵핑정보를 없앤다. 이것은 어디까지나 맵핑정보를 없애는 것일 뿐, 공유메모리를 없애는 것은 아니다.

   

shmctl : 공유메모리 영역을 제어하기 위해서 사용한다. 공유메모리를 삭제하거나 잠금의 설정 해제 혹은 권한을 변경하기 위한 목적으로 사용할 수 있다. 두번째 인자인 cmd를 이용해서 원하는 작업을 내릴 수 있다.

  • IPC_STAT : 공유메모리 공간의 정보를 가져오기 위해서 사용한다. 내용은 buf에 저장된다. 다음은 struct shmid_ds 의 설명이다.

    struct shmid_ds
    {
    struct ipc_perm shm_perm; // 퍼미션
    int shm_segsz; // 메모리 공간의 크기
    time_t shm_dtime; // 마지막 attach 시간
    time_t shm_dtime; // 마지막 detach 시간
    time_t shm_ctime; // 마지막 변경 시간
    unsigned short shm_cpid; // 생성프로세스의 pid
    unsigned short shm_lpid; // 마지막으로 작동한 프로세스의 pid
    short shm_nattch; // 현재 접근한 프로세스의 수
    };
  • IPC_SET : 공유메모리의 권한변경을 위해서 사용된다. 슈퍼유저혹은 공유메모리의 사용권한을 가지고 있어야 한다.
  • IPC_RMID : 공유메모리를 삭제한다. 이 명령을 사용한다고 해서 즉시 공유메모리가 삭제되지는 않는다. 다른 프로세스가 공유메모리를 사용하고 있을 수도 잇기 때문이다. 그래서 공유메모리를 맵핑해서 사용하는 프로세스의 갯수가 0, 즉 shm_nattch 가 0일때까지 기다렸다가 삭제된다. 해당 공유메모리영역에 삭제표시를 하는 것이라고 보면 될것 같다.

   

   

2.4.2 공유메모리 다루기

이제 공유메모리를 이용해서 데이터를 공유하는 간단한 프로그램을 만들어보도록 하겠다. 우선 check_process.c라는 프로그램을 하나 만들 것이다. 이 프로그램은 현재 시스템에서 실행중인 프로세스의 갯수를 1초단위로 계산해서 공유메모리 영역에 쓰는 일을 한다. 다음으로 get_process_num.c이라는 프로그램을 만들 건데, 이 프로그램은 공유메모리 영역에 접근해서 실행중인 프로세스의 갯수를 얻어와서 화면에 출력하는 일을 한다.

   

프로세스의 갯수는 popen(3)함수를 이용해서, ps(1)를 실행시킨 다음 라인수를 계산해서 얻어오도록 하겠다. 프로세스 갯수는 proc파일시스템을 이용해서 얻어올 수도 있겠지만 아직 proc를 다루지 않은관계로 간단한 popen을 이용하기로 했다.

   

001 #include <sys/ipc.h>
002 #include <sys/shm.h>
003 #include <string.h>
004 #include <unistd.h>
005 #include <stdlib.h>
006 #include <stdio.h>
007
008 int main(int argc, char **argv)
009 {
010 int shmid;
011 void *shared_memory = (void *)0;
012 FILE *fp;
013 char buff[1024];
014 int skey = 5678;
015
016 int *process_num;
017 int local_num;
018
019 // 공유메모리 공간을 만든다.
020 shmid = shmget((key_t)skey, sizeof(int), 0666|IPC_CREAT);
021 if(shmid == -1)
022 {
023 perror("shmget failed : ");
024 exit(0);
025 }
026
027 // ipcs(s)를 이용해서 확인하기 위함.
028 printf("Key %x\n", skey);
029
030 // 공유메모리를 맵핑한다.
031 shared_memory = shmat(shmid, (void *)0, 0);
032 if(!shared_memory)
033 {
034 perror("shmat failed : ");
035 exit(0);
036 }
037
038 process_num = (int *)shared_memory;
039
040 for (;;)
041 {
042 local_num = 0;
043 fp = popen("ps axh", "r");
044 if(fp != NULL)
045 {
046 while(fgets(buff,1024, fp))
047 {
048 local_num++;
049 }
050 }
051 *process_num = local_num;
052 printf("process_num is %d\n", (int)*process_num);
053 sleep(5);
054 pclose(fp);
055 }
056 }
057

20 shmget 을 이용해서 공유메모리 공간을 생성했다. key 번호는 5678로 했다.

28 skey를 16진수로 표시했다. 리눅스는 ipcs(1)라는 ipc 관리 프로그램을 제공하는데, 여기에서는 key 번호가 16진수로 표시되기 때문에 확인을 쉽도록 하기 위함이다.

31 shmat를 이용해서 공유메모리를 맵핑한다.

40 ~ 50 popen(3)을 이용해서 ps(1)를 실행시키고, 라인수를 계산했다. 라인수가 프로세스의 갯수이다. 프로세스의 갯수는 공유메모리 공간에 저장한다. 이제 다른 프로세스에서 공유메모리 공간에 접근해서 프로세스의 갯수를 얻어올 수 있게 되었다.

   

이제 공유메모리 공간에 접근해서 프로세스의 갯수를 읽어오는 프로그램을 만들어 보도록 하겠다. 이 프로그램의 이름은 read_process_num.c 로 하겠다.

   

001 #include <sys/ipc.h>
002 #include <sys/shm.h>
003 #include <string.h>
004 #include <unistd.h>
005 #include <stdlib.h>
006 #include <stdio.h>
007
008 int main(int argc, char **argv)
009 {
010 int shmid;
011 int skey = 5678;
012
013 int *shared_memory;
014
015 shmid = shmget((key_t)skey, sizeof(int), 0666);
016 if(shmid == -1)
017 {
018 perror("shmget failed\n");
019 exit(0);
020 }
021
022 shared_memory = shmat(shmid, (void *)0, 0);
023 if(!shared_memory)
024 {
025 perror("shmat failed : ");
026 exit(0);
027 }
028 printf("shm id : %d\n", shmid);
029 while(1)
030 {
031 int num = *shared_memory;
032 printf("Process Num : %d\n", num);
033 sleep(1);
034 }
035 }
036

  • 11 : 사용할 공유메모리의 키번호는 5678 이다.
  • 15~19 : shmget 를 이용해서, 공유메모리 식별자를 얻어온다.
  • 22~27 : shmat 를 이용해서 공유메모리를 매핑한다.
  • 29~34 : 1초 간격으로 돌면서 공유메모리의 내용을 읽어온다.

   

check_process 를 먼저 실행시키고, 그후 get_process_num을 실행시키면, 공유메모리에 있는 프로세스갯수를 읽어오는 것을 확인할 수 있을 것이다.

   

2.4.3 장점과 한계

공유메모리는 비교적 간단하게 사용할 수 있다. 또한 커널메모리영역에서 관리하기 때문에 매우 빠르게 접근가능하다는 장점도 가진다. 그러나 커널설정에 종속적이기 때문에, 사용하기전에 커널에서 허용하고 있는 공유메모리 세그먼트의 크기를 확인해야 한다.

   

일반적으로 리눅스커널의 초기값은 32MB로 잡혀있다. 상당히 작은 크기인데, 다행이 2.6 이상의 커널에서는 단일 공유메모리 세그먼트의 크기를 1GB까지 사용할 수 있도록 지원되고 있다. 1GB면 왠만한 애플리케이션을 다루는데에는 큰 문제 없을 것으로 생각된다.

   

공유메모리 세그먼트의 크기는 /proc/sys/kernel/shmmax 에서 확인할 수 있다.

# cat shmmax
33554432

다음과 같이 세그먼트의 크기를 변경할 수 있다. 512MB로 확장하고 싶다면, 아래와 같이 파일에 써주기만 하면 된다.

# echo "536870912" > /proc/sys/kernel/shmmax
혹은
# echo "512*1024*1024" | bc(3) > /proc/sys/kernel/shmmax

공유메모리는 메시지 전달 방식이 아니기 때문에 데이터를 읽어야되는 시점을 알 수 없다는 단점을 가진다. 이 문제를 해결하려면 다른 IPC 설비들을 응용해야 한다.

   

2.5 Memory Map

메모리맵도 공유메모리 공간과 마찬가지로 메모리를 공유한다는 측면에 있어서는 서로 비슷한 측면이 있다. 다른점은 메모리맵의 경우 열린파일을 메모리에 맵핑시켜서, 공유한다는 점일 것이다. 파일은 시스템전역적인 자원이니 서로 다른 프로세스들끼리 데이터를 공유하는데 문제가 없을 것임을 예상할 수 있다.

   

메모리맵으로 할 수 있는 일들은 다음과 같다.

   

2.5.1 Memory map 생성과 삭제

리눅스는 mmap(2)라는 시스템 함수를 제공 한다. 이 함수를 이용해서, 열려진 파일을 메모리에 맵핑시킬 수 있다.

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);

  • addr : NULL일경우 매핑시킬 메모리 영역을 커널이 선택한다. 이반적으로 NULL을 사용하면 된다. mmap은 매핑된 메모리를 가리키는 주소를 반환한다.
  • length : offset에서 시작하여 length 만큼을 주소로 대응하도록 한다. 보통은 0으로 지정한다.
  • prot : 메모리 보호모드를 설정하기 위해서 사용한다.

PROT_EXEC

페이지는 실행될 수 있다.

PROT_READ

페이지는 읽을 수 있다.

PROT_WRITE

페이지는 쓰여질 수 있다.

PROT_NONE

페이지는 접근될 수 없다.

  • fd : 대응시킬 파일의 파일지정번호
  • flag : 대응되는 객체의 타입, 페이지 복사본에 대한 수정이 다른 프로세스도 가능하게 할것인지, 혹은 복사할 것인지, 독립된 메모리 영역으로 복사시킬 건지등을 결정 한다.

MAP_FIXED

지정된 주소 이외의 다른 주소를 선택하지 않는다. 사용하지 않는게 좋다.

MAP_SHARED

다른 프로세스들과 대응영역을 공유한다.

MAP_PRIVATE

copy-on-write 한다. 즉 독립적으로 다른 프로세스에 복사된다. 대응영역이 공유되지 않는다.

2.5.2 예제 : 생산자

간단한 예제 프로그램을 만들어 보기로 했다. 이 프로그램은 mymmap.mm이라는 파일을 만들고 메모리에 대응시킨다. 대응시킨 메모리에는 int형 데이터를 쓴다.

001 #include <stdio.h>
002 #include <stdlib.h>
003 #include <string.h>
004 #include <unistd.h>
005 #include <fcntl.h>
006 #include <sys/mman.h>
007
008 int main()
009 {
010 int fd;
011 int *pmmap;
012 int i;
013 fd = open("mymmap.mm", O_RDWR|O_CREAT, 0666);
014 if(fd < 0)
015 {
016 perror("open");
017 exit(1);
018 }
019 ftruncate(fd, 4096);
020
021 pmmap = (int *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
022 if((unsigned)pmmap == (unsigned)-1)
023 {
024 perror("mmap");
025 exit(1);
026 }
027
028 for(i = 0; i < 100; i++)
029 {
030 pmmap[i] = i*i;
031 }
032 pmmap[i+1] = -1;
033 getchar();
034 munmap(pmmap, 4096);
035 close(fd);
036 return 0;
037 }
038

  1. 13 : open(2) 함수를 이용해서 mymap.mm 파일을 오픈한다.
  2. 19 : 파일이 메모리에 대응되고 데이터가 저장되기 때문에, 데이터의 사이즈를 예상해서 적당한 파일크기를 만들어줘야 한다. malloc(2)대신 사용하는 거라고 볼 수 있다. 파일의 크기는 4096으로 잡았고, ftruncate(2)라는 함수를 이용해서 파일을 생성했다.
  3. 21 : mmap(2)를 이용해서 mymap.mm 파일을 메모리에 대응시킨다.
  4. 28-31 : 만들어진 메모리맵에 int형 데이터를 쓴다. 100개의 값을 저장하기로 했으니, 100 * sizeof(int) 만큼의 공간이 사용될 것이다.
  5. 32 : 마지막에 -1을 입력한다. 배열의 끝임을 알려주기 위해서 사용했다.
  6. 33 : getchar(3)함수로 키보드 입력을 기다린다.

   

2.5.3 예제 : 소비자

이 프로그램은 위에서 만들어진 메모리맵 파일의 데이터를 읽어오는 일을 한다.

001 #include <sys/stat.h>
002 #include <sys/mman.h>
003 #include <unistd.h>
004 #include <stdlib.h>
005 #include <fcntl.h>
006
007 int main(int argc, char **argv)
008 {
009 int fd;
010 int i=0;
011 char *file = NULL;
012 char *linebuf;
013 int *maped;
014 int flag = PROT_WRITE | PROT_READ;
015
016 if ((fd = open("mymmap.mm", O_RDWR, 0666)) < 0)
017 {
018 perror("File Open Error");
019 exit(1);
020 }
021
022 // mmap를 이용해서 열린 파일을 메모리에 대응시킨다.
023 // file은 대응된 주소를 가리키고, file을 이용해서 필요한 작업을
024 // 하면 된다.
025 if ((maped =
026 (int *) mmap(0, 4096, flag, MAP_SHARED, fd, 0)) == -1)
027 {
028 perror("mmap error");
029 exit(1);
030 }
031
032 while(1)
033 {
034 if (maped[i] == -1) break;
035 printf("> %d\n",maped[i]);
036 i++;
037 }
038 close(fd);
039 }
040

  1. 32-37 : 배열의 끝. 즉 배열의 값이 -1인게 확인될 때까지 루프를 돌면서 메모리맵에 저장된 데이터를 읽어 온다.

   

2.5.4 메모리 맵의 장점

메모리맵은 파일을 메모리에 대응시킴으로써, 프로세스간 메모리를 서로 공유할 수 있다는 IPC로서의 장점을 가진다는 것을 알 수 있다. 이외에 또다른 장점이 있는데, 파일 입출력에서의 비용을 줄일 수 있다는 점이다. 파일에서의 작업은 open(2), read(2), write(2), lseek(2)와 같은 상당한 비용을 지불하는 함수를 통해서 이루어진다. 매모리 맵을 이용하면 이러한 비용을 줄일 수 있다.

   

또하나의 장점은 메모리의 내용을 파일로 남길 수 있다는 점이다. 메모리의 내용은 휘발성으로 프로세스가 종료되면 증발하게 된다. 보통 메모리의 정보를 남겨야할 필요가 생기면 프로세스의 종료전에 파일로 남기는데, 메모리맵의 경우 파일로 대응되기 때문에, 비교적 안전하게 정보를 남길 수 있다는 장점도 가진다.

   

2.6 세마포어 - Semaphore

세마포어는 전통적인 IPC 설비의 하나로 제공되기는 하지만 다른 IPC 설비와는 약간 다른 특징을 가진다. 다른 IPC 설비들은 모두가 데이터를 공유하기 위한 특징을 가지는데 반해서 세마포어는 자원에 대한 접근을 제어하기 위한 목적으로 사용된다. 세마포어 그 자체가 데이터를 공유하기 위한 어떤 공간을 제공하지는 않는다는 얘기다. 대게의 경우에는 다른 IPC설비를 지원하기 위한 이유로 사용된다.

   

매모리맵을 예로 들어보자. 여러개의 프로세스가 하나의 메모리맵에 엑세스를 한다면, 메모리맵에 한번에 하나씩의 프로세스만 접근이 가능하도록 제어할 필요가 있을 것이다. 그렇지 않다면 다음과 같은 문제가 발생할 수 있다.

   

count ++ 하는 프로그램

  1. 메모리맵에 0이 저장되어 있다. count = 0;
  2. A 프로그램이 메모리맵의 값을 읽어들인다. count = 0;
  3. B 프로그램이 메모리맵의 값을 읽어들인다. count = 0;
  4. A 프로그램이 매모리맵의 값 + 1 한다. count = 1;
  5. B 프로그램이 매모리맵의 값 + 1 한다. count = 1;

   

뭔가 잘못되었다는 것을 알 수 있다. A와 B 프로세스가 count++ 을 했으니, count 에는 2가 들어있어야 겠지만 접근제어가 되지 않은 관계로 count에 1이 들어 있다.

   

이 문제는 특정 영역에 단지 하나의 프로세스만 진입가능하도록 하는 것으로 해결할 수 있을 것이다.

   

count ++ 하는 프로그램 : 접근제어를 한 버전

  1. 메모리맵에 0이 저장되어 있다. count = 0;
  2. A 프로그램이 메모리맵의 값을 읽어들인다. count = 0;
  3. 다른 프로세스가 접근하지 못하도록 한다.
    1. B 도 메모리맵의 값을 읽을려고 하지만 접근을 하지 못하기 때문에 대기한다.
  4. A 프로그램이 매모리맵의 값 + 1 한다. count = 1;
  5. 다른 프로세스가 접근하도록 허용한다.
  6. 기다리던 B 프로세스가 메모리맵의 값을 읽어들인다. count = 1;
  7. B 프로세스가 +1 연산을 한다. count = 2;

바로 세마포어를 이용해서 할 수 있는 일이다.

   

2.6.1 세마포어의 작동원리

세마포어 S는 정수값을 가지는 변수며, PV 두개의 명령에 의해서 접근할 수 있다. P테스트를 위한 명령이며 V증가를 위한 명령이다.

   

진입을 제한해야 하는 영역을 임계영역이라고 하면, P는 임계구역에 진입하기 위해서 수행이되고, V는 (작업을 마치고)임계영역에서 나올때 수행된다. 당연히 PV 명령의 수행은 원자성을 보장해야 한다. 하나의 프로세스가 PV를 이용해서 세마포어 값을 변경할때, 다른 프로세스가 이 값을 변경할 수 있으면 안된다.

   

  • P(S) 를 이용해서, 세마포어의 값을 테스트한다.
    • 세마포어의 값이 1이라면, 임계영역에 들어가게 된다.
    • 세마포어의 값은 1만큼 감소한다.
    • 이제 세마포어의 값은 0이기 때문에 다른 프로세스는 임계영역에서 입구에서 대기해야 한다.
  • V(S) 를 이용해서, 세마포어의 값을 증가한다.
    • 작업을 마치고 임계영역을 빠져나갈때, 세마포어의 값을 1증가한다.
    • 세마포어의 값이 1이 되었기 때문에, 대기하던 프로세스가 임계영역에 진입할 수 있게 된다.

   

2.6.2 세마포어의 사용

세마포어는 3개의 함수를 제공한다. 즉

  1. 세마포어의 생성 : 자원을 사용하기 위해서 알림판을 만드는 거라고 보면 된다.
  2. 세마포어의 획득 및 되돌려주기 : 알림판을 사용가능/불가능으로 만드는 작업
  3. 세마포어의 세부값 제어

   

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

int semget(key_t key, int nsems, int semflg);
int semop (int semid, struct sembuf *sops, unsigned nsops);
int semctl(int semid, int semnum, int cmd, union semun arg);

세마포어는 커널이 관리한다. semget을 이용해서 커널에 세마포어의 생성 혹은 기존에 만들어진 세마포어의 접근을 요청할 수 있다. semget의 인자는 다음과 같다.

  • key : 세마포어에 접근하기 위한 key 값
  • nsems : 세마포어 계수로 접근제하하려는 자원의 수
  • semflg : 세마포어 동작제어를 위한 옵션

IPC_CREATE

key에 해당하는 세마포어가 없다면 새로 생성한다.

IPC_EXCL

세마포어가 이미 있다면, 에러를 리턴해서 세마포어에 접근하지 못한다. 이미 열려진 세마포어에 접근하려면 이 옵션이 없어야 한다.

2.6.3 세마포어 예제 프로그램

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

#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdio.h>

#define MAX_THREAD 2

int count = 0;

void *myThreadFunc(void *data);

struct sembuf mysem_open = {0, -1, SEM_UNDO};
struct sembuf mysem_close = {0, 1, SEM_UNDO};

union snum
{
int val;
};

static int semid;

int main(int argc, char **argv)
{
int thr_id;
int status;
int i;
union snum s_union;
pthread_t pt[MAX_THREAD];

semid = semget(2345, 1, 0600|IPC_CREAT);

if(semid == -1)
{
perror("semget error");
return 1;
}

s_union.val = 1;
if(semctl(semid, 0, SETVAL, s_union) == -1)
{
return 1;
}

for(i = 0; i < MAX_THREAD; i++)
{
thr_id = pthread_create(&pt[i], NULL, myThreadFunc, (void *)&i);
if(thr_id < 0)
{
perror("Thread Create Error");
return 1;
}
sleep(1);
}
for(i = 0; i < MAX_THREAD; i++)
{
pthread_join(pt[i], NULL);
}
}

void *myThreadFunc(void *data)
{
int thread_num = *(int *)data;
int lnum;
printf("Thread Create %d\n", thread_num);
while(1)
{
semop(semid, &mysem_open, 1);
lnum = count;
sleep(1);
lnum = lnum+1;
count = lnum;
printf("[%d] count : %d\n", thread_num, count);
semop(semid, &mysem_close, 1);
}
}

이 프로그램은 카운팅 프로그램이다. 두 개의 스레드가 하나의 count 변수에 접근하는데, 세마포어를 이용해서 접근을 제어하고 있다. 스레드 함수인 myThreadFunc에서 semop 부분을 주석 처리한 후 어떤 결과가 나오는지 확인해 보도록 하자.

   

2.6.4 세마포어의 장점과 단점

세마포어는 변수의 값을 확인해서 임계영역으로의 진입을 제어한다. 그렇다면 프로그램변수로도 임계영역의 진입을 제어할 수 있을 것이다. 대략 다음과 같다.

   

P(S)
{
while (S <= 0)
continue;
S--;
}
/* 임계영역 */

V(S)
{
S++;
}

매우 간단한 구현으로 보이지만, 이방법을 이용하게 될 경우 프로세스가 busy wait 상태에 놓이기 된다. 또한 다른 프로세스들간에는 사용하기 힘들다는 문제점도 가진다. 반면 세마포어는

  1. busy wait 상태에 놓이지 않는다.
  2. 커널에서 관리되기 때문에 다른 프로세스들간에도 사용할 수 있다.

는 장점을 가진다.

   

세마포어를 제어하기 위해서는 P함수와 V함수를 사용해야 하는데, 이 두개의 함수는 독립적이다. 때문에 잘못사용하게 될경우 deadlock에 빠질 수 있다.

   

2.7 Socket

Socket는 물리적으로 멀리 떨어져 있는 컴퓨터끼리의 통신을 도와주기 위한 통신계층이다. Socket은 원격통신을 위한 여러가지 함수들을 제공하는데, 이들을 이용해서 물리적으로 떨어진 컴퓨터 간의 통신이 가능하게 된다. 인터넷을 이용한 통신 프로그램의 대부분이 socket 기반으로 작성된다고 보면 틀림없을 것이다.

   

컴퓨터와 컴퓨터간의 통신이라고는 하지만 실질적으로는 이쪽 컴퓨터의 프로세스와 저쪽 컴퓨터의 프로세스가 통신을 하는 것다. 이렇게 프로세스간 통신을 한다는 점에서 봤을 때 IPC설비와 근본적으로 다른점은 없다고 볼 수 있다. 차이점이라면 통신이 이루어지는 영역이 컴퓨터 내부인지 아니면 온라인인지 하는 것이될 것이다.

   

비록 socket이 원격의 컴퓨터 프로세스들간의 통신을 위한 도구이지만 이러한 프로세스간 통신이라는 비슷한 특성으로 내부 프로세스간 통신을 위한 방법을 제공한다. 즉 외부 프로세스간 통신으로 사용할건지 내부 프로세스간 통신으로 사용할 건지를 선택할 수 있게끔 하고 있다. socket는 단일 주제만으로도 책한두권은 만들어낼 수 있는 방대한 양이다. 여기에서는 socket의 기능중 내부 프로세스간 통신지원 기능에 대해서만 알아보도록 할 것이다.

   

2.7.1 Unix Domain Socket 의 장점

Unix Domain Socket(이하 소켓)의 가장 큰 장점은 네트워크 통신에 사용하던 기술을 그대로 사용할 수 있다는 점일 것이다. 코딩의 일관성을 유지할 수 있도록 도와준다. 얻을 수 있는 장점은 단지 함수를 그대로 사용할 수 있다는 점 이상이다. 다수의 클라이언트를 동시에 처리하기 위한 방법, 메시지 관리를 위한 방법등 네트워크 프로그래밍에서 사용하던 응용기술들 역시 그대로 사용할 수 있다는 장점을 가진다.

   

또한 소켓은 다른 IPC 설비와는 달리 꽤나 높은 수준에서 추상화가 되어 있어서, 좀더 직관적으로 프로그램을 작성할 수 있다.

   

다른 IPC 설비 들은 특정용도에 맞도록 제작된 측면이 있어서, 어떤 곳에서는 효율적이지만 또다른 곳에서는 비효율적이거나 컴퓨터자원의 제한을 많이 받는다거나 하는 단점이 있다. 이에 비해서 소켓은 매우 범용적으로 사용할 수 있다. 물론 범용적으로 사용할려면 그만큼 생각해야 할 것들이 좀더 있을 수 있긴하다.

   

파이프로도 충분한 간단한 프로그램에 소켓을 사용하는 건 비효율적이긴 하지만 어느정도 이상의 규모가 된다면 소켓을 이용하는 걸 추천한다.

   

2.7.2 Unix Domain Socket 예제

이 프로그램은 에코서버/클라이언트의 IPC 버전이다.

   

먼저 서버 프로그램이다.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE 1024
int main(int argc, char **argv)
{
int server_sockfd, client_sockfd;
int state, client_len;
pid_t pid;

FILE *fp;
struct sockaddr_un clientaddr, serveraddr;

char buf[MAXLINE];

if (argc != 2)
{
printf("Usage : %s [socket file name]\n", argv[0]);
printf("예 : %s /tmp/mysocket\n", argv[0]);
exit(0);
}

if (access(argv[1], F_OK) == 0)
{
unlink(argv[1]);
}

// internet 기반의 스트림 소켓을 만들도록 한다.
client_len = sizeof(clientaddr);
if ((server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
perror("socket error : ");
exit(0);
}
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sun_family = AF_UNIX;
strcpy(serveraddr.sun_path, argv[1]);

state = bind(server_sockfd , (struct sockaddr *)&serveraddr,
sizeof(serveraddr));
if (state == -1)
{
perror("bind error : ");
exit(0);
}

state = listen(server_sockfd, 5);
if (state == -1)
{
perror("listen error : ");
exit(0);
}

while(1)
{
client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr,
&client_len);
pid = fork();
if (pid == 0)
{
if (client_sockfd == -1)
{
perror("Accept error : ");
exit(0);
}
while(1)
{
memset(buf, 0x00, MAXLINE);
if (read(client_sockfd, buf, MAXLINE) <= 0)
{
close(client_sockfd);
exit(0);
}
write(client_sockfd, buf, strlen(buf));
}
}
}
close(client_sockfd);
}

다음은 클라이언트 프로그램이다.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE 1024

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

int client_len;
int client_sockfd;

FILE *fp_in;
char buf_in[MAXLINE];
char buf_get[MAXLINE];

struct sockaddr_un clientaddr;

if (argc != 2)
{
printf("Usage : %s [file_name]\n", argv[0]);
printf("예 : %s /tmp/mysocket\n", argv[0]);
exit(0);
}

client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (client_sockfd == -1)
{
perror("error : ");
exit(0);
}
bzero(&clientaddr, sizeof(clientaddr));
clientaddr.sun_family = AF_UNIX;
strcpy(clientaddr.sun_path, argv[1]);
client_len = sizeof(clientaddr);

if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) < 0)
{
perror("Connect error: ");
exit(0);
}
while(1)
{
memset(buf_in, 0x00, MAXLINE);
memset(buf_get, 0x00, MAXLINE);
printf("> ");
fgets(buf_in, MAXLINE, stdin);
write(client_sockfd, buf_in, strlen(buf_in));
read(client_sockfd, buf_get, MAXLINE);
printf("-> %s", buf_get);
}

close(client_sockfd);
exit(0);
}

   

<http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/system_programing/Book_LSP/ch08_IPC>에서 삽입

반응형

2007/10/19 - 4:45오후

  • 제가 시험관계로 조사&정리한 내용입니다.

    어떤 서브루틴이의 인자에 대한 변경이 원래 변수의 값에 영향을 미칠 call by reference라고 한다. 포인터를 이용하면 주소 값을 전달해주기 때문에 call by reference 흉내 수는 있지만 call by reference 아니다.

    포인터를 사용한 call by reference 흉내 경우 호출된 함수의 스택에 넘겨받은 주소를 보관하기 위한 로컬 변수가 생성된다. 하지만, call by reference 지원하는 언어의 경우 스택에 넘겨받은 주소를 보관하지 않는다.

    call by reference 지원하는 언어로 C++ 참조형연산자(&) FORTRAN등이 있다.

    참조형과 포인터 변수와의 차이점은 주어진 주소를 변경할 있느냐이다. 참조형 변수를 한번 선언하면 가리키고 있는 기억 장소에 대한 주소를 변경할

    없다.

    질문

    1.그럼 c++ 참조형 연사자는 데이터영역에 저장이 되나요??

    2.제가 찾은 URl(http://tpcall.tistory.com/archive/20061030)에서는 JAVA reference 타입도 call by reference라는데 맞는 얘기인가요??

    3.저희 교수님은 배열은 call by reference 동작한다는데 맞는 이야기인가요??

    1.다른 언어는

    글쓴이: chadr 작성 일시: , 2007/10/19 - 7:46오후

    1.다른 언어는 모르겠지만 c++ 경우 레퍼런스로 함수 인자를 선언했을 스택에 해당 변수의 주소가 push됩니다..

    2.자바의 경우에는 기본타입 스트링을 제외한 것은 모두 레퍼런스라고 알고 있습니다. 하지만 질문자님께서 알고 계신 "스택에 푸시 안하고 넘어가는 참조" 아닐겁니다. 동적으로 메모리에 할당 되는 데이터 값을 스택과 같은 임시 장소에 주소를 push하지 않고 참조 할려면 항상 고정된 주소가 있어야하는데, 동적이다보니 그런건 불가능하니까요.. 자세히 알아볼려면 바이트코드를 디스어셈블 해봐야 알겠지만요..

    3.c++ 경우에는 배열을 인자로 선언하고 넘겨주면 레퍼런스 형식으로 넘어갑니다. 배열의 모든 원소가 스택에 복사되지는 않습니다. 물론 여기서 레퍼런스도 "스택에 푸시 안하고 넘어가는 참조" 아닙니다.

    .. c++ 포인터를 사용한 레퍼런스입니다.

    ps. 포인터를 이용하여 구현한 레퍼런스가 아닌 경우에는 어떻게 구현하는지 저도 궁금해지는군요..:)

    -------------------------------------------------------------------------------

    It's better to appear stupid and ask question than to be silent and remain stupid.

    -------------------------------------------------------------------------------

    It's better to appear stupid and ask question than to be silent and remain stupid.

    »

  • 글쓴이: klutzy 작성 일시: , 2007/10/20 - 9:46오후

    call by reference 원래 변수의 위치를 파라미터로 넘기는 것이 정상입니다. C 포인터를 이용해 call by ref 구현할 있는 것이고요.

    자세히.. 변수가 가지는 값에는 L-value R-value 있습니다. L-value 변수가 존재하는 메모리 위치의 (포인터)이고, R-value 변수가 가지고 있는 실제 값입니다. 여기에서 call by value 파라미터로 R-value, call by ref L-value 넘겨줍니다. 언어 차원에서 reference 지원이 없는 C 대신 L-value 맘대로 있기 때문에 구현이 가능한 거고요. 언어 차원에서 call by ref 지원하는 경우도 내부 구현은 변수의 주소값입니다.

    배열 같은 경우도 딱히 어떤 방식이냐 따지는 것이 의미가 없어 보이네요. 그냥 배열 자체를, 여러 값들이 모여 있는 장소의 위치값을 가지는 reference value 보는 간단합니다.

    »

  •    

    C/C++에서는 배열을

    글쓴이: 익명 사용자 (미확인) 작성 일시: , 2007/10/21 - 12:02오전

    C/C++에서는 배열을 직접 매개변수로 전달할 없습니다. 함수 선언의 매개변수 부분에서 배열은 포인터로 자동 변환됩니다.

    void f(int arr[3]) // 실제로는 void f(int *arr) 된다

    {

    printf("%d", *arr++); // 배열에 ++연산자를?

    printf("%d", *arr);

    }

    배열에 ++연산자를 적용하니 안될꺼 같죠? 됩니다. 위의 코드는 100% 적법한 코드입니다. 이건 위의 코드에서 변수 arr 실제 타입이 pointer to int이기 때문입니다. 또한, 함수 내부에서 sizeof(arr) 하게 되면 int* 크기가 반환되지 배열의 크기가 반환되지는 않습니다.

    이러한 이유 때문에 C/C++에서 배열이 call by reference 전달된다고 말하는 것은 틀린 설명입니다. 프로그래머는 배열을 전달한다고 믿고 있겠지만, 실제로는 배열의 첫번째 원소를 가리키는 주소값이 call by value 함수 내부의 매개변수로 복사됩니다.

    , C++에서는 참조 연산자 & 이용해서 배열을 직접 매개변수로 전달할 있습니다. 이게 바로 진정한 call by reference 입니다. 하지만 여전히, &연산자를 사용하지 않는 경우에는 배열을 매개변수로 직접 사용할 없습니다. 변환되는 과정이 자동으로 숨겨져서 이루어지기 때문에 프로그래머가 알아채기는 쉽지 않지만 말입니다.

    자바에서는 배열이 call by reference 전달됩니다. 정확히 말하자면 기본형이 아닌 타입의 함수 매개변수는 모두 call by reference 전달됩니다. 때문에 C/C++ Java 혼동하는 사람들이 위와 같이 잘못된 설명을 하는지 모르겠습니다만, 틀린 설명입니다.

    덧붙여 말하자면, C에서는 함수의 매개변수는 모조리 call by value 전달됩니다. 포인터를 이용한 전달 방식이 간접적인 방법 또는 흉내내기는 지언정, 그렇다고 call by reference 되는 것은 아닙니다. C++에서는 참조 연산자를 이용해서 call by reference 가능하지만요.

    교수님이 말씀하셨다고요..... 교수님들이 이런 세세한 부분에서는 종종 틀리는 경우를 많이 봅니다. 전공분야가 다르거나 폭넓게 공부하다 보니 그러시는 것이겠지요. 하지만 그렇다고 교수님 틀리셨네요 하고 가서 따지는 일은 하지 마시길 바랍니다. 교수님들은 건방진 학부생이 자기 틀린부분을 파고드는 것을 매우 기분나빠합니다. 이른바 찍히는 거지요. 편하게 학부생활 하시길 바랍니다. 시험 답안지에는 교수님이 설명하신 대로 쓰십시오.

    »

  •    

    뭔가 개념이 혼동되는 같은데요?

    글쓴이: xorule 작성 일시: , 2008/12/18 - 2:48오후

    Call-By-Reference / Call-By-Value 그렇게 어려운 개념이었나요?

    Call-By-Reference 주소를 함수의 인자로 사용한다

    Call-By-Value 값을 함수의 인자로 사용한다.

    위에 쓰신분은 나름의 철학을 가지고 있겠지만 내가 보았을때는 자신만의 독창적 세계관을 구축했다고 있겠군요..

    Call-By-Reference Call-By-Value function 목적상 구별해야 하는 개념일

    구현이 어떻게 되는가를 구별해야 하는 개념은 아닙니다.

    Program 어떤 목적을 위해 짜여지는 코드지 최적화 연구를 하기 위한 tool 아니기 때문에..

    language for program 개념이 아닌 program for language 목숨거는 위에분 말은 신경쓸 필요가 없어보입니다.

    이상

    »

  • 댓글 보기 옵션

    원하시는 댓글 전시 방법을 선택한 다음 "설정 저장" 누르셔서 적용하십시오.

반응형

출처: 오래전에 받은것이라.. 모르겠음... 블로그 주인께서 알려주시면 바로 삽입하겠습니다.

보통 노트북을 쓰시는 분들은 유선랜카드와 무선랜카드를 가지고 계실겁니다.

   

그런 노트북으로 유선으로 연결해서 쓰시는데 무선 신호는 닫지 않아서 wifi 못사용하시는분들

   

유무선 공유기 있으신 분들은 그냥 wifi 쓰시면 대구요^^; 저처럼 아이폰을 질러서 유무선 공유기를

   

살돈이 없다!! 하시는 분들 괜찮은 같으니 한번 해보세요^^

   

우선 무선랜카드가 활성화 되어 있어야 합니다. 물론 유선으로 인터넷이 연결이 되어 있어야 하구요

   

기본 바탕을 위와 같이 하고 시작해 보도록 하겠습니다.

   

시작->실행->"services.msc" 입력후 Enter 하시게 되면 아래와 같은 창이 뜨게 됩니다.

   

   

서비스들 중에 밑으로 내려보시면 "Window firewall/Internet Connection Shearing (ICS)"라는 서비스가

   

있을겁니다. 그게 중지되어 있으면 안되구요. 반드시 "시작됨" 상태여야 합니다.

   

다음으로 넘어가서 "네트워크 연결" 클릭하셔서 우선 유선랜카드 "로컬 영역 연결"에서

   

오른쪽 클릭을 하시고 "속성" 누릅니다.

   

   

속성창 위의 탭중에 고급 탭으로 갑니다.

   

   

인터넷 연결 공유 부분의 "다른 네트워크 사용자가 컴퓨터의 인터넷 연결을 통해

   

연결할 있도록 허용" 부분을 Check!! 해주시고 확인을 누르세요^^

   

다음은 "무선 네트워크 연결" 속성으로 들어갑니다.

   

   

"무선 네트워크" 탭으로 가셔서 기본 설정 네트워크 부분의 "추가" 눌러줍니다.

   

네트워크 이름 부분에 원하시는 이름 아무거나 써주시구요.

   

네트워크 인증은 "개방모드" 하시고  데이터 암호화는 "사용 안함"으로 하셔야 연결할때

   

암호 없이 연결 됩니다. 그리고 밑에 있는 "컴퓨터 (특별) 네트워크이며 무선 엑세스 지점을

   

사용 안함" Check!! 주셔야됩니다.

   

   

그렇게 하고나면 작성한 무선 네트워크가 뜨게 되는데요 아마 "(요청시)"라고 있을겁니다.

   

제가 요청하는 방법은 정확히 몰라서 이렇게 하고 있는데 참고하세요^^

   

   

위에서 만든 네트워크를 클릭하고 속성을 눌러 연결 탭으로 가시면 Check 박스가 한개 있을껍니다.

   

그걸 Check하시면 웃기지만 유선인터넷으로 무선 네트워크를 공유하여 신호를 보낸걸 다시 노트북이

   

신호를 잡아 자동으로 무선 인터넷을 연결하는 겁니다. 그렇게 되면 컴퓨터에서 항상 연결하려고 요청하기

   

때문에 와이파이 신호가 나오더군요.

   

이렇게 하시면 유무선 공유기 없이도 아이폰에서 와이파이를 잡아서 인터넷을 있답니다^^;

   

P.S-무선 랜카드에 따라서 신호가 매우 약할 수도 있는것 같습니다. 저같은 경우는 너무 약해서

   

       사용을 못하거든요 ^^; 열심히 올려놓구 사용을 못하니 이거원 ㅎㅎ 신호는 아주 미세히

   

       잡힌답니다^^

   

반응형

OS별로 자주 쓰이는 CPU, Memory등의 정보확인 방법에 대한 비교이다.

일부 command는 Root 권한으로 수행되어야 한다.

   

1. CPU 정보

AIX            lsdev -Cc processor HP-UX       ioscan -fnC processor

SOLARIS    psrinfo -v

Tru64         psrinfo -v

LINUX        cat /proc/cpuinfo


2. Physical RAM

AIX            bootinfo -r

HP-UX       grep -i Physical /var/adm/syslog/syslog.log

SOLARIS    Prtconf

Tru64         uerf | grep memory

LINUX        free 


3. Kernel Bits

AIX            bootinfo -K

HP-UX       getconf KERNEL_BITS

SOLARIS    isainfo -kv

Tru64        64

LINUX       getconf WORD_BIT  


4. Service Switch

AIX           /etc/netsvc.conf

HP-UX      /etc/nsswitch.conf

SOLARIS   /etc/nsswitch.conf

Tru64       /etc/svc.conf

LINUX      /etc/nsswitch.conf  


5. NIC

AIX            ifconfig -a

HP-UX       lanscan -v

SOLARIS    ifconfig -a

Tru64         ifconfig -a

LINUX        ifconfig -a 


6. Administrator

AIX            smit

HP-UX       sam

SOLARIS    admintool

Tru64      

LINUX        linuxconf 
   

 

출처

http://javagosu.tistory.com/12

반응형

'Linux' 카테고리의 다른 글

Unix Domain Socket UDP  (0) 2011.08.19
[명령어]Message Queue 설정 및 확인  (0) 2011.08.11
RAID  (0) 2011.08.11
SNMP란 무엇인가요?  (0) 2011.08.11
grep  (0) 2011.08.11

출처: 괭이군 블로그인데.. 사라짐.. 

CPNT는 Contents - Platform - Network - Terminal (또는 Device) 로 진행되는 Value Chain을 뜻합니다.

이러한 Value Chain은 과거 통신사의 주된 Vaㄴlue Chain이었지만 현재의 지식중심의 시대에서는 거의 모든 산업군에서 중요하게 작용하고 있다고 해도 과언이 아니라 생각합니다.

   

과거 CPNT상의 Value Delivery sequence에서 가장 중요한 Issue는 무엇보다도 Platform과 Network 였습니다. 즉 Microsoft의 Windows, Apple의 OSX 같은 모든 Soft의 기준이 되는 플렛폼 제공자와 이를 연결해주는 위한 ADSL, PSTN, FTTH 등 물리적인 네트워크 인프라 제공 사업자의 입김이 강했던 시기였죠.

이러한 배경 속에서 이 둘의 Value Creation은 양 끝에 존재하던 컨텐츠를 소유하고 있는 사업자와 장치를 생산하는 사업자의 Value Creation과는 비교도 안될 정도로 큰 성장을 거두었었습니다.

왜냐면 이 둘을 통하지 않고는 어떠한 가치도 전달되지 못하는 상황이었기에 울며겨자먹기로 종속되어있었기 때문입니다.

   

하지만 지금의 우리는 이러한 과거 상황이 뒤집힐만한 환경 속에서 살아가고 있습니다.

이러한 변화의 가장 큰 이유는 무엇보다도 'Web'이라는 암묵적 통합환경이 제공되었기 때문입니다.

   

Web이라는 통합환경은 Contents 제작자와 소비자에게 PlatformNetwork의 특성을 벗어날 수 있는 기회를 제공하였습니다. 일례로 들자면 Mac환경 속에서 HWP문서를 별다른 소프트를 설치하지 않고도 열람할 수 있는 Plug-in을 웹브라우져가 제공한다던가 동일한 웹화면을 Static Network ( 쉽게 생각하면 현재 사용중인 유선 LAN 등 ) 에서나 Dynamic Network (Mobile WIMAX, WIFI) 에서도 별다른 Format 변환없이 접근할 수 있는 환경이 소비자들에게 널리 인식되는 점 등입니다.

   

이러한 변화상을 통해 새로운 신규시장진입자들에게 새로운 기회가 되고 있습니다. (Internet Explorer 천하였던 Web Browser 시장에서 Firefox, ( Mosaic Group ) Chromn (Google), Safari (Apple) 등 신규 진입자의 활발한 시장 개척, 국내 Network 3사 의 통합 (KT+KTF, SK+HANARO, LG+DACOM+THRUNET (Powercom) ) 및 제 4 무선통신사업자 (CJ)진입 등) 특히 Network에서 Packet 별 과금하던 과거의 Data 통신 등 이통사가 가지고 있던 수익모델은 정부의 IT 정책 (100mb -> 1000mb로 전송속도 강화, 과금체계 개선, WIBRO (Mobile WiMAX) Infra 구축권고 등) 을 통해 끊임없는 투자의 위협과 현재 가지고 있는 비즈니스모델의 교체를 강요 받고 있는 환경입니다.

   

이러한 Platform 시장의 대규모 변화 (O/S 에서 Web Browser로 이동) 과 Network 시장의 수익성약화 가능성 속에서 이제는 ContentsTerminal에 대한 수익모델로 그 중요성이 옮겨가고 있다고 생각합니다.

   

과거 Contents와 Terminal은 Platform과 Network의 부수적인 가치로 인지가 되었으나 Web 2.0 시대가 되면서 그 무엇보다도 중요한 가치로 그 중요성이 증대되고 있습니다. 특히 이러한 시장변화에서 가장 먼저 두각을 나타낸 기업이 있다면 다들 아시는 Apple의 Itune과 IPOD일 것입니다. Itune에서 음악이라는 Contents를 받아 IPOD라는 Terminal (Device)로 전달하는 가치이동흐름속에서 Platform과 Network의 수익성은 그리 크지 않습니다.

미국을 예로 들면 Network Provider AT&T를 통해 IPONE으로 자료를 전송받지만 AT&T 는 Contents에 대한 권리가 없기때문에 오로지 수익을 DATA전송에 대한 과금을 통해서만 획득할 수 있고 AT&T는 이러한 DATA 전송을 위해 H/W의 확충이라는 부담을 가지게 됩니다.

즉 과거 주도적인 시장성의 약화를 의미하기도 합니다.

   

특히 Device에 대한 새로운 Needs 또한 또다른 Business Model의 성장을 의미합니다.

근래 인기있는 Netbook은 과거 Performance 중심의 Laptop시장이 Mobility로 옮겨가고 있는 변화를 보여주는 중요한 예시가 될 것입니다. 특히 과거 전화기능과 SMS중심의 Mobile Phone 시장은 Mobile Communication으로 그 의미가 확대되고 있습니다. 는 One Small Device로 고객의 Needs를 충족시키는 Smart Phone (Blackberry, IPHONE, OMNIA 등) 시장의 성장을 통해 알 수 있습니다.

   

이러한 Value Chain의 재편성 속에서 중요하게 생각해야 하는 점은 Contents 와 Device를 중심으로 시장은 성장하고 있으며 특히 과거 Platform과 Network는 Device쪽에 종속되는 경향이 있다는 점입니다. 이를 통해 새로운 Business Model의 개척은 Contents와 Device를 어떻게 강결합하여 제공할 수 있을 것인가에 촛점을 맞춰야 할 것입니다.

   

Contents Vendor (EMI, SONY Amazon 등 ),  개인 개발자의 참여를 독려한 App Store 라는 무형의 상품을 Platform인 Itune을 통해 거래하도록 하여 Device 인 IPOD로 전달하는 유기적인 Business 모델이 이를 잘 보여주는 예라고 볼 수 있을 것입니다.

   

출처..

링크가 사라짐...

반응형

   

컴퓨터 특수기호 이름

출처  loch44


!  Exclamation Point (익스클레메이션 포인트)

"  Quotation Mark (쿼테이션 마크)

#  Crosshatch (크로스해치)

$  Dollar Sign (달러 사인)

%  Percent Sign (퍼센트 사인)

@  At Sign (앳 사인, 혹은 앳)

&  Ampersand (앰퍼센드)

'  Aposterophe (어퍼스트로피)

*  Asterisk (아스테리스크)

-  Hyphen (하이픈)

.  Period (피리어드)

/  Slash (슬래시)

\  Back Slash (백 슬래시)

:  Colon (콜론)

;  Semicolon (세미콜론)

^  Circumflex (서큠플렉스)

`  Grave (그레이브)

{  Left Brace (레프트 브레이스)

}  Right Brace (라이트 브레이스)

[  Left Braket (레프트 브라켓)

]  Right Braket (라이트 브라켓)

|  Vertical Bar (버티컬 바)

~  Tilde (틸드)

   

반응형

RAID

RAID(Redundant Array of Independent Disks 혹은 Redundant Array of Inexpensive Disks)는 여러 개의 하드 디스크에 일부 중복된 데이터를 나눠서 저장하는 기술이다. 복수 배열 독립 디스크로도 불린다. 데이터를 나누는 다양한 방법이 존재하며, 이 방법들을 레벨이라 하는데, 레벨에 따라 저장장치의 신뢰성을 높이거나 전체적인 성능을 향상시키는 등의 다양한 목적을 만족시킬 수 있다.

최초에 제안되었을 때는 다섯가지의 레벨이 존재했는데, 이후에 중첩 레벨을 비롯한 여러 가지 다른 레벨들이 추가되었다.

RAID는 여러 개의 디스크를 하나로 묶어 하나의 논리적 디스크로 작동하게 하는데, 하드웨어적인 방법과 소프트웨어적인 방법이 있다. 하드웨어적인 방법은 운영 체제에 이 디스크가 하나의 디스크처럼 보이게 한다. 소프트웨어적인 방법은 주로 운영체제 안에서 구현되며, 사용자에게 디스크를 하나의 디스크처럼 보이게 한다.

   

표준 레이드 레벨

흔히 쓰이는 레이드 레벨을 빠르게 간추리면 다음과 같다:

   

RAID 레벨 0

RAID 0

패리티(오류 검출 기능)가 없는 스트리핑된 세트 (적어도 2 개의 디스크). 개선된 성능에 추가적인 기억 장치를 제공하는 게 장점이지만 실패할 경우 자료의 안전을 보장할 수 없다. 디스크에서 실패가 일어나면 배열을 파괴하게 되는데, 이러한 파괴는 디스크를 많이 장착할수록 가능성이 더 크다. 하나의 단일 디스크 실패는 배열을 완전히 파괴한다. 왜냐하면 데이터가 레이드 0으로 쓰일 때, 데이터는 여러 조각으로 나뉘기 때문이다. 조각의 수는 드라이브 안의 디스크 수와 일치한다. 조각들은 각 디스크에 동시적으로 같은 섹터 위에 기록된다. 완전한 데이터 덩어리의 작은 토막들이 병렬로 드라이브를 읽어 낼 수 있게 해 주며, 이러한 종류의 배열은 넓은 대역너비를 제공한다. 그러나 디스크들의 한 섹터가 실패할 때는 모든 다른 디스크 위의 일치하는 섹터가 사용 불능으로 표시된다. 왜냐하면 데이터의 일부가 손상된 것이 아니기 때문이다. 레이드 0은 오류 검출 기능을 제공하지 않기 때문에 어떠한 오류도 복구하지 못한다. 배열에 디스크를 더 많이 넣으면 더 높은 대역을 사용할 수 있겠지만 데이터 손실의 큰 위험이 도사리게 된다.

RAID 1

패리티(오류 검출 기능)가 없는 미러링된 세트 (적어도 2 개의 디스크). 디스크 오류와 단일 디스크 실패에 대비하여 실패 방지 기능이 제공된다. 분할 탐색을 지원하는 다중 스레드를 지원하는 운영 체제를 사용할 때 읽기 성능이 향상된다. 다만, 쓰기를 시도할 때에는 약간의 성능 저하가 뒤따른다. 배열은 적어도 하나의 드라이브가 기능하는 한 계속 동작한다.

RAID 3RAID 4

패리티가 단순 제공되는(dedicated) 스트리핑된 세트 (적어도 3 개의 디스크).

RAID 5

패리티가 배분되는(distributed) 스트리핑된 세트 (적어도 3 개의 디스크).

RAID 6

패리티가 배분되는(distributed) 스트리핑된 세트 (적어도 4 개의 디스크).

RAID 0+1

레이드 0+1은 먼저 디스크를 스트리핑(RAID 0)하고, 디스크를 미러링(RAID 1) 한다. (적어도 4개의 디스크)

디스크가 6개일경우는 3개씩 스트리핑하고 미러링을 그다음에 수행한다.

RAID 10(RAID 1+0)

레이드 10은 먼저 디스크를 미러링(RAID 1)하고, 그 이후 스트리핑 한다. (적어도 4개의 디스크)

디스크가 6개일 경우는 2개씩 미러링을 하고, 미러링된 3개를 스트리핑 한다.

RAID 50(RAID 5+0)

패리티가 배분되는(distributed) 스트리핑된 세트를 다시 스트리핑(RAID 0) 한다. (적어도 6개의 디스크)

RAID 1E

미러링과 데이터 스트라이핑의 결합이다.(적어도 3 개의 디스크).

비표준 레이드 레벨

RAID 1.5

읽기 시에는 RAID 0 처럼 작동하여 성능상의 이점을 얻는다. 쓰기 시에는 RAID 1처럼 작동하여 안정성을 도모한다. RAID 1에 비해 읽기 성능에서 약간의 이점이 있을 뿐이라 널리 쓰이지는 않는다. HighPoint사의 컨트롤러에서만 지원하는 방식이다.

같이 보기

이 글은 컴퓨터에 관한 토막글입니다. 서로의 지식을 모아 알차게 문서를 완성해 갑시다.

   

   

<http://ko.wikipedia.org/wiki/RAID>에서 삽입

반응형

간이 망 관리 프로토콜(簡易網管理)

simple network management protocol

   

①TCP/IP의 망 관리 프로토콜(RFC 1157). 라우터(router)나 허브(hub) 등 망 기기(network agent)의 망 관리 정보를 망 관리 시스템에 보내는 데 사용되는 표준 통신 규약으로 채용되었다.

TCP/IP의 게이트웨이 관리 프로토콜(SGMP:simple gateway management protocol)을 바탕으로 개발되었으며, 개방형 시스템 간 상호 접속(OSI)의 망 공통 관리 정보 프로토콜 (CMIP)에 대응한다.

요구와 응답의 2가지 기능을 사용하여 망 관리 정보를 수집, 관리한다. 1988년에 RFC 1157로 간이 망 관리 프로토콜(SNMP) 표준이 발표되었으며, 1991년에 개정판인 SNMP2가 개발되어 SNMP2에 대응하는 제품도 판매되고 있다.

   

②SNMP와 밀접한 관계가 있는 망 관리 정보 베이스(MIB)의 총칭.

   

http://kin.naver.com/browse/db_detail.php?d1id=1&dir_id=10301&docid=111050

   

1절. 소개

2절. SNMP개요

2.1절. SNMP란 무엇인가

2.2절. SNMP로 할수 있는 것들

2.3절. SNMP를 통한 망의 구성

2.4절. MIB에 대해서

2.5절. SNMP 프로토콜의 동작과 구성

3절. SNMP 설치 및 운용

3.1절. ucd-snmp 설치

3.2절. SNMP AGENT 실행

3.3절. SNMP MANAGER 테스트

3.3.1절. 동기적인 데이타 요청 - snmp get, get next

3.3.2절. 비동기적인 데이타 요청 - snmp trap

4절. 결론

   

1절. 소개

개인적으로 최근들어 SNMP에 관심을 가지게 되었다. (실은 상당히 오래되었지만) 그래서 앞으로 몇부? 에 걸쳐서 SNMP관련 강좌를 개설하고자 한다. 강좌는 SNMP개요및 설치운용에서 부터 시작해서 프로그래밍을 통해서 SNMP응용 애플리케이션을 제작하고, 확장 MIB(뒤에 설명한다)를 작성하는 것 까지를 다룰것이다.

이번글은 그중 첫번째 글로 SNMP개요와 설치및 운용에 대한 글이다. 설치및 운용은 실제 어떻게 작동되는지 눈으로 확인하는 차원의 수준에서 이루어질 것이며, 설치되는 snmp애플리케이션의 상세설치와 높은 수준에서의 운용에 대해서는 언급하지 않을것이다. 이러한 것들은 (필요할경우)해당 snmp애플리케이션의 메뉴얼을 참고해서 개인적으로 학습해야만 할것이다.

여기에서 얻은 지식은 나중에 SNMP애플리케이션을 제작하는 밑거름이 될것이다.

   

2절. SNMP개요

2.1절. SNMP란 무엇인가

SNMP는 Simple Network Management Protocol의 약자이다. 해석을 해보자면 간단한 네트워크관리를 위한 규약 인데, 말그대로 SNMP는 네트워크관리를 위한 용도로 사용되는 프로토콜이다. 가장 앞에 Simple라는 단어가 붙어있는데, 진짜로 간단한 프로토콜인지 아닌지는 사람에 따라 약간씩 차이가 있을수 있다. 필자가 보기엔 그리 복잡한 프로토콜은 아닌것 같은데, 어떤 사람들은 매우 복잡한 프로토콜 이라고 말하는 사람들도 있다.

그럼 먼저 SNMP가 나타난 배경에 대해서 알아보도록 하겠다. SNMP가 쓰이기 전에 일반적으로 사용되는 네트워크 관리는 ICMP에 의존했었다. ICMP는 Network계층의 프로토콜로써, 운영체제에 관계없이 사용할수 있는 간단한 프로토콜이였다. 이 프로토콜을 이용해서 우리는 네트워크로 연결된 각각의 호스트가 작동하고 있는지, 작동한다면 어느정도의 응답시간을 가지고 작동하는지 등의 간단한 정보를 얻을수 있었으며, 초기에는 이정도로도 필요한 네트워크 관리가 가능했었다. ICMP를 이용한 가장 유용한 도구는 아마도 ping 프로그램일 것이다.

그러나 인터넷의 사용이 보편화되고 네트워크에 연결된 호스트의 수가 증가하자 거기에 따라서 네트워크 구성역시 복잡해지고, ICMP만을 가지고는 이러한 네트워크의 관리를 효율적으로 할수 없게 되었다.

그래서 몇가지 프로토콜에 대한 연구가 진행되었고, SGMP, HIMS, CMIP/CMIS등이 제안되게 되었다. 이중에서 SGMP를 발전시킨 SNMP가 사실상 네트워크 관리를 위한 표준적인 프로토콜로 자리잡게 되었다. 다른 프로토콜들이 사용되지 않은데에는 몇가지 이유가 있었다. CMIP/CMIS는 너무 방대하고 너무 복잡했으며, HEMS의 경우에는 실제 적용사례가 적었기 때문이다.

어쨋든 SNMP는 거의 대부분의 운영체제에서 사용되어 지고 있다. 여러분이 사용하는 Linux, 그밖의 대부분의 유닉스와, 윈도우계열 운영체제는 기본적으로 SNMP프로토콜을 사용하는 도구들을 제공하고 있다. 그외에도 router등 TCP/IP를 네트워크 프로토콜로 사용되는 운영체제들 역시 SNMP는 필수적으로 제공하고 있다.

   

2.2절. SNMP로 할수 있는 것들

SNMP를 이용해서 할수 있는 것들은 다음과 같다.

네트워크 구성관리

네트워크상의 호스트들이 어떤 구조를 이루고 있는지 지도를 그리는게 가능하다.

성능관리

각 네트워크 세그먼트간 네트워크 사용량, 에러량, 처리속도, 응답시간 등 성능 분석에 필요한 통계정보를 얻어낼수 있다.

장비관리

SNMP의 주목적이 네트워크관리관리 이기는 하지만 SNMP특유의 유연한 확장성을 이용하여서 시스템정보(CPU, MEMORY, DISK 사용량)의 정보를 얻어올 수 있도록 많은 부분이 확장되었다. 이 정보는 네트워크문제를 해결하는데 큰도움을 준다. 예를들어 특정 세그먼트의 네트워크 사용량이 갑자기 급증했는데, 특정 호스트의 CPU사용율까지 갑자기 증가했다면, 우리는 해당 호스트에서 문제가 발생했을것이란걸 유추해낼수 있을것이다.

보안관리

정보의 제어 및 보호 기능, 최근버젼인 SNMP3는 특히 정보보호를 위한 기능이 향상되었다.

   

2.3절. SNMP를 통한 망의 구성

SMTP는 인터넷상에서 메시지를 교환하기 위한 프로토콜로 사용되며, 주로 전자메일 교환을 위해서 사용되는 프로토콜이다. 그러나 SMTP는 어디까지나 프로토콜일 뿐이며, 실제 메시지를 인터넷상에서 주고 받기 위해서는 SMTP프로토콜을 사용하는 SMTP서버(Sendmail같은)와 SMTP클라이언트(mutt, pine같은)가 준비되어 있어야만 한다.

SNMP역시 그자체로는 프로토콜일 뿐이며 SNMP프로토콜을 활용해서 실제 네트워크 관리 정보를 얻어오기 위해서는 응용 애플리케이션이 준비되어있어야만 한다. 보통의 네트워크프로토콜을 사용하는 애플리케이션이 서버/클라이언트 모델로 구성되듯이 SNMP역시 서버와 클라이언트로 구성된다.

그림 1. SNMP망 관리 시스템

일반적으로 SNMP망 에서는 서버/클라이언트라고 부르지 않고 snmp manager/snmp agent라고 부른다. snmp agent는 관리대상이 되는 시스템에 설치되어서 필요한 정보(네트워크 혹은 시스템)를 수집하기 위한 snmp 모듈(혹은 애플리케이션) 이며, snmp manager은 snmp agent가 설치된 시스템에 필요한 정보를 요청하는 snmp 모듈이다. snmp agent는 서버, snmp manager은 클라이언트로 생각하면 이해하기가 좀더 수월할 것이다(그러나 반드시 agent가 서버, manager이 클라이언트가 되는건 아니다. 그냥 개념적으로 이해만 하고 있도록 하자).

   

2.4절. MIB에 대해서

SNMP는 네트워크를 관리하기 위한 프로토콜이다. 그렇다면 무엇을 관리할 것인가(관리객체)를 결정해야 할것이다. 관리객체를 결정했다면, 이러한 관리객체를 효과적으로 관리하기 위해서 이를 분류해야 할것이다. 이게 바로 MIB이다.

MIB는 Man In Black의 줄임말이 아니다. Management Information Base의 줄임말인데, 관리되어야할 자원 객체의 분류된 정보를 말한다. 관리되어야할 객체는 시스템정보, 네트워크사용량, 네트워크 인터페이스정보 등이 된다.

이 MIB객체들은 관리하기 편하도록 Tree구조를 가지게 된다. 다음은 MIB의 일반적인 구조이다.

그림 2. MIB계층 구조

MIB는 위에서 처럼 계층적인(디렉토리) 구조를 가지게 된다(위의 그림은 MIB를 설명하기 위해 일부만을 표시하고 있다). 예를들어서 agent가 설치되어 있는 시스템으로 부터 시스템부가정보(sysDescr)를 얻어오길 원한다면 ISO.org.dod.internet.mgmt.mib-2.system.sysDescr과 같은 식으로 manger에서 데이타를 요청하면 된다.

위의 MIB계층 구조를 보면 각 MIB옆에 숫자가 있는것을 볼수 있다. 이 숫자가 OID번호이다. 즉 sysDescr의 OID값은 1.3.6.1.1.2.1.1.1 이 될것이다. OID번호를 이용하는 이유는 MIB고유 문자열을 통해서 원하는 데이타를 가져오기위해서는 아무래도 요청이 길어질수가 있기 때문이다.

MIB는 IANA(Internet Assigned Number Authority)라는 단체에서 관리하며 표준적으로 사용되고 있다. 그럼으로 표준적인 MIB구현을 위해서는 IANA에서 OID를 부여받아야만 한다. 그래야 전체네트워크상에서 다른 여러가지 MIB와 중복되지 않고 사용이 가능할것이다.

작은 정보: cisco과 같은 대중적인(거의 표준이나 마찬가지인) 제품들은 모두 자체적인 MIB를 구현해서 IANA에 등록하여 사용하고 있다. 여러분이 cisco 라우터등의 SNMP정보를 접근할수 있다면 cisco MIB가 등록되어 있음을 확인할수 있을것이다. 확인하는 방법은 다음 강좌에서 따로 언급하도록 하겠다.

MIB는 계층적 구조를 가짐으로 필요에 따라서 확장해서 사용이 가능하며, (물론 프로그래밍 능력이 있어야 하지만)때에 따라서는 자체 회사내에서만 사용가능하거나 제한된 네트워크 영역의 네트워크상황을 관제하는 제품을 위한 MIB를 추가해야 하는경우가 생길수 있을것이다. 그래서 사설로 MIB를 만들어서 사용할수 있는 여지를 남겨두었다. (마치 독립된 지역네트워크를 위해 사설IP를 사용하는 것처럼) 이러한 사설 MIB는 private(4)의 enterprises(1)에 정의해서 사용할수 있다. 여러분이 그리 대중적이지 않은 그래서 IANA에 등록되지 않은 어떤 장비의 고유 SNMP정보를 얻어오고 싶다면 업체에 문의하거나, 메뉴얼을 확인하는 정도로 쉽게 SNMP정보를 얻어올수 있다.

현재 MIB는 버젼 2까지나와 있으며, 버젼의 구분을 위해서 MIB-1, MIB-2로 부르고 있다. MIB-2는 MIB-1의 확장판으로 MIB-1의 모든 객체를 포함하여 약 171개의 객체들을 더 포함하고 있다. 최근의 제품들은 대부분 MIB-2를 지원하고 있다. 물론 위에서 말했듯이 독자적인 MIB를 만들어서 사용할수 있으며, 이를 확장 MIB라고 부른다.

   

2.5절. SNMP 프로토콜의 동작과 구성

현재 SNMP는 버전 3가지 나와있는 상태이지만 아직까지는 버젼2가 가장 널리 사용 되고 있다. 필자역시 SNMP 버젼 2에 대한 경험이 많은 관계로 버젼2를 기준으로 설명하도록 하겠다.

SNMP는 기본적으로 네트워크 정보를 수집하는데 그 목적이 있는데, 수집하는 몇가지 각각 다른 방법이 있다. 일반적으로 생각해서 우리가 생활중에 얻게 되는 정보는 우리가 요구해서 발생하는 정보와(신문을 구입한다든지, 인터넷으로 서핑을 하는등) 뉴스속보와 같은 형식으로 중요한 일이 있을때 발생하는 정보가 있을것이다. 또한 단지 정보를 얻는데 그치지 않고 정보를 입력하기도 한다.

SNMP정보수집역시 기본적으로 위의 일상생활에서의 정보수집과 같은 방식으로 이루어진다. 이하 snmp manager은 manager로 snmp agent는 agent로 부르도록 한다.

GET

manager에서 agent로 특정 정보를 요청하기 위해서 사용한다.

GET NEXT

기본적으로는 GET과 같은일을 한다. 그러나 SNMP에서 각정보들은 계층적 구조로 관리된다. 위의 MIB계층 구조를 나타낸 이미지에서 우리는 system(1)계층밑에 있는 모든 정보를 가져오고 싶을 때가 있을것이다. 그럴경우 GET NEXT를 사용할수 있다.

SET

manager에서 agent로 특정 값을 설정하기 위해서 사용한다.

TRAP

agent에서 통보해야될 어떤 정보가 발생했을때(임계치를 넘는네트워크자원 사용등) manager에게 해당 상황을 알리기 위해서 사용한다. 위의 다른 요청들이 동기적 요청이라면 이것은 비동기적 사건을 알리기 위해서 사용되어진다.

SNMP프로토콜은 기본적으로 어떤 정보를 요청하는 메시지와 이에 대한 응답메시지로 이루어지며 다음과 같은 구조를 가지고 있다.

표 1. SNMP 메시지

Version

Community name

SNMP PDU

Version은 말이 필요없다. SNMP프로토콜의 버젼번호를 나타낸다. Community name은 메니저와 에이전트간의 관계를 나타내는데, 인증, 접근통제등의 목적으로 사용된다. 보통은 간단하게 public을 사용한다. PDU 는 Physical Data Unit의 줄임말인데, 실제 전송되는 필요한 정보들을 담고 있는 Unit이다. Unit 이라고 하는 이유는 실제 전송되는 정보들의 부가 속성을 나타내기 위한 몇가지 값들을 포함하고 있기 때문이다. PDU는 PDU 타입(GET인지 Set인지 GET Next인지, TRAP인지등)과, Request-id, 실제보내고자 하는 데이타등(OID와 OID에 대한 값들)으로 구성되어 있다.

SNMP를 통해서 전달되는 메시지들은 기본적으로 UDP를 이용하게 된다. 바로위에서 PDU는 Request-id를 포함하고 있다고 했는데, 데이타그램처리방식인 UDP의 단점을 극복하기 위해서 사용되는 값으로, 각 메시지의 요청번호를 표시한다. 그래야만 수신된 SNMP메시지가 어떤 요청에 대해서 수신된 메시지인지 확인이 가능할것이기 때문이다.

   

3절. SNMP 설치 및 운용

그럼 실제로 시스템에 SNMP(agent와 manager 애플리케이션)을 설치해서 정보를 가져오는걸 간단히 테스트 해보도록 하겠다.

설치는 Linux(Kernel-2.4.x)에서 ucd-snmp로 할것이다. 위에서 설명했듯이, SNMP는 manager과 agent로 운영되게 되는데, 테스트의 편의를 위해서 하나의 시스템(localhost)에서 manager와 agent를 운용하도록 하겠다.

   

3.1절. ucd-snmp 설치

ucd-snmp는 net-snmp.sourceforge.net에서 얻을수 있으며 애플리케이션 관련 정보들도 얻을수 있다. ucd-snmp는 현재 버젼 5.x대까지 진행되어 있는데, 5.x부터는 net-snmp로 이름을 바꾸고 개발되어지고 있으며, 4.x버젼까지를 ucd-snmp라고 부르고 있다. 필자는 익숙한 ucd-snmp(버젼 4.x)를 설치하도록 할것이다. 비록 net-snmp가 최신이긴 하지만 별로 다루어본적이 없고, 대부분의 경우 아직까지는 ucd-snmp가 많이 사용되어지고 있기 때문이다. 최신이 아니라고 불만을 가질 필요는 없다. 근본적으로 net-snmp와 ucd-snmp간의 차이는 없으며, 우리의 목적은 최신의 snmp애플리케이션을 테스트하는게 아닌 snmp의 기능과 원리를 이해하고 이를 이용해서 필요한 응용 애플리케이션을 작성하는 것이기 때문이다.

위의 URL에서 ucd-snmp를 다운받아서 압축을 풀고 컴파일 하도록 하자. 컴파일 하는중에는 아마도 아무런 문제가 없을것이다. 컴파일은 매우 일반적인 방법을 따른다. 적당한 디렉토리에 압축을 풀고 ./configure, make, make install 하면된다. 헤에... 너무 간단하지 않은가 ?

   

3.2절. SNMP AGENT 실행

make install 까지 했다면 agent와 manager프로그램이 모두 설치되어 있을 것이다. 그리고 여기에 더불어 개발자를 위한 각종 라이브러리와 헤더파일들도 설치된다. 이 라이브러리와 헤더파일들은 개발할때 필요하며 다음 강좌에서 다루게 될것이다.

ucd-snmp는 agent 프로그램으로 snmpd를 제공한다. agent환경을 제대로 만들려면 복잡해보이는(사실은 그리 복잡하다고 볼수없는) 설정파일을 만들어줘야 하지만 이것은 각자의 몫이다. net-snmp프로젝트 홈페이지에서 제공하는 메뉴얼을 참고하기 바란다. 어쨋든 현재로써는 단지 snmpd를 띄우는 정도로 snmp agent환경을 만들수 있다.

[root@localhost root]# snmpd

이것으로 snmp를 테스트할 최소한의 agent환경이 구축되었다.

   

3.3절. SNMP MANAGER 테스트

3.3.1절. 동기적인 데이타 요청 - snmp get, get next

GETGET NEXT는 동기적인 정보요청을 위해서 사용한다. manager에서 agent에 대해서 정보를 요청했을때 해당 정보를 agent에서 보내주는 방식이다. GET은 단일정보요청을 위해서 사용하며, GET NEXT는 해당 계층의 하위에 있는 모든 정보의 요청을 위해서 사용된다.

ucd-snmp는 이러한 정보요청을 위한 manager프로그램으로 snmpgetsnmpnext, snmpwalk를 제공한다.

snmpget은 이름에서 알수 있듯이 agent로부터 특정한 정보를 얻어내기 위해서 사용한다. 정보를 얻기 위해 필요한 기본정보는 agent가 설치되어 있는 서버의 주소(혹은 이름) 와 커뮤니티(권한을 위한)이름 그리고 얻기 원하는 정보의 OID번호 혹은 MIB의 계층이름이다. 예를들어서 localhost로부터 public권한을 가지고 sysDescr(시스템 부가정보)정보를 얻어오고 싶다면 아래와 같이 하면 된다.

[root@localhost /root]# snmpget localhost public system.sysDescr.0

system.sysDescr.0 = Linux localhost 2.4.2-2

#1 Sun Apr 8 20:41:30 EDT 2001 i686

혹은 MIB이름대신에 OID번호를 사용해도 된다.

[root@localhost /root]# snmpget localhost public 1.1.0

system.sysDescr.0 = Linux localhost 2.4.2-2

#1 Sun Apr 8 20:41:30 EDT 2001 i686

snmpwalk는 해당 MIB의 하위계층에 있는 모든 정보를 요청한다. 예를들어 system MIB의 하위 계층에 있는 모든 OID에 대한 정보를 요청하길 원한다면 아래와 같이 하면된다. 이게 가능한 이유는 snmpwalk가 정보를 요청하기 위해서 snmp메시지를 만들때 PDU타입을 GET NEXT를 사용하기 때문이다. 나중에 직접구현하게 될것이다. 지금은 구현에 신경쓰지 말자. system하위의 모든 OID에 대한 정보를 얻어오고 있음을 확인할수 있다.

snmpgetnext는 snmpwalk의 기능 축소판정도로 볼수 있을것이다. 즉 MIB계층구조에서 현재 요청한 OID의 다음 OID의 정보를 가져온다. 예르들어 system.sysDescr.0에 대한 정보를 요청하면 다음 OID인 system.sysObjectID.0의 정보를 요청하게 될것이다. 이게 가능한 이유는 snmpwalk와 마찬가지로 내부적으로 GET NEXT를 이용하고 있기 때문이다. snmpwalk가 더이상 얻을수 없을때까지 OID를 요청하는것과 달리 snmpgetnext 바로다음의 OID만을 요청한다.

   

3.3.2절. 비동기적인 데이타 요청 - snmp trap

기본적으로 GET, GET NEXT를 통한 데이타요청은 일정한 polling시간을 가지고 manager에서 agent로 필요한 정보를 요청하는 방식이다. 그러나 이걸 이용해서는 비동기적으로 발생하는 정보를 수집할수가 없다.

이러한 비동기적인 정보는 여러가지가 될수 있다. 예를들면 특정 네트워크 세그먼트에 문제가 생겼다거나 디스크나 메모리용량을 과다하게 사용하고 있다거나(많은 운영체제의 경우 시스템정보까지도 snmp를 통해서 얻을수 있도록 허용하고 있다)하는 사건들은 비동기적으로 발생할것이다. 이럴경우에는 agent에서 manager측으로 사건을 통보해야 할것이다. 이렇게 agent에서 manager측으로 비동기적으로 사건을 통보하는 것을 SNMP TRAP라고 한다(간단히 말해서 경고메시지 보내는거다).

ucd-snmp에서는 이러한 trap정보를 전송하고 받기 위해서 snmptrapdsnmptrap를 제공한다. snmptrapd는 agent에 제공되는 데몬프로그램으로 manager에서의 trap데이타 발생을 기다린다. snmptrap는 agent에 설치되어서 사용될수 있으며 trap데이타를 manager로 전송하는 일을한다.

이 snmptrap은 꽤 유용하게 사용할수 있다. 간단하게 스크립트로 만들어서 어떤 파일이 변조되었을경우 trap정보를 manager쪽으로 발생시킨다거나, 프로세스 갯수가 일정갯수 이상 초과했을때 이를 전송한다든지 하는 기능을 비교적 간단하게 추가시킬수 있을것이다.

다음은 ucd-snmp에서 제공하는 trap애플리케이션을 이용한 간단한 테스트이다. 먼저 snmptrapd를 manager측에서 실행시켜야 한다. 이 애플리케이션은 옵션없이 실행할경우 데몬모드로 실행되며 표준출력을 시키지 않음으로 다음과 같이 옵션을 주고 실행시켜서 일반모드(forground)에서 받은 trap정보를 표준출력하도록 실행시키도록 하자.

[root@localhost root]# snmptrapd -f -P 2003-04-23 00:13:34

UCD-snmp version 4.2.6 Started.

이제 agent측에서 snmptrap를 이용해서 trap정보를 manager로 전송해보도록 하자.

[root@localhost root]# snmptrap -v 2c -c public localhost ""

ucdStart sysContact.0 s "yundream"

그러면 manager로 system.sysContact.0="yundream" 과 같은 정보가 전달되는걸 확인할수 있을것이다.

이들 ucd-snmp에서 제공하는 애플리케이션들의 자세한 사용법은 메뉴얼 페이지를 참고하기 바란다.

   

4절. 결론

이상 SNMP의 개념과 개념의 이해를 위해서 실제 사용되는 snmp애플리케이션을 설치해서 간단히 운영테스트까지 해보았다. 이러한 운영테스트를 위해서 ucd-snmp를 사용했는데, 다음 강좌는 ucd-snmp에서 제공하는 snmplib를 통해서 snmp애플리케이션을 만드는 법을 다루도록 하겠다.

http://blog.naver.com/gagvirus.do?Redirect=Log&logNo=80005633576

   

   

반응형

+ Recent posts