정리

[Win32] IPC - #3 Pipe(파이프)

저장소/VC++
[출처] 윈도우즈 API 정복, 김상형 지음

Win32 파이프는 두 프로세스간에 정보를 주고 받을 수 있는 통로(Information Conduit)를 말하는데 다양한 IPC 방법 중 하나이며 주로 연속적인 바이트 스트림을 교환할 때 많이 사용된다.
Win32 API는 이름없는 파이프와 이름있는 파이프 두 가지 종류의 파이프를 지원한다.

1. 이름없는 파이프(Anonymous Pipe) - 잘 안쓰이니 대충 넘겨도 됨.
 주로 부모 자식간의 단방향 통신에만 사용, 네트워크상의 다른 컴퓨터끼리는 사용할 수 없는 로컬 전용의 파이프이다. 이름있는 파이프에 비해 오버헤드가 적으니 기능상의 제약이 많다. 함수는 아래와 같다.

BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize);

이 함수는 파이프를 생성하고 파이프 양쪽 끝인 읽기 핸들과 쓰기 핸들을 첫 번째 인수(hReadPipe)와 두 번째 인수(hWritePipe)로 전달된 참조인수로 리턴한다. 두 개의 HANDLE형 변수를 선언하고 변수의 포인터를 이 함수로 전달하면 된다. 세 번째 인수는 파이프의 보안 속성을 지정하는데 이름없는 파이프는 주로 상속을 통해 자식 프로세스로 전달되므로 보안 속성의 bInheritHandle멤버를 TRUE로 설정해야 한다. 네 번째 인수 nSize는 파이프의 버퍼 크기이되 0으로 지정하면 디폴트 크기로 버퍼를 만든다.

부모 프로세스가 자식 프로세스에게 데이터를 보낼 때 취해야 하는 절차이다. 반대로 데이터를 받아야 할 때는 핸들만 바꿔주면 된다.

ㄱ. 일기 핸들 전달을 위해 표준 입력을 재지향하는데 핸들 전달 후 복구를 위해 표준 입력 핸들을 저장해 놓는다.
ㄴ. 상속 가능한 파이프를 생성한 후 표준 입력을 파이프의 읽기 핸들로 재지향한다. 이때 쓰기 핸들은 상속되어서는 안 되므로 상속되지 않는 복사본을 만들고 원래의 상속 가능한 쓰기 핸들은 파괴한다.
ㄷ. 차일드 프로세스를 실행한다. 부모 프로세스의 표준 입력 핸들이 차일드로 상속되며 이때 표준 입력이 파이프의 읽기 핸들로 재지향되어 있으므로 차일드는 결과적으로 파이프의 읽기 핸들을 상속받게 된다.
ㄹ. 부모는 읽기 핸들을 차일드에게 전달했으므로 자신이 가지고 있는 읽기 핸들은 닫는다. 그리고 보관해 놓았던 표준 입력 핸들을 원래대로 복구한다.
ㅁ. 쓰기 핸들의 복사본으로 데이터를 보내면 차일드는 표준 입력 핸들로부터 데이터를 읽을 수 있다.
ㅂ. 통신이 끝난 후 쓰기 핸들을 닫는다. 양쪽 끝의 핸들이 모두 파괴되면 파이프도 같이 파괴된다.


2. 이름있는 파이프(Named Pipe) - 확실히 알아둘 것




함수는 아래와 같다.
HANDLE CreateNamedPipe(LPCTSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes);

[파라미터 설명]

lpName
만들고자 하는 파이프의 이름을 지정한다. 다른 파이프와 중복되지 않아야 한다.
형식은 아래와 같다.
"\\서버명\pipe\파이프 이름"
로컬 컴퓨터인 경우는 마침표(.)를 대신 찍으면 된다.
"\\.\pipe\파이프 이름"
CreateNamedPipe는 원격지 컴퓨터의 파이프를 생성하는 기능은 가지고 있지 않다. 그러나 CreateFile, CallNamedPipe 등 파이프를 여는 함수는 원격지의 파이프를 열 수 도 있으므로 이 때는 파이프 이름에 서버명을 같이 지정해야 한다.

파이프 이름은 최대 256문자까지 가능하며 대소문자는 구분하지 않는다.

dwOpenMode
동기화 입출력
비동기화 입출력

완전 쓰기 모드(Write through)는 바이트 유형의 원격지 컴퓨터끼리 통신할 때만 유효하다. FILE_FLAG_WRITE_THROUGH 플래그를 지정하므로써 파이프를 완전 쓰기 모드로 동작시킬 수 있다.
WriteFile 함수로 출력을 내보내면 원격지 컴퓨터의 버퍼에 데이터가 완전히 전달되기 전에는 리턴하지 않는다. 즉 데이터를 버퍼에 넣는 것 뿐만 아니라 이 데이터가 네트워크를 통해 반대편 컴퓨터의 버퍼로 완전히 전달될 때까지 대기한다.
이 모드는 쓰기 동작을 완벽하게 동기화해야 할 때 유용하다.
파이프를 생성할 때만 지정할 수 있어서 서버, 클라이언트가 각각 다른 모드로 지정하는 것도 가능하다.


dwPipeMode
파이프의 유형, 읽기 모드, 대기 모드를 지정한다.
파이프 유형은 파이프로 데이터가 출력되는 방법을 지정, 바이트 유형과 메시지 유형 두 가지가 있다.

바이트 유형

메시지 유형

읽기 모드

대기 모드

dwMaxInstances
같은 파이프 이름으로 생성할 수 있는 최대의 인스턴스 갯수를 지정한다. 즉 하나의 서버가 동시에 통신할 수 있는 클라이언트의 갯수이다.
1 ~ PIPE_UNLIMITED_INSTANCES(256)까지 지정할 수 있다.

nOutBufferSize, nInBufferSize
파이프의 입력용, 출력용 버퍼의 크기를 지정한다. 단, 이 크기는 어디까지나 권장치일 뿐이며 실제로 시스템은 효율을 높이기 위해 이 인수로 지정한 크기와는 다르게 버퍼를 할당하기도 한다.

nDefaultTimeOut
디폴트 제한 시간은 1/1000초 단위로 지정한다. 이 값은 WaitNamedPipe 함수가 여유 파이프를 대기할 때 제한 시간으로 사용된다. 모든 인스턴스가 동일한 제한 시간으로 파이프를 생성해야 한다.

lpSecurityAttributes
파이프도 커널 오브젝트이므로 보안 속성을 지정할 수 있다. NULL로 지정하면 디폴트 보안 속성이 적용된다. 대개의 경우 NULL로 지정하면 별 말썽이 없다.