파이프
- 파이프는 두 프로세스가 통신할 수 있게 하는 전달자로서 동작
- 초기 UNIX 시스템에서 제공하는 IPC 기법의 하나
- 초기 UNIX 시스템에서 제공하는 IPC 기법의 하나
- 파이프는 프로세스 간에 통신하는 간단한 방법이지만, 통신할 때 여러 제약이 발생
- 파이프 구현을 위해 고려해야 할 점
- 파이프가 단방향 또는 양방향 통신을 허용하는가?
- 양방향 통신이 허용된다면 → 반이중 방식인가, 전이중 방식인가?
반이중 방식
: 한 순간에 한 방향 전송만 가능전이중 방식
: 동시에 양방향 데이터 전송 가능
- 통신하는 두 프로세스 간에 부모-자식과 같은 특정 관계가 존재해야 하는가?
- 파이프는 네트워크를 통해 통신이 가능한가, 아니면 동일 기계 안에 있는 두 프로세스끼리만 가능?
- 파이프가 단방향 또는 양방향 통신을 허용하는가?
일반 파이프
- 일반 파이프는 생산자-소비자 형태로, 두 프로세스 간의 통신을 허용
- 생산자는 쓰기 종단에 쓰고, 소비자는 읽기 종단에서 읽는다.
→ 일반 파이프는 한쪽으로 데이터를 전송할 수 있으며, 단방향 통신만 가능- 양방향 통신이 하고 싶다면 파이프 2개를 사용해야 함
- 양방향 통신이 하고 싶다면 파이프 2개를 사용해야 함
- 생산자는 쓰기 종단에 쓰고, 소비자는 읽기 종단에서 읽는다.
- 일반 파이프는 파이프를 생성한 프로세스 이외에는 접근할 수 없다.
- UNIX 시스템에서 일반 파이프 사용
- UNIX는 파이프를 파일의 특수한 유형으로 취급
→ 파이프는 일반적은 read()와 write() 시스템콜을 사용하여 접근 가능 pipe(int fd [])
: fd [] 파일 설명자를 통해 접근되는 파이프를 생성- fd [0] → 파이프의 읽기 종단
- fd [1] → 파이프의 쓰기 종단
- 부모 프로세스가 파이프를 생성하고 fork()로 생성한 자식 프로세스와 통신하기 위해 사용
- 파이프는 파일의 특수한 유형이기 때문에 자식 프로세스는 부모로부터 파이프를 상속받음
- 부모가 쓰기 종단(fd [1])에 데이터를 쓰면 읽기 종단(fd [0])에서 자식이 읽을 수 있다.
- 부모가 쓰기 종단(fd [1])에 데이터를 쓰면 읽기 종단(fd [0])에서 자식이 읽을 수 있다.
- 파이프는 파일의 특수한 유형이기 때문에 자식 프로세스는 부모로부터 파이프를 상속받음
- UNIX는 파이프를 파일의 특수한 유형으로 취급
- Windows 시스템에서의 일반 파이프
- 익명 파이프(anonymous pipe)라고 부른다.
- UNIX의 파이프와 유사하게 동작 → 단방향/ 두 프로세스가 부모-자식 관계
- 파이프의 읽기와 쓰기는 Read-File()과 WriteFile()을 통해 이루어짐
- 파이프를 생성하기 위한 Windows API →
CreatePipe()
(매개변수 4개) - UNIX와는 다르게, 부모 프로세스가 생성한 파이프가 자동으로 상속되지 않음
→ 프로그래머가 어떤 속성을 상속받는지 명시해줘야 함- 파이프는 반이중 방식이므로 자식이 파이프의 쓰기 종단을 상속받는 것을 금지시켜야 함
- 파이프는 반이중 방식이므로 자식이 파이프의 쓰기 종단을 상속받는 것을 금지시켜야 함
- 두 프로그램 간의 중요한 공통점
- 통신하는 두 프로세스는 부모-자식 관계를 가져야 한다.
- 이 유형의 파이프는 동일한 기계상의 두 프로세스끼리만 통신이 가능하다.
- 일반 파이프는 오로지 프로세스들이 서로 통신하는 동안에만 존재
→ 통신이 종료되면 일반 파이프는 사라짐
지명 파이프(Named Pipes)
- 통신이 양방향으로 가능하며, 부모-자식 관계도 필요하지 않음
- 지명 파이프는 다수의 writer을 가지며, 프로세스가 종료하더라도 계속 존재한다.
- UNIX에서의 지명 파이프 - FIFO
- 생성되면 지명 파이프는 파일 시스템의 보통 파일처럼 존재
mkfifo()
시스템 콜을 이용하여 생성됨open()
, read(),write()
, close() 시스템 콜로 조작- 명시적으로 파일 시스템에서 삭제될 때까지 존재
- 양방향 통신을 허용하긴 하지만 반이중 전송만 가능
- 양방향 통신할 일이 생기면 FIFO 2개 사용
- 양방향 통신할 일이 생기면 FIFO 2개 사용
- 통신하는 두 프로세스는 동일한 기계 내에 존재해야 함
- 다른 기계에 존재하는 프로세스 사이에 통신이 필요하면 소켓이 필요
- 다른 기계에 존재하는 프로세스 사이에 통신이 필요하면 소켓이 필요
- byte 단위 통신만 허용
- Windows 시스템의 지명 파이프 → UNIX보다 훨씬 풍부한 통신 기법 제공
- 전이중 통신 허용, 두 프로세스는 같은 기계/ 다른 기계 상에 존재할 수 있음
- byte 단위 혹은 메시지 단위 데이터 전송 허용
CreateNamePipe()
함수를 사용해서 생성,ConnectNamedPipe()
를 사용해 연결ReadFile()과
WriteFile()
함수를 사용하여 실행
클라이언트 서버 환경에서 통신
소켓
소켓(socket)
: 통신의 극점을 뜻함- 소켓을 이용한 통신은 분산된 프로세스 간에 널리 사용되고 효율적
- 두 프로세스가 네트워크상에서 통신을 하려면 양 프로세스당 하나씩 소켓이 필요
- 각 소켓은 IP주소와 포트 번호 2가지 결합하여 구분
- 소켓은 클라이언트-서버 구조 사용
- 서버는 지정된 포트에 클라이언트 요청 메시지가 도착하기를 기다림
- 요청이 수신되면 서버는 클라이언트 소켓으로부터 연결 요청을 수락함으로써 연결 완성
- Talnet, ftp 및 http 등의 특정 서비스를 구현하는 서버는 well-known 포트로부터 메시지를 기다림
well-known 포트
: 전 세계적으로 표준으로 사용하는 포트 번호라는 의미- SSH 서버는 22번, FTP 서버는 21번, HTTP 서버는 80번 포트 사용 등등
- 1024 미만의 모든 포트는 well-known 포트로 간주되며 표준 서비스를 구현하는 데 사용
소켓 서버 연결
- 클라이언트 프로세스가 연결 요청 → 호스트 컴퓨터가 포트 번호 부여
- 해당 번호는 1024보다 큰 임의의 정수
- 호스트 X에 있는 클라이언트(IP : 148.51.5.25)가 웹 서버에 접속하려고 함
- 호스트 X는 클라이언트에게 포트 1852를 부여
→ 연결은 소켓 호스트 X의 (148.51.5.25:1852)와 (161.125.32.9:80)으로 구성
- 모든 연결은 유일해야 함
- 다른 클라이언트 프로세스가 동일한 서버와 통신 → 다른 포트 번호를 부여
→ 모든 연결이 유일한 소켓 쌍으로 구성되는 것을 보장
- 다른 클라이언트 프로세스가 동일한 서버와 통신 → 다른 포트 번호를 부여
- 해당 번호는 1024보다 큰 임의의 정수
Java 소켓 통신
- 3가지 종류의 소켓을 제공
연결 기반(TCP) 소켓
: socket 클래스로 구현비연결성(UDP) 소켓
: DatagramSocket 클래스 사용Mul-ticast 소켓
: DatagramSocket의 서브클래스- 데이터를 여러 수신자에게 보낼 수 있다.
소켓의 한계
- 소켓을 이용한 통신은 너무 낮은 수준
- 원시적인 바이트 스트림 데이터를 구조화하여 해석하는 것은 클라이언트와 서버의 책임
← 스레드 간에 구조화되지 않은 바이트 스트림만 통신하기 때문
- 원시적인 바이트 스트림 데이터를 구조화하여 해석하는 것은 클라이언트와 서버의 책임
원격 프로시저 호출(RPC 패러다임)
- 네트워크에 연결된 두 시스템의 통신에 사용하기 위한 프로시저 호출 기법을 추상화하는 방법으로 설계
- 원격 서비스와 관련된 가장 보편적인 형태 중 하나
- 원격 서비스와 관련된 가장 보편적인 형태 중 하나
- IPC와 많은 측면이 유사하며, IPC 기반 위에 만들어짐
- RPC(원격 프로시저)는 클라이언트가 원격 호스트의 프로시저 호출하는 것을
마치 자기 프로시저를 호출하는 것처럼 해줌
IPC와의 차이점(특징)
- 원격 서비스 제공을 위해 메시지 기반 통신을 해야 함
← 프로세스들이 서로 다른 시스템 위에서 돌아가기 때문에 - RPC 통신에서 전달되는 메시지는 구조화되어 있음 → 데이터의 패킷 수준을 넘어섬
- 각 메시지에는 원격지 포트에서 listen 중인 RPC 디먼의 주소가 지정되어 있음
- 실행되어야 할 함수의 식별자, 매개변수가 포함
- 요청된 함수가 실행되고 어떤 출력이든지 별도의 메시지를 통해 요청자에게 반환
원격 프로시저에서의 포트
- 여기서 포트는 단순히 메시지 패키지의 시작 부분에 포함된 정수
- 시스템의 네트워크 주소는 하나, But 포트는 여러 개 가질 수 있음
← 왜? 시스템에서 지원되는 여러 서비스를 구별하기 위해서 - 원격 프로세스가 어떤 서비스를 받고자 하면 그 서비스에 대응되는 포트 주소로 메시지를 보내야 함
스텁(Stub)
- RPC 시스템은 클라이언트 쪽에 스텁을 제공하여 통신을 하는데 필요한 자세한 사항들을 숨겨줌
- 원격 프로시저마다 다른 스텁이 존재
- 클라이언트가 원격 프로시저 호출 시 일어나는 과정
- RPC는 그에 대응하는 스텁을 호출하고, 원격 프로시저가 필요로 하는 매개변수를 건네줌
- 스텁이 원격 서버의 포트를 찾고 매개변수를 정돈
- 스텁은 메시지 전달 기법을 사용하여 서버에게 메시지를 전송
- 이에 대응되는 서버 측 스텁이 메시지를 수신한 뒤 적절한 서버의 프로시저를 호출
- 필요한 경우 반환 값들도 동일한 방식으로 돌려줌
스텁에서 하는 매개변수 정돈
- 매개변수 정돈은 클라이언트와 서버 기기의 데이터 표현 방식의 차이 문제를 해결한다.
- 예
- 어떤 기계는 최상위 바이트를 먼저 저장하고, 다른 기계는 최하위 바이트를 먼저 저장
→ 차이 해결을 위해 RPC 시스템은 기종 중립적인 데이터 표현 방식을 정의
→ 이러한 표현 방식 중 하나인 XDR(external data representation) 사용
- 어떤 기계는 최상위 바이트를 먼저 저장하고, 다른 기계는 최하위 바이트를 먼저 저장
- 클라이언트 층에서 데이터를 보내기 전 매개변수 정돈 작업의 일환으로 XDR 형태로 바꾸어 보낸다.
- 수신 측 기계에서는 XDR 데이터를 받아, 매개변수를 풀어내서 데이터를 바꾼 후 서버에게 전달.
- 예
호출의 의미
- RPC 경우, 네트워크 오류 때문에 실패할 수도 있고, 메시지 중복되어 호출이 여러 번 실행될 수 있다.
→ 문제 해결법 : 운영체제가 메시지를 “최대 한번”이 아닌 “정확히 한번” 실행되도록 보장하는 것 - “최대 한번”은 각 메시지에 타임스탬프를 매기는 것으로 보장 가능
→ 서버는 이미 처리한 모든 메시지의 타임스탬프 기록, 중복 메시지를 검사할 만큼의 기록을 가져야 함
→ 기록에 보관된 타임스탬프를 가진 메시지가 도착하면 그 메시지는 무시
→ 해당 방법으로 클라이언트는 한 번 이상 메시지를 보낼 수 있고, “단 한번” 실행을 보장받음 - “정확히 한번”을 하기 위해선 서버가 요청을 받지 못하는 위험을 제거할 필요가 있음
- 이를 완수하기 위해선 위의 “최대 한 번” 프로토콜을 구현하고,
추가로 RPC 요청이 수신됐고 실행됐다는 응낙 메시지를 보내야 한다.- 클라이언트는 해당 호출에 대한 ACK을 받을 때까지 주기적으로 각 RPC 호출을 재전송해야 함
- 이를 완수하기 위해선 위의 “최대 한 번” 프로토콜을 구현하고,
클라이언트와 서버 간의 통신 문제
- RPC가 클라이언트와 서버의 포트를 바인딩할 때, 클라이언트는 서버의 포트 번호를 알 수가 없음
← 이는 공유 메모리가 없기 때문 - 2가지 방법이 사용됨
- 고정된 포트 주소 형태로 미리 정해 놓는 방법
- 컴파일되고 나면 그 후에는 서버가 포트 번호를 임의로 바꿀 수 없음
- 컴파일되고 나면 그 후에는 서버가 포트 번호를 임의로 바꿀 수 없음
- 랑데부 방식에 의해 동적으로 바인딩하는 방법
- 운영체제는 고정 RPC 포트를 통해 랑데부용 디먼(matchmaker)을 제공
- 해당 방식은 통신 초기에 오버헤드가 조금 발생하지만 1번 방식보다 더 유연함
- 클라이언트가 실행하기를 원하는 RPC 이름을 가진 메시지를 matchmaker에게 전송
- matchmaker은 RPC 이름에 대응하는 포트 번호가 무엇인지 알려달라고 요청
- 포트 번호가 클라이언트에게 반환
- 클라이언트는 그 포트 번호로 RPC 요청을 계속 보낸다.
- 해당 방식은 통신 초기에 오버헤드가 조금 발생하지만 1번 방식보다 더 유연함
- 운영체제는 고정 RPC 포트를 통해 랑데부용 디먼(matchmaker)을 제공
- 고정된 포트 주소 형태로 미리 정해 놓는 방법
분산 파일 시스템(Distributed File System, DFS)
- RPC는 분산 파일 시스템(DFS)을 구현하는데 유용하다.
- DFS는 몇 개의 RPC 디먼과 클라이언트로 구현할 수 있다.
- 메시지가 원격지 DFS 서버 포트로 보내지고 이 서버는 file operation을 실행해 준다.
- 메시지는 실행할 디스크 연산 포함
- DFS는 이 연산 결과를 클라이언트에게 반환 메시지로 보낸다.
- 파일 전체를 보내라는 것일 수도 있고,
몇 개의 블록만 보내라는 것이 될 수도 있음
- 파일 전체를 보내라는 것일 수도 있고,
- 메시지가 원격지 DFS 서버 포트로 보내지고 이 서버는 file operation을 실행해 준다.