호우동의 개발일지

Today :

article thumbnail

파이프

  • 파이프는 두 프로세스가 통신할 수 있게 하는 전달자로서 동작
    • 초기 UNIX 시스템에서 제공하는 IPC 기법의 하나

  • 파이프는 프로세스 간에 통신하는 간단한 방법이지만, 통신할 때 여러 제약이 발생
  • 파이프 구현을 위해 고려해야 할 점
    1. 파이프가 단방향 또는 양방향 통신을 허용하는가?
    2. 양방향 통신이 허용된다면 → 반이중 방식인가, 전이중 방식인가?
      • 반이중 방식 : 한 순간에 한 방향 전송만 가능
      • 전이중 방식 : 동시에 양방향 데이터 전송 가능

    3. 통신하는 두 프로세스 간에 부모-자식과 같은 특정 관계가 존재해야 하는가?
    4. 파이프는 네트워크를 통해 통신이 가능한가, 아니면 동일 기계 안에 있는 두 프로세스끼리만 가능?

 


일반 파이프

  • 일반 파이프는 생산자-소비자 형태로, 두 프로세스 간의 통신을 허용
    • 생산자는 쓰기 종단에 쓰고, 소비자는 읽기 종단에서 읽는다.
      → 일반 파이프는 한쪽으로 데이터를 전송할 수 있으며, 단방향 통신만 가능
      • 양방향 통신이 하고 싶다면 파이프 2개를 사용해야 함

  • 일반 파이프는 파이프를 생성한 프로세스 이외에는 접근할 수 없다.

  • UNIX 시스템에서 일반 파이프 사용
    • UNIX는 파이프를 파일의 특수한 유형으로 취급
      → 파이프는 일반적은 read()와 write() 시스템콜을 사용하여 접근 가능

    • pipe(int fd []) : fd [] 파일 설명자를 통해 접근되는 파이프를 생성
      • fd [0] → 파이프의 읽기 종단
      • fd [1] → 파이프의 쓰기 종단

    • 부모 프로세스가 파이프를 생성하고 fork()로 생성한 자식 프로세스와 통신하기 위해 사용
      파이프의 부모 자식은 서로 통신이 가능하다.
      • 파이프는 파일의 특수한 유형이기 때문에 자식 프로세스는 부모로부터 파이프를 상속받음
        • 부모가 쓰기 종단(fd [1])에 데이터를 쓰면 읽기 종단(fd [0])에서 자식이 읽을 수 있다.

  • Windows 시스템에서의 일반 파이프
    • 익명 파이프(anonymous pipe)라고 부른다.
    • UNIX의 파이프와 유사하게 동작 → 단방향/ 두 프로세스가 부모-자식 관계
    • 파이프의 읽기와 쓰기는 Read-File()과 WriteFile()을 통해 이루어짐
    • 파이프를 생성하기 위한 Windows API → CreatePipe() (매개변수 4개)
    • UNIX와는 다르게, 부모 프로세스가 생성한 파이프가 자동으로 상속되지 않음
      → 프로그래머가 어떤 속성을 상속받는지 명시해줘야 함
      • 파이프는 반이중 방식이므로 자식이 파이프의 쓰기 종단을 상속받는 것을 금지시켜야 함

  • 두 프로그램 간의 중요한 공통점
    • 통신하는 두 프로세스는 부모-자식 관계를 가져야 한다.
    • 이 유형의 파이프는 동일한 기계상의 두 프로세스끼리만 통신이 가능하다.
    • 일반 파이프는 오로지 프로세스들이 서로 통신하는 동안에만 존재
      → 통신이 종료되면 일반 파이프는 사라짐

 


지명 파이프(Named Pipes)

  • 통신이 양방향으로 가능하며, 부모-자식 관계도 필요하지 않음
  • 지명 파이프는 다수의 writer을 가지며, 프로세스가 종료하더라도 계속 존재한다.
  • UNIX에서의 지명 파이프 - FIFO
    • 생성되면 지명 파이프는 파일 시스템의 보통 파일처럼 존재
    • mkfifo() 시스템 콜을 이용하여 생성됨
      • open() , read(), write() , close() 시스템 콜로 조작
      • 명시적으로 파일 시스템에서 삭제될 때까지 존재

    • 양방향 통신을 허용하긴 하지만 반이중 전송만 가능
      • 양방향 통신할 일이 생기면 FIFO 2개 사용

    • 통신하는 두 프로세스는 동일한 기계 내에 존재해야 함
      • 다른 기계에 존재하는 프로세스 사이에 통신이 필요하면 소켓이 필요
    • byte 단위 통신만 허용

  • Windows 시스템의 지명 파이프 → UNIX보다 훨씬 풍부한 통신 기법 제공
    • 전이중 통신 허용, 두 프로세스는 같은 기계/ 다른 기계 상에 존재할 수 있음
    • byte 단위 혹은 메시지 단위 데이터 전송 허용
    • CreateNamePipe() 함수를 사용해서 생성, ConnectNamedPipe()를 사용해 연결
      • ReadFile()과 WriteFile() 함수를 사용하여 실행

 

 


클라이언트 서버 환경에서 통신


소켓

  • 소켓(socket) : 통신의 극점을 뜻함
  • 소켓을 이용한 통신은 분산된 프로세스 간에 널리 사용되고 효율적
  • 두 프로세스가 네트워크상에서 통신을 하려면 양 프로세스당 하나씩 소켓이 필요
  • 각 소켓은 IP주소와 포트 번호 2가지 결합하여 구분
  • 소켓은 클라이언트-서버 구조 사용
    1. 서버는 지정된 포트에 클라이언트 요청 메시지가 도착하기를 기다림
    2. 요청이 수신되면 서버는 클라이언트 소켓으로부터 연결 요청을 수락함으로써 연결 완성

  • Talnet, ftp 및 http 등의 특정 서비스를 구현하는 서버는 well-known 포트로부터 메시지를 기다림
    • well-known 포트 : 전 세계적으로 표준으로 사용하는 포트 번호라는 의미
      • SSH 서버는 22번, FTP 서버는 21번, HTTP 서버는 80번 포트 사용 등등
      • 1024 미만의 모든 포트는 well-known 포트로 간주되며 표준 서비스를 구현하는 데 사용

 


소켓 서버 연결

  • 클라이언트 프로세스가 연결 요청 → 호스트 컴퓨터가 포트 번호 부여
    • 해당 번호는 1024보다 큰 임의의 정수
      소켓을 사용한 통신
      소켓을 사용한 통신
      1. 호스트 X에 있는 클라이언트(IP : 148.51.5.25)가 웹 서버에 접속하려고 함
      2. 호스트 X는 클라이언트에게 포트 1852를 부여
        → 연결은 소켓 호스트 X의 (148.51.5.25:1852)와 (161.125.32.9:80)으로 구성

    • 모든 연결은 유일해야 함
      • 다른 클라이언트 프로세스가 동일한 서버와 통신 → 다른 포트 번호를 부여
        → 모든 연결이 유일한 소켓 쌍으로 구성되는 것을 보장

 


Java 소켓 통신

  • 3가지 종류의 소켓을 제공
    • 연결 기반(TCP) 소켓 : socket 클래스로 구현
    • 비연결성(UDP) 소켓 : DatagramSocket 클래스 사용
    • Mul-ticast 소켓 : DatagramSocket의 서브클래스
      • 데이터를 여러 수신자에게 보낼 수 있다.

 


소켓의 한계

  • 소켓을 이용한 통신은 너무 낮은 수준
    • 원시적인 바이트 스트림 데이터를 구조화하여 해석하는 것은 클라이언트와 서버의 책임
      ← 스레드 간에 구조화되지 않은 바이트 스트림만 통신하기 때문

 

 


원격 프로시저 호출(RPC 패러다임)

  • 네트워크에 연결된 두 시스템의 통신에 사용하기 위한 프로시저 호출 기법을 추상화하는 방법으로 설계
    • 원격 서비스와 관련된 가장 보편적인 형태 중 하나

  • IPC와 많은 측면이 유사하며, IPC 기반 위에 만들어짐
  • RPC(원격 프로시저)는 클라이언트가 원격 호스트의 프로시저 호출하는 것을
    마치 자기 프로시저를 호출하는 것처럼 해줌

 


IPC와의 차이점(특징)

  • 원격 서비스 제공을 위해 메시지 기반 통신을 해야 함
    ← 프로세스들이 서로 다른 시스템 위에서 돌아가기 때문에

  • RPC 통신에서 전달되는 메시지는 구조화되어 있음 → 데이터의 패킷 수준을 넘어섬
    • 각 메시지에는 원격지 포트에서 listen 중인 RPC 디먼의 주소가 지정되어 있음
    • 실행되어야 할 함수의 식별자, 매개변수가 포함
    • 요청된 함수가 실행되고 어떤 출력이든지 별도의 메시지를 통해 요청자에게 반환

 


원격 프로시저에서의 포트

  • 여기서 포트는 단순히 메시지 패키지의 시작 부분에 포함된 정수
  • 시스템의 네트워크 주소는 하나, But 포트는 여러 개 가질 수 있음
    ← 왜? 시스템에서 지원되는 여러 서비스를 구별하기 위해서

  • 원격 프로세스가 어떤 서비스를 받고자 하면 그 서비스에 대응되는 포트 주소로 메시지를 보내야 함

 


스텁(Stub)

  • RPC 시스템은 클라이언트 쪽에 스텁을 제공하여 통신을 하는데 필요한 자세한 사항들을 숨겨줌
  • 원격 프로시저마다 다른 스텁이 존재
  • 클라이언트가 원격 프로시저 호출 시 일어나는 과정
    1. RPC는 그에 대응하는 스텁을 호출하고, 원격 프로시저가 필요로 하는 매개변수를 건네줌
    2. 스텁이 원격 서버의 포트를 찾고 매개변수를 정돈
    3. 스텁은 메시지 전달 기법을 사용하여 서버에게 메시지를 전송
    4. 이에 대응되는 서버 측 스텁이 메시지를 수신한 뒤 적절한 서버의 프로시저를 호출
      • 필요한 경우 반환 값들도 동일한 방식으로 돌려줌

 


스텁에서 하는 매개변수 정돈

  • 매개변수 정돈은 클라이언트와 서버 기기의 데이터 표현 방식의 차이 문제를 해결한다.
      • 어떤 기계는 최상위 바이트를 먼저 저장하고, 다른 기계는 최하위 바이트를 먼저 저장
        → 차이 해결을 위해 RPC 시스템은 기종 중립적인 데이터 표현 방식을 정의
        → 이러한 표현 방식 중 하나인 XDR(external data representation) 사용

    1. 클라이언트 층에서 데이터를 보내기 전 매개변수 정돈 작업의 일환으로 XDR 형태로 바꾸어 보낸다.
    2. 수신 측 기계에서는 XDR 데이터를 받아, 매개변수를 풀어내서 데이터를 바꾼 후 서버에게 전달.

 


호출의 의미

  • RPC 경우, 네트워크 오류 때문에 실패할 수도 있고, 메시지 중복되어 호출이 여러 번 실행될 수 있다.
    → 문제 해결법 : 운영체제가 메시지를 “최대 한번”이 아닌 “정확히 한번” 실행되도록 보장하는 것

  • “최대 한번”은 각 메시지에 타임스탬프를 매기는 것으로 보장 가능
    → 서버는 이미 처리한 모든 메시지의 타임스탬프 기록, 중복 메시지를 검사할 만큼의 기록을 가져야 함
    → 기록에 보관된 타임스탬프를 가진 메시지가 도착하면 그 메시지는 무시
    → 해당 방법으로 클라이언트는 한 번 이상 메시지를 보낼 수 있고, “단 한번” 실행을 보장받음

  • “정확히 한번”을 하기 위해선 서버가 요청을 받지 못하는 위험을 제거할 필요가 있음
    • 이를 완수하기 위해선 위의 “최대 한 번” 프로토콜을 구현하고,
      추가로 RPC 요청이 수신됐고 실행됐다는 응낙 메시지를 보내야 한다.
      • 클라이언트는 해당 호출에 대한 ACK을 받을 때까지 주기적으로 각 RPC 호출을 재전송해야 함

 


클라이언트와 서버 간의 통신 문제

  • RPC가 클라이언트와 서버의 포트를 바인딩할 때, 클라이언트는 서버의 포트 번호를 알 수가 없음
    ← 이는 공유 메모리가 없기 때문

  • 2가지 방법이 사용됨
    1. 고정된 포트 주소 형태로 미리 정해 놓는 방법
      • 컴파일되고 나면 그 후에는 서버가 포트 번호를 임의로 바꿀 수 없음

    2. 랑데부 방식에 의해 동적으로 바인딩하는 방법
      • 운영체제는 고정 RPC 포트를 통해 랑데부용 디먼(matchmaker)을 제공
        • 해당 방식은 통신 초기에 오버헤드가 조금 발생하지만 1번 방식보다 더 유연함
          RPC의 실행
          RPC의 실행
        1. 클라이언트가 실행하기를 원하는 RPC 이름을 가진 메시지를 matchmaker에게 전송
        2. matchmaker은 RPC 이름에 대응하는 포트 번호가 무엇인지 알려달라고 요청
        3. 포트 번호가 클라이언트에게 반환
        4. 클라이언트는 그 포트 번호로 RPC 요청을 계속 보낸다.

 


분산 파일 시스템(Distributed File System, DFS)

  • RPC는 분산 파일 시스템(DFS)을 구현하는데 유용하다.
  • DFS는 몇 개의 RPC 디먼과 클라이언트로 구현할 수 있다.
    • 메시지가 원격지 DFS 서버 포트로 보내지고 이 서버는 file operation을 실행해 준다.
      • 메시지는 실행할 디스크 연산 포함
      • DFS는 이 연산 결과를 클라이언트에게 반환 메시지로 보낸다.
        • 파일 전체를 보내라는 것일 수도 있고,
          몇 개의 블록만 보내라는 것이 될 수도 있음