https://basaeng.tistory.com/40
개요
이전의 메일슬롯에 이어 이번에는 파이프 기반 IPC에 대해 알아보자.
그 전에 더 자세한 이해를 위해 오브젝트 핸들 상속과 핸들 테이블에 대해서 알아보자.
핸들 테이블과 오브젝트 핸들의 상속
커널 오브젝트는 OS가 관리하지만 이를 가리키는 오브젝트 핸들은 프로세스가 소유한다.
이 말은 같은 핸들 값을 가지는 것은 같은 커널 오브젝트를 가리킨다는 뜻이 아니며, 서로 다른 핸들 값이더라도 같은 커널 오브젝트를 가리킬 수 있다는 것이다.
핸들 테이블
각 프로세스는 핸들을 관리하기 위해 핸들 테이블을 사용한다.
커널 오브젝트를 다루는 함수를 사용해보면, HANDLE을 반환하는 것을 알 수있는데 HANDLE은 숫자값으로 실제로 가리키는 주소 값이 아니다.
이를 보아, 함수를 호출하는 과정 내에서 핸들 테이블에 key는 HANDLE값, value는 실제 가리키는 주소를 사용해서 테이블을 채우고 있음을 유추할 수 있다.
핸들의 상속
CreateProcess를 통해서 자식 프로세스를 생성할 때 부모 프로세스가 가진 핸들을 전달할 수 있도록 상속이 존재한다.
단 모든 핸들이 상속되는 것은 아니고, 상속이 허용된 핸들만 상속할 수 있다.
각 핸들의 상속 여부는 해당 리소스가 생성될 때 정해진다.
리소스를 생성할 때 SECURITY_ATTRIBUTES가 보통 필요한데, 이 구조체의 bInheritHandle을 TRUE로 설정하면 생성되는 리소스의 핸들이 상속 가능하게 핸들 테이블에 설정된다.
CreateProcess를 할 때 bInheritHandles 인자를 TRUE로 하면, 자식 프로세스의 핸들 테이블에는, 부모 프로세스의 핸들 중 상속 가능한 테이블이 상속된다.
다만 자식 프로세스는, 상속받은 핸들이 어떤 커널 오브젝트를 가리키는지 알 수 없다.
따라서 자식 프로세스 main에 인자로 전달하거나 별도로 전달하는 방법이 필요하다.

책의 메일슬롯 예시이다.
부모Sender가 자식Sender를 만들고, 자식 Sender는 핸들을 상속받았기 때문에 같은 메일슬롯에 CreateFile없이 연결할 수 있다.
Pseudo 핸들과 핸들의 중복
GetCurrentProcess를 통해서 현재 자신 프로세스의 오브젝트 핸들을 얻을 수 있다.
다만 GetCurrentProcess를 통해서 얻는 핸들은 성능, 안정성, 일관성을 위해 가짜(Pseudo)핸들이 반환된다.
이는 자기자신에 대한 API에 실제 프로세스의 핸들처럼 사용가능하다. 다만 CloseHandle을 통해서 닫을 수는 없다.
실제 현재 프로세스의 핸들을 얻기 위해서는 DuplicateHandle 함수가 필요하다.
https://learn.microsoft.com/ko-kr/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
DuplicateHandle 함수(handleapi.h) - Win32 apps
개체 핸들을 복제합니다.
learn.microsoft.com
이 함수는 source process의 source handle을 복제해 target process에 등록하고 target process의 handle table에 해당 handle값을 돌려줘 인자로 넣은 target handle에 저장한다.
자식 프로세스는 어떤 핸들이 복제된 것인지 알지 못하기 때문에 이 반환된 핸들 값을 이용해 통지해줄 수 있다.
target process를 본인(source process)으로 한다면, 핸들 테이블에 기존의 같은 커널 오브젝트를 가리키는 row가 생긴다.
따라서 Usage Count도 1 증가한다.
파이프 방식의 IPC
Windows에서 파이프는 이름없는(익명)(Anonymous)파이프와, 이름있는(명명)(Named) 파이프 2가지로 나뉜다.
이를 이전의 메일슬롯과 비교해보자.
메일슬롯은 경로를 통해
#define SLOT_NAME _T("\\\\.\\mailslot\\mailbox")
서로 관련이 없는 프로세스들 사이에서 통신한다.
반면, 익명 파이프(Anonymous Pipe)는 이름이 없기 때문에 핸들을 직접 전달해야만 통신할 수 있으며, 이는 주로 부모-자식 관계처럼 생성 시 핸들을 상속시킬 수 있는 프로세스 간에만 유용하다.
명명 파이프(Named Pipe)는 이름을 통해 접근 가능하다는 점에서 메일슬롯과 유사하지만, 양방향 통신이 가능하며, 브로드캐스트는 지원하지 않는다. 또한, 전이중 통신, 동기/비동기 I/O, 네트워크 통신까지 지원하는 등 보다 범용적인 IPC 수단이다.
이름없는 파이프
https://learn.microsoft.com/ko-kr/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
CreatePipe 함수(namedpipeapi.h) - Win32 apps
익명 파이프를 만들고 파이프의 읽기 및 쓰기 끝에 핸들을 반환합니다.
learn.microsoft.com
이름없는 파이프는 배수관과 비슷하다. 단방향으로 물이 들어오는 곳 (hWritePipe)과 나가는 곳이(hReadPipe) 구분되어 있기 때문이다.
BOOL CreatePipe(
[out] PHANDLE hReadPipe,
[out] PHANDLE hWritePipe,
[in, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
[in] DWORD nSize
);
파이프를 생성할 때는 파이프의 양쪽 끝에 접근하기 위한 핸들을 얻을 수 있다.
하나가 hReadPipe 다른 하나가 hWritePipe이다.
nSize는 파이프의 버퍼 크기를 지정할 때 사용한다. 만약 0을 전달하면, default size로 결정된다.
파이프가 생성된 뒤에는 쓰기 핸들(hWritePipe)에는 WriteFile, 읽기 핸들(hReadPipe)에는 ReadFile을 사용해 데이터를 송수신할 수 있다.
hReadPipe 핸들을 자식이 상속받는다면, 부모가 송신하고, 자식이 수신하는 구조이다.
hWritePipe 핸들을 자식이 상속받는다면, 자식이 송신하고, 부모가 수신하는 구조이다.
이름있는 파이프
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-createnamedpipea
CreateNamedPipeA 함수(winbase.h) - Win32 apps
ANSI(CreateNamedPipeA) 함수(winbase.h)는 명명된 파이프의 인스턴스를 만들고 후속 파이프 작업에 대한 핸들을 반환합니다.
learn.microsoft.com
이름 있는 파이프는 양방향 통신을 한다는 것이 핵심이다.
이름있는 파이프를 사용할 때는 마치 메일슬롯에서 CreateMailslot을 Server가 하고, Client가 CreateFile을 통해 연결한 것 처럼,
CreateNamedPipe와 CreateFile이 필요하다. 추가적으로 NamedPipe는 Connection을 유지해야 하므로, ConnectNamedPipe 함수가 필요하다.
CreateNamedPipe
HANDLE CreateNamedPipeA(
[in] LPCSTR lpName,
[in] DWORD dwOpenMode,
[in] DWORD dwPipeMode,
[in] DWORD nMaxInstances,
[in] DWORD nOutBufferSize,
[in] DWORD nInBufferSize,
[in] DWORD nDefaultTimeOut,
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
dwOpenMode: PIPE_ACCESS_DUPLEX, PIPE_ACCESS_BOUND, PIPE_ACCESS_OUTBOUND
dwPipeMode: 3가지의 설정 값을 |(bit or) 연산을 통해 결합해 인자로 사용한다.
1. PIPE_TYPE_BYTE, PIPE_TYPE_MESSAGE
2. PIPE_READMODE_BYTE, PIPE_READMOE_MESSAGE
3. PIPE_WAIT, PIPE_NONWAIT
nMaxInstances: 최초 CreateNamedPipe 호출 시, 해당 파이프 이름으로 만들 수 있는 인스턴스의 최대 개수를 설정하는 인자이다. 이후 같은 이름으로 호출되는 CreateNamedPipe에서는 이 값이 무시된다.
nOutBufferSize: 출력 버퍼 사이즈. 0이면 default
nInBufferSize: 입력 버퍼 사이즈. 0이면 default
nDefaultTimeOut: WaitNamedPipe 함수의 기본 만료 시간을 millisecond로 지정
lpSecurityAttributes: 보안 속성 지정
ConnectNamedPipe
https://learn.microsoft.com/ko-kr/windows/win32/api/namedpipeapi/nf-namedpipeapi-connectnamedpipe
ConnectNamedPipe 함수(namedpipeapi.h) - Win32 apps
명명된 파이프 서버 프로세스가 클라이언트 프로세스가 명명된 파이프의 인스턴스에 연결되기를 기다릴 수 있도록 합니다.
learn.microsoft.com
BOOL ConnectNamedPipe(
[in] HANDLE hNamedPipe,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
NamedPipe를 생성하는 서버 측에서는 ConnectNamedPipe를 파이프를 요청 대기 상태로 변경한다.
CreateNamedPipe 함수 호출을 통해서 생성한 파이프 핸들을 hNamedPipe에 전달한다.
SetNamedPipeHandleState
SetNamedPipeHandleState 함수(namedpipeapi.h) - Win32 apps
지정된 명명된 파이프의 읽기 모드 및 차단 모드를 설정합니다. 지정된 핸들이 명명된 파이프의 클라이언트 끝에 있고 명명된 파이프 서버 프로세스가 원격 컴퓨터에 있는 경우 함수를 사용하
learn.microsoft.com
클라이언트는 CreateFile을 통해 파이프를 연결하고, SetNamedPipeHandleState를 사용해 파이프의 통신 모드를 설정한다.
BOOL SetNamedPipeHandleState(
[in] HANDLE hNamedPipe,
[in, optional] LPDWORD lpMode,
[in, optional] LPDWORD lpMaxCollectionCount,
[in, optional] LPDWORD lpCollectDataTimeout
);
프로세스 환경변수
프로세스 환경변수를 사용하면, 더 안정적으로 자식 프로세스에 정보를 전달할 수 있다.
프로세스 별로 key=value 형태로, 별도의 메모리에 데이터를 저장한다.
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-setenvironmentvariable
SetEnvironmentVariable 함수(winbase.h) - Win32 apps
SetEnvironmentVariable 함수(winbase.h)는 현재 프로세스에 대해 지정된 환경 변수의 내용을 설정합니다.
learn.microsoft.com
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-getenvironmentvariable
GetEnvironmentVariable 함수(winbase.h) - Win32 apps
GetEnvironmentVariable 함수(winbase.h)는 호출 프로세스의 환경 블록에서 지정된 변수의 내용을 검색합니다.
learn.microsoft.com
CreateProcess를 통해 자식 프로세스를 생성할 때 환경변수 정보를 NULL로 설정하면 부모의 환경변수를 사용할 수 있다.
'C, C++ > 뇌를 자극하는 윈도우즈 시스템 프로그래밍' 카테고리의 다른 글
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 10장 컴구조(3) (0) | 2025.06.08 |
|---|---|
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 9장 스케줄링 알고리즘과 우선순위 (2) | 2025.06.08 |
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 6장 - 커널 오브젝트와 오브젝트 핸들 (0) | 2025.05.20 |
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 5장 - 프로세스의 생성과 소멸 (0) | 2025.05.20 |
| [뇌를 자극하는 윈도우즈 시스템 프로그래밍] 4장 - 컴구조(2) (0) | 2025.05.17 |