[OS] 7. 프로세스 간 통신(IPC)


프로세스 간 통신 (IPC)

  • 프로세스는 시스템 내에서 독립적으로 실행되기도 하고 데이터를 주고받으며 협업하기도 한다.
  • 프로세스 간 통신(IPC)은 데이터를 주거나 받는 동작으로 이루어지며, 이는 쓰기 연산과 읽기 연산으로 간소화할 수 있다.
  • 모든 통신에 관련된 연산은 open()read()write()close() 구조이다.
    • 전역 변수, 파일을 사용한 통신은 운영체제의 도움없이 진행되는 통신 방식
    • 파이프, 소켓, 원격 프로시저 호출 등은 운영체제가 제공하는 통신 방식
  • 프로세스 간 통신의 개념

    Untitled

    • 프로세스 내부 데이터 통신
      • 하나의 프로세스 내에 2개 이상의 스레드가 존재하는 경우의 통신
      • 전역 변수나 파일을 이용
    • 프로세스 간 데이터 통신
      • 같은 컴퓨터에 있는 여러 프로세스끼리 통신
      • 공용 파일, 파이프를 사용
    • 네트워크를 이용한 데이터 통신
      • 여러 컴퓨터가 네트워크로 연결되어있을 경우 통신
      • 소켓, 원격 프로시저 호출을 사용
      • 소켓을 사용하는 프로세스간 통신을 네트워킹 이라고 한다.

프로세스 간 통신의 분류

분류 방식 종류 예시
통신 방향 양방향 통신 일반적 통신, 소켓
  반양방향 통신 무전기
  단방향 통신 전역 변수, 파일, 파이프
     
통신 구현 방식 대기가 있는 통신(동기화) 파이프, 소켓
  대기가 없는 통신(비동기화) 전역 변수, 파일
  • 반양방향 통신은 데이터를 양쪽 방향으로 전송할 수 있지만, 동시 전송은 불가능하고 특정 시점에 한쪽 방향으로만 전송할 수 있는 구조

전역 변수를 이용한 통신

  • 공동으로 관리하는 메모리를 사용하여 데이터를 주고 받는다.

    Untitled

  • 데이터를 보내는 쪽에서는 전역변수나 파일에 값을 쓰고, 데이터를 받는 쪽에서는 전역변수의 값을 읽는다.
  • 직접적인 관련이 있는 프로세스 간에 사용한다.
    • e.g. 부모 프로세스가 전역 변수를 선언한 후 자식 프로세스를 만들면 부모 프로세스와 자식 프로세스가 통신을 할 수 있다.
  • 전역변수를 사용하는 통신 방식의 문제점은, 언제 데이터를 보낼지 받는 쪽에서는 모른다는 것이다.
    • 따라서 데이터를 받는 쪽에서 반복적으로 전역변수의 값을 점검해야한다.
    • 상태 변화를 살피기 위해 반복문을 실행하며 기다리는 것을 바쁜 대기(busy waiting)라고 한다.
    • 시스템 차원에서 큰 자원 낭비이므로 안 좋은 프로그래밍의 전형적인 예다.
  • 바쁜 대기 문제를 해결하기 위해서 동기화(synchronization)를 사용한다.
  • 동기화를 사용하면 바쁜 대기를 하지 않아도 데이터가 도착했음을 운영체제가 알려준다.
    • e.g. 메신저에서 메세지가 도착했다고 알려주는 알림

동기화 통신 vs. 비동기화 통신

  • 동기화 통신
    • 동기화를 지원하는 방식
    • 데이터를 받는 쪽은 데이터가 도착할 때까지 자동으로 대기 상태에 머물러있다.
    • open()close() 함수를 사용한다.
      • open(): 키 또는 권한(descriptor)를 받아 작업을 시작
      • close(): 자원을 다 사용하면 키를 반납
  • 비동기화 통신
    • 동기화를 지원하지 않는 방식
    • 데이터를 받는 쪽은 바쁜 대기를 사용하여 데이터의 도착 여부를 확인한다.

파일을 이용한 통신

  • 파일(전역변수) 입출력 코드는 크게 open, write, readclose 로 이루어져 있다.

    Untitled

  • 부모-자식 관계 프로세스 간 통신에 많이 사용된다.
  • 동기화를 제공하지 않는다.
  • 파일 내의 데이터는 한 줄로 길게 저장된다. 즉 순차 파일(Sequential File) 이다.
  • 순차 파일에 접근 하는 방식을 순차적 접근(Sequential Access)이라고 한다.
  • 운영체제가 동기화를 지원하지 않기 때문에, 부모-자식 프로세스 관계라면, 부모 프로세스가 wait()을 사용하여 자식 프로세스가 작업을 끝낼 때까지 기다렸다가 작업을 시작한다.
  • read()와 write()가 파일 기술자를 공유한다. 따라서 read()를 하건 write()를 하건 상관없이 기술자가 전진하여 동기화를 할 수 없다.
  • 파일 열기
    • open()을 이용하여 사용하고자 하는 파일이 있는지, 파일이 있다면 쓰기 권한이 있는지 확인
      • open(”test.txt”, O_RDWR)
      • O_RDWR: 읽기/쓰기 작업
      • O_RDONLY: 읽기 전용
    • 정상적으로 파일을 사용할 수 있다면, open()은 fd를 반환
      • fd(File Descriptor)는 어떤 파일에 접근할 수 있는 권한으로, 파일 기술자라고 한다.
      • 어떤 파일에 쓰기/읽기 연산을 하려면 먼저 fd 를 얻어야하며 작업이 끝나면 fd 를 돌려줘야한다.
  • 읽기/쓰기 연산
    • write(fd, ‘Test’, 5) : 파일에 test 를 쓰라는 뜻이다. Test 의 크기가 5B이기 때문에 5 를 명시
    • read(fd, buf, 5) : 파일에서 5B를 읽어 변수 buf에 저장
  • 파일 닫기
    • close(fd): fd 가 가리키는 파일을 닫는다.

파이프를 이용한 통신

  • 파이프는 운영체제가 제공하는 동기화 통신 방식으로 단방향이다. 파이프는 이름 있는 파이프와 이름 없는 파이프로 나뉜다.

    Untitled

  • 파이프는 queue 와 같다. 따라서 한쪽에서는 write(push)하는 것이고, 한 쪽은 read(pop) 밖에 할 수가 없다.
  • 즉 파이프에 쓰기 연산을 하면 데이터가 전송되고, 읽기 연산을 하면 데이터를 받는다.
  • 파이프로 양방향 통신을 하려면 파이프 2개를 사용해야 한다.
  • read()와 write() 의 기술자가 따로 존재한다. 따라서 동기화가 가능하다.
    • 파일 기술자를 fd[2]와 같이 2개의 원소를 가진 배열로 정의하는데, 원소 하나는 읽기용이고 하나는 쓰기용이다.
  • 대기 상태
    1. 프로세스 B가 파이프 1에 대해 읽기 연산을 수행했는데 프로세스 A 가 파이프 1에 아직 쓰기 연산을 하지 않았다면 프로세스 B는 대기 상태가 된다.
    2. 대기 상태는 프로세스 A가 파이프 1에 데이터를 쓰는 순간 자동으로 풀려 동기화가 이루어진다.
    3. 프로세스 B는 바쁜 대기를 하지 않아도 된다.
  • 이름 없는 파이프
    • 일반적인 파이프
    • 부모-자식 관계와 같이 서로 관련 있는 프로세스 간 통신에 사용
  • 이름 있는 파이프
    • FIFO 라 불리는 특수한 파일을 이용하며 서로 관련 없는 프로세스 간 통신에 사용

소켓을 이용한 통신

  • 여러 컴퓨터에 있는 프로세스 간 통신은 네트워킹이라고 한다.
  • 네트워킹은 원격 프로시저 호출(RPC)이나 소켓을 이용한다. 소켓은 프로세스 동기화를 지원하고 양방향 통신이 가능하다.

    Untitled

  • 소켓은 하나만 사용해도 양방향 통신이 가능하다. 반면에 파이프의 경우, 양방향 통신을 하기 위해서는 파이프를 2개 사용해야 한다.
  • 소켓을 사용하여 다른 컴퓨터와 통신을 하려면,
    1. IP 주소로 컴퓨터의 위치를 파악한다.
    2. 원격지의 시스템 내 여러 프로세스 중 어떤 프로세스와 통신을 할지 결정한다.
      • 한 컴퓨터 내에는 여러 프로세스가 존재한다.
      • 이 때 사용하는 구분 번호를 포트 번호(Port Number)라고 한다.
    3. 통신하고자 하는 프로세스는 소켓에 쓰기 연산을 하면 데이터가 전송되고 읽기 연산을 하면 데이터를 받는다.
  • 클라이언트
    1. socket()
    2. connect()
    3. read()/write()
    4. close()
  • 서버
    1. socket()
    2. bind()
      • 소켓을 생성한 후, bind()를 사용하여 특정 포트에 새로운 소켓을 등록한다.
      • 동시에 여러 클라이언트에 서비스 하기 위해 하나의 포트번호에 여러 개의 소켓을 생성한다.
      • 소켓을 하나만 생성한다면 단 한사람에게 서비스를 할 수 있을 것이다.
    3. listen()
    4. accept()
      • 클라이언트의 connect(), 즉 연결 요청을 기다리다가 여러 명의 클라이언트가 동시에 connect 를 하는 경우 그 중 하나를 골라서 작업을 한다.
      • accept()가 되면 소켓 기술자(descriptor)가 생성되고 작업이 시작된다.
    5. read()/write()
    6. close()
      • 작업이 끝나면, 소켓 기술자를 닫는다. 이후에 계속 클라이언트를 받아서 작업해야 하기 때문에 무한루프를 돈다.
  • 원격 프로시저 호출(RPC, remote procedure call)
    • 다른 컴퓨터에 있는 함수를 호출하는 것이다.
    • 소켓을 이용하여 구현한다.
    • e.g. 자바같은 객체 지향 언어에서 다른 컴퓨터에 있는 객체의 메소드를 불러와 사용

공유 메모리(Shared Memory)

  • 공유 메모리는 프로세스간 메모리 영역을 공유해서 사용할 수 있도록 허용한다.

    https://velog.velcdn.com/images/phc09188/post/58f69269-3b52-4798-a82b-0d96b2b81344/image.png출처 : https://velog.velcdn.com

  • 프로세스가 공유 메모리 할당을 커널에 요청하면 커널은 해당 프로세스에 메모리 공간을 할당한다.
  • 이후 어떤 프로세스건 해당 메모리 영역에 접근할 수 있다.
  • 프로세스 간 readwrite 를 모두 필요로 할 때 사용한다.
  • 중개자 없이 곧바로 메모리에 접근할 수 있기 때문에 모든 IPC 중에서 가장 빠르게 작동한다.

파이프(Pipe)

  • 통신을 위한 메모리 공간(버퍼)을 생성하여 프로세스가 데이터를 주고 받게끔 한다.

    https://velog.velcdn.com/images/phc09188/post/d0c2fad5-0eec-4b8e-baf3-e1a546966993/image.png출처 : https://velog.velcdn.com

  • 파이프는 익명 파이프와 네임드 파이프 2가지로 나뉘어진다.

    1. 익명 파이프(Anonymous PIPE)
      • 일반적인 파이프
      • 통신할 프로세스가 명확하게 알 수 있는 경우 사용한다.
      • 파이프는 두 개의 프로세스를 연결하고, 하나의 프로세스는 데이터를 쓰기만, 다른 하나는 데이터를 읽기만 할 수 있다.
      • 한 쪽 방향으로만 통신이 가능한 파이프의 특징 때문에 반이중통신이라고 부르기도 한다.
      • 송/수신을 모두 하기 원한다면 두 개의 파이프를 만들어야 가능하다.
      • 간단하게 사용이 가능하고, pipe 함수로 생성한다.
      • 단점
        • 반이중 통신이라 프로세스가 읽기와 쓰기 통신을 모두 해야한다면, PIPE 두 개를 만들어야 하므로, 구현이 복잡해질 수 있다.
        • 전이중 통신을 고려해야 할 상황이라면 낭비가 심하게 때문에 좋은 선택이 아니다.
    2. 네임드 파이프(Named PIPE)
      • 전혀 모르는 상태의 프로세스들 사이의 통신에 사용
      • 익명 파이프의 확장된 상태로 부모 프로세스와 무관한 다른 프로세스도 통신 가능하다.
        • 프로세스 통신을 위해 이름이 있는 파일을 사용하기 때문에 가능하다.
        • FIFO 라 불리는 특수 파일을 이용해 서로 관련 없는 프로세스 간 통신에 사용한다.
        • 외부 프로세스와 통신 가능
      • mkfifo 또는 mknod 함수로 생성 가능.
      • 단점
        • 익명 파이프와 같이 반이중통신이라는 단점이 있다.

소켓(Socket)

  • 유닉스 도메인 소켓 또는 IPC 소켓은 동일한 호스트 운영체제에서 실행되는 프로세스 간 데이터를 교환하기 위한 데이터 통신 엔드 포인트이다.

    https://velog.velcdn.com/images/phc09188/post/1e8bfbf1-8adb-4f59-870c-789b0379dab0/image.png출처 : https://velog.velcdn.com

  • 네트워크 소켓 통신을 통해 데이터를 공유한다.
  • 클라이언트와 서버가 소켓을 통해서 통신하는 구조로, 원격에서 프로세스 간 데이터를 공유할 때 사용한다.
  • 전이중(양방향)통신이 가능하다.
  • 서버/클라이언트 환경을 구축하는데 용이하다.
  • 중대형 어플리케이션에서 주로 사용한다.

메시지 큐(Message Queue)

  • 입출력 방식은 이름있는 파이프와 동일하다.

    https://velog.velcdn.com/images/phc09188/post/ce41f521-1515-4b76-9e2b-df7ee0418234/image.png출처 : https://velog.velcdn.com

  • 이름있는 파이프와 다른 점
    • 메시지 큐는 파이프처럼 데이터의 흐름이 아니라 메모리 공간을 사용한다.
    • PIPE 나 FIFO 와는 달리 다수의 프로세스간 메세지를 전달 할 수 있다.
  • 사용할 데이터에 번호를 붙이면서 여러 프로세스가 동시에 데이터를 쉽게 다룰 수 있다.
  • 메시지의 접근을 위해서는 키가 필요하다.

메모리 맵(Memory Map)

  • 공유 메모리처럼 메모리를 공유해준다.

    https://velog.velcdn.com/images/phc09188/post/df38d877-ffc7-4690-b576-b668c50b27d3/image.png출처 : https://velog.velcdn.com

  • 메모리 맵은 열린 파일을 메모리에 맵핑시켜서 공유하는 방식이다.
  • 주로 파일로 대용량 데이터를 공유해야 할 때 사용한다.
  • FILE IO가 느릴 때 사용하면 좋다.
  • 대부분의 운영체제에서는 프로세스를 실행할 때 실행 파일의 각 세그먼트를 메모리에 사상하기 위해 메모리 맵 파일을 이용한다.
  • 메모리 맵 파일은 파일의 크기를 바꿀 수는 없으며 메모리 맵 파일을 사용하기 이전, 또는 이후에만 파일의 크기를 바꿀 수 있다.
맨 위로 이동 ↑

Tag : ,

Category :

Last Modified :

댓글 남기기