Anonymouse Pipe, Named Pipe
Windows에서 파이프는 두가지가 존재하는데 Anonymouse Pipe와 Named Pipe가 있습니다. Anonymouse Pipe는 부모 자식 관계 프로세스(혹은 자식, 자식)들 사이에서 통신하는 경우에 유용합니다. Named Pipe는 주소 정보가 존재하는 파이프인데, 주소가 있다는 것은 서로 관계가 없는 프로세스들 사이에서도 주소 정보를 공유함으로써 데이터를 주고 받을 수 있다는 것입니다.
앞서 메일슬롯과의 차이를 보자면 Named Pipe는 양뱡향 통신이 가능하다는 것이고 MailSlot은 브로드케스트 방식(단방향)의 데이터 전송이 가능합니다.
AnonymousePipe
AnonymousePipe.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <stdio.h> #include <tchar.h> #include <Windows.h> int main(void) { HANDLE hReadPipe, hWritePipe; TCHAR sendString[] = _T("Anonymouse Pipe"); TCHAR recvString[100]; DWORD bytesWritten; DWORD bytesRead; CreatePipe(&hReadPipe, &hWritePipe, NULL, 0); WriteFile(hWritePipe, sendString, lstrlen(sendString)*sizeof(TCHAR), &bytesWritten, NULL); _tprintf(_T("string Send: %s \n"), sendString); ReadFile(hReadPipe, recvString, bytesWritten, &bytesRead, NULL); recvString[bytesRead / sizeof(TCHAR)] = 0; _tprintf(_T("String Recv: %s \n"), recvString); CloseHandle(hReadPipe); CloseHandle(hWritePipe); return 0; } | cs |
NamedPipe
NamedPipe는 양뱡향 통신이 핵심이다. 예를 들어 서버와 클라이언트가 있다고 하자. 서버에서는 CreateNamedPipe()를 이용해 Pipe를 생성하고 ConnectNamedPipe()를 이용해 연결이 되도록 대기를 한다. 그러면 클라이언트에서 서버로 연결을 해야하는데 이때 CreateFile()을 사용한다.
NamedPipe_Server.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #include <stdio.h> #include <tchar.h> #include <Windows.h> #define BUF_SIZE 2014 int CommToClient(HANDLE); int _tmain(int argc, TCHAR* argv[]) { LPTSTR pipeName = _T("\\\\.\\pipe\\simple_pipe"); HANDLE hPipe; while (1) { hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUF_SIZE, BUF_SIZE, 20000, NULL); if (hPipe == INVALID_HANDLE_VALUE) { printf("CreatePipe Failed\n"); return -1; } BOOL isSuccess = 0; isSuccess = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (isSuccess) { CommToClient(hPipe); } else { CloseHandle(hPipe); } return 1; } } int CommToClient(HANDLE hPipe) { TCHAR fileName[MAX_PATH]; TCHAR dataBuf[BUF_SIZE]; BOOL isSuccess; DWORD fileNameSize; isSuccess = ReadFile(hPipe, fileName, MAX_PATH*sizeof(TCHAR), &fileNameSize, NULL); if (!isSuccess || fileNameSize == 0) { printf("Pipe read message error! \n"); return -1; } FILE* filePtr = _wfopen(fileName, _T("r, ccs=UNICODE")); if (filePtr == NULL) { printf("%d\n", GetLastError()); _tprintf(_T("File open fault! \n")); return -1; } DWORD bytesWritten = 0; DWORD bytesRead = 0; while (!feof(filePtr)) { bytesRead = (fread(dataBuf, sizeof(TCHAR), BUF_SIZE, filePtr))*sizeof(TCHAR); WriteFile(hPipe, dataBuf, bytesRead, &bytesWritten, NULL); if (bytesRead != bytesWritten) { printf("Pipe write message error! \n"); break; } } FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); CloseHandle(hPipe); return 1; } | cs |
15라인을 보면 CreateNamedPipe()에 3번째 인자를 보면 OR 연산을 하는 것을 볼 수 있다. 이 3번째 인자는 데이터 전송타입, 데이터 수신 타입, 블로킹 모드를 설정한다.
단순히 문자열을 주고 받는 것이 목적이라면 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIP_WAIT 를 사용하면 되고,
바이너리 데이터를 주고 받는 것이 목적이라면 PUPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIP_WAIT 로 하면 된다.
NamedPipe_Cilent.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | #include <stdio.h> #include <tchar.h> #include <Windows.h> #define BUF_SIZE 1024 int _tmain(int argc, TCHAR* argv[]) { HANDLE hPipe; TCHAR readDataBuf[BUF_SIZE + 1]; LPTSTR pipeName = _T("\\\\.\\pipe\\simple_pipe"); while (1) { hPipe = CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hPipe != INVALID_HANDLE_VALUE) { break; } if (GetLastError() != ERROR_PIPE_BUSY) { printf("Could not open pipe \n"); return 0; } if (!WaitNamedPipe(pipeName, 20000)) { printf("Could not open pipe \n"); return 0; } } DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; BOOL isSuccess = SetNamedPipeHandleState(hPipe, &pipeMode, NULL, NULL); if (!isSuccess) { printf("SetNamedPipeHAndleSate failed\n"); return 0; } LPCTSTR fileName = _T("C:\\Users\\k3y6reak\\Documents\\Visual Studio 2013\\Projects\\NamedPipe_Client\\Debug\\message.txt"); DWORD bytesWritten = 0; isSuccess = WriteFile(hPipe, fileName, (lstrlen(fileName) + 1) * sizeof(TCHAR), &bytesWritten, NULL); if (!isSuccess) { printf("WriteFile failed \n"); return 0; } DWORD bytesRead = 0; while (1) { isSuccess = ReadFile(hPipe, readDataBuf, BUF_SIZE*sizeof(TCHAR), &bytesRead, NULL); if (!isSuccess && GetLastError() != ERROR_MORE_DATA) { break; } readDataBuf[bytesRead/sizeof(TCHAR)] = 0; _tprintf(_T("%s \n"), readDataBuf); } CloseHandle(hPipe); return 0; } | cs |
실행결과는 아래와 같다.
책의 예제에는 단순히 file명만 가지고 실행하는데 정상적으로 작동하지 않는다. Debugging을 해서 보면 분명이 파일명은 넘어오는데 File Pointer값이 NULL로 되어 읽어드리지를 못한다.
그래서 절대경로를 넣어주면 잘 실행된다.
'High Level Technique > Window System' 카테고리의 다른 글
우선순위 알고리즘 (0) | 2017.01.02 |
---|---|
프로세스 환경변수 (0) | 2017.01.02 |
Pseudo Handle, Handle Duplicate (0) | 2016.12.28 |
핸들 테이블과 오브젝트 핸들의 상속 (0) | 2016.12.28 |
커널 오브젝트 상태 (Kernel Object State) (0) | 2016.12.27 |