* 해당 글은 윤성우의 뇌를 자극하는 윈도우즈 시스템 프로그래밍 도서를 읽고 정리한 글입니다
https://product.kyobobook.co.kr/detail/S000001223395
* 핸들 테이블
핸들 정보를 저장하고 있는 테이블로서 프로세스별로 독립적이다
* Usage Count
커널 오브젝트를 참조하는 프로세스 개수만큼 커널 오브젝트의 Usage Count 증가
* 프로세스가 핸들을 얻게 되었다는 의미
핸들 테이블에 해당 핸들에 대한 정보가 갱신(추가)되었음을 의미하는 것이다
* GetCurrentProcess 함수
현재 실행중인 프로세스 자신의 핸들을 얻을 수 있다
[그런데] 이 함수를 통해 얻은 핸들을 가리켜 가짜 핸들(Pseudo 핸들)이라고 함
현재 실행중인 프로세스를 참조하기 위한 용도로 정의해 놓은, 약속된 상수가 반환되는 것이기 때문임
[따라서] 자식 프로세스에 상속되지 않는다
현재 실행중인 프로세스에서 진짜 핸들(Real Handle)을 얻기 위해서는 DuplicateHandle 함수를 이용하면 됨
* DuplicateHandle 함수
핸들 복사, 진짜 핸들(Real Handle)
BOOL DuplicateHandle(
[in] HANDLE hSourceProcessHandle,
[in] HANDLE hSourceHandle,
[in] HANDLE hTargetProcessHandle,
[out] LPHANDLE lpTargetHandle,
[in] DWORD dwDesiredAccess,
[in] BOOL bInheritHandle,
[in] DWORD dwOptions
);
hSourceProcessHandle
: 복제할 핸들을 소유하고 있는 프로세스에 대한 핸들
hSourceHandle
: 복제할 핸들을 지정
hTargetProcessHandle
: 복제할 핸들을 소유할 프로세스를 지정
lpTargetHandle
: 복제될 핸들값을 저장할 변수의 주소를 지정
dwDesiredAccess
: 복제된 핸들의 접근 권한
bInheritHandle
: 복제된 핸들의 상속 여부 지정
TRUE 전달 시 새로운 자식 프로세스로 상속되고, FALSE 전달 시 상속되지 않는다
dwOptions
: 비트 단위 OR 연산자를 통해 동시 전달 가능
없음과 아래의 옵션 선택 가능
- DUPLICATE_CLOSE_SOURCE
- DUPLICATE_SAME_ACCESS
https://learn.microsoft.com/ko-kr/windows/win32/api/handleapi/nf-handleapi-duplicatehandle
* 메일슬롯은
두 프로세스가 서로 메시지를 주고 받을 수 있기 위해서는 두 개의 메일슬롯을 생성해야 하는 번거로움이 있다
이러한 번거로움을 덜기 위해 한 개만 생성하여 메시지를 주고 받고자 할 때, 사용 가능한 IPC 기법이 있는데
이름 없는 파이프(Anonymous Pipe), 이름 있는 파이프(Named Pipe)이다
ㄴ 메일슬롯
단방향 통신(서로 메시지를 주고 받기 위해 두 개를 생성해야 한다)
메일슬롯에 할당된 주소를 기반으로 통신하기 때문에 관계없는 프로세스들 사이에서도 통신 가능
ㄴ 이름없는 파이프
단방향 통신(서로 메시지를 주고 받기 위해 두 개를 생성할 필요 없다)
파이프를 통해서 생성된 핸들을 기반으로 통신하기 때문에 프로세스들 사이에서는 관계가 있어야 함
ㄴ 이름있는 파이프
양방향 통신
이름을 기반으로 통신하기 때문에 관계없는 프로세스들 사이에서도 통신이 가능하다
* CreatePipe 함수
이름없는 파이프 생성
한쪽 끝에서는 데이터 들어가고
다른 한쪽 끝에서는 들어간 데이터가 흘러나오는 것이 파이프의 원리인 것처럼
두 개의 끝을 가지고 있어야 한다
BOOL CreatePipe(
[out] PHANDLE hReadPipe,
[out] PHANDLE hWritePipe,
[in, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
[in] DWORD nSize
);
hReadPipe
: 데이터를 읽기 위한 파이프의 끝
hWritePipe
: 데이터를 쓰기 위한 파이프의 끝
lpPipeAttributes
: 보안 관련 정보
nSize
: 파이프의 버퍼 사이즈를 지정하는 용도
https://learn.microsoft.com/ko-kr/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
* CreateNamedPipe 함수
이름있는 파이프 생성
ConnectNamedPipe 함수 호출하여 파이프 연결
Server-Client 구조
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
);
lpName
: 파이프 이름을 지정
dwOpenMode
: 파일을 개방할 때 모드를 지정
dwPipeMode
: 파이프 모드 지정
nMaxInstances
: 생성할 수 있는 파이프의 최대 개수 지정
nOutBufferSize
: 이름있는 파이프의 출력 버퍼 사이즈를 지정
nInBufferSize
: 이름있는 파이프의 입력 버퍼 사이즈를 지정
nDefaultTimeOut
: WaitNamedPipe 함수에 적용할 기본 만료 시간을 밀리세컨드 단위로 지정
lpSecurityAttributes
: 보안 속성을 지정
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-createnamedpipea
* ConnectNamedPipe 함수
이름있는 파이프 서버 프로세스가 클라이언트 프로세스가 연결되기를 기다리도록 한다
즉, 이름있는 파이프 서버의 대기 상태
BOOL ConnectNamedPipe(
[in] HANDLE hNamedPipe,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
https://learn.microsoft.com/ko-kr/windows/win32/api/namedpipeapi/nf-namedpipeapi-connectnamedpipe
hNamedPipe
: 파이프의 핸들을 전달
lpOverlapped
: 중첩 I/O를 위한 전달인자
BOOL isSuccess = ReadFile(
hPipe, // 서버 파이프와 연결된 핸들
readDataBuf, // 데이터 수신할 버퍼
BUF_SIZE * sizeof(TCHAR), // 버퍼 사이즈
&bytesRead, // 수신한 바이트 수
NULL);
① ReadFile는 읽어온 데이터의 크기를 바이트 단위로 반환한다
즉, bytesRead는 문자 수가 아닌 바이트 수를 나타낸다
② TCHAR는 유니코드 설정 여부에 따라 크기가 다르다
ANSI 환경 : 1바이트 (sizeof(TCHAR) == 1)
유니코드 환경 : 2바이트 (sizeof(TCHAR) == 2)
③ 문자열 끝에 올바른 널 종료(\0)를 추가하기 위해서는 문자 단위 인덱스를 계산해야 한다
문자 단위 인덱스를 계산하려면, bytesRead를 sizeof(TCHAR)로 나눠야 한다
▶ 왜 나눠야 하는가?
결국, 문자 크기(TCHAR의 크기)가 달라지면 배열 인덱스의 위치도 달라지기 때문
1바이트: c[0]과 c[1] 사이의 간격 = 1칸
2바이트: c[0]과 c[1] 사이의 간격 = 2칸
readDataBuf[bytesRead / sizeof(TCHAR)] = 0; // 문자 단위로 계산하여 널 종료 추가
// 파일 크기 계산
fseek(filePtr, 0, SEEK_END);
fileSize = ftell(filePtr);
rewind(filePtr); // 파일 포인터를 다시 시작 위치로 이동
* WaitNamedPipe 함수
내가 설정한 time-out이나 디폴트로 정의된 시간(CreateNamedPipe 함수의 7번째 인자를 통해 전달)만큼
이름있는 파이프 서버에 연결할 수 있을 때까지 기다린다
BOOL WaitNamedPipeA(
[in] LPCSTR lpNamedPipeName,
[in] DWORD nTimeOut
);
lpNamedPipeName
: 파이프 이름
nTimeOut
: 타임-아웃 시간 설정
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-waitnamedpipea
* SetNamedPipeHandleState 함수
파이프 속성 변경
BOOL SetNamedPipeHandleState(
[in] HANDLE hNamedPipe,
[in, optional] LPDWORD lpMode,
[in, optional] LPDWORD lpMaxCollectionCount,
[in, optional] LPDWORD lpCollectDataTimeout
);
hNamedPipe
: 파이프와의 연결 속성을 변경시키기 위한 핸들 지정
lpMode
: 읽기 모드와 리턴방식에 대한 값을 비트 OR 연산으로 전달
lpMaxCollectionCount
: 서버로 데이터를 보내기에 앞서서 버퍼링할 수 있는 최대 바이트 크기를 지정하는데 사용
lpCollectDataTimeout
: 서버로 데이터를 보내기 앞서서 버퍼링을 허용하는 최대 시간을 지정하는데 사용
* 프로세스 환경변수
자식 프로세스에게 핸들 정보를 전달하기 위해서 파일을 이용했으나 이보다 더 안정적인 방법이 있다
바로 프로세스 환경 변수를 이용하는 것이다
* SetEnvironmentVariable 함수
현재 프로세스에 대해 환경변수를 설정
BOOL SetEnvironmentVariable(
[in] LPCTSTR lpName,
[in, optional] LPCTSTR lpValue
);
lpName
: key에 해당하는 값 지정
lpValue
: value에 해당하는 값 지정
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-setenvironmentvariable
* GetEnvironmentVariable 함수
호출 프로세스의 환병 블록에서 지정된 변수의 내용을 검색
DWORD GetEnvironmentVariable(
[in, optional] LPCTSTR lpName,
[out, optional] LPTSTR lpBuffer,
[in] DWORD nSize
);
lpName,
: key 값 전달
lpBuffer
: value 값을 저장하기 위한 메모리의 주소를 지정
nSize
: lpBuffer가 가리키는 메모리의 크기를 지정
https://learn.microsoft.com/ko-kr/windows/win32/api/winbase/nf-winbase-getenvironmentvariable
* CreateToolhelp32Snapshot 함수
현재 실행중인 프로세스의 사진을 찍으라는 의미
ㄴ 프로세스가 사용하는 힙, 모듈, 스레드도 가능
HANDLE CreateToolhelp32Snapshot(
[in] DWORD dwFlags,
[in] DWORD th32ProcessID
);
dwFlags
: 스냅샷에 포함할 시스템의 부분, 이 매개변수는 값이 하나 이상일 수도 있음
th32ProcessID
: 스냅샷에 포함할 프로세스의 프로세스 식별자, 이 매개변수는 현재 프로세스를 나타내는 0일 수 있음
https://learn.microsoft.com/ko-kr/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
'IT공부 > IT서적' 카테고리의 다른 글
[뇌를 자극하는 윈도우즈 시스템 프로그래밍] 9장. 스케줄링 알고리즘과 우선순위 (0) | 2025.01.28 |
---|---|
[윤성우 열혈 C프로그래밍] 디버깅 빌드, 어셈블리 코드 - Chapter11, Chapter12, Chapter13, Chapter14 (0) | 2025.01.27 |
[윤성우 열혈 C프로그래밍] 디버깅 빌드, 어셈블리 코드 - Chapter9 (0) | 2025.01.18 |
[윤성우 열혈 C프로그래밍] 디버깅 빌드, 어셈블리 코드 - Chapter8 (0) | 2025.01.16 |
[윤성우 열혈 C프로그래밍] 디버깅 빌드, 어셈블리 코드 - Chapter6, Chapter7 (0) | 2025.01.15 |