Programming Language/C, C++

네임드 파이프 예제

MOLOKINI 2016. 4. 30. 13:13

Pipe는 두 프로세스를 잇는 통로입니다.

 

예를 들어, 두 개의 수조가 있고 그 사이를 파이프로 관통해 연결한다고 합시다.

그럼 하나의 수조에 물을 채운다면 그 물이 파이프를 따라 흘러 또 다른 수조로 들어가게 되겠죠?

 

이처럼, 프로세스 간에도 Pipe를 연결한다면 원하는 정보를 다른 프로세스로 전달할 수 있습니다.

 

Pipe에는 Named PipeAnonymous Pipe, 두 종류가 존재하는데요.

 

간략하게 설명하면

Anonymous Pipe : 이름없는 파이프, 한쪽 방향으로만 데이터 전송, 부모 => 자식 프로세스

Named Pipe : 이름있는 파이프, 양쪽 방향으로 데이터 전송, 프로세스 <=> 프로세스

 

아래는 Named Pipe를 이용해 프로세스간 통신을 하는 코드입니다.

- 출처 : http://ezbeat.tistory.com/300

 

서버 코드

 

#include <stdio.h>

#include <Windows.h>

#include <tchar.h>

 

#define PIPE_NAME "\\\\.\\pipe\\test_pipe"       // 파이프 이름 설정, 이 파이프로 통신을 할 것임

 

int ConnectClient(HANDLE hNamePipe)

{

TCHAR recvMessage[100];

TCHAR sendMessage[100];

DWORD recvSize;

DWORD sendSize;

 

while(1)

{

_tprintf(_T("Input Send Message : "));

_tscanf(_T("%s"),sendMessage);

 

//sendSize -> NULL 포함한 바이트 수

if(!(WriteFile(

hNamePipe,

sendMessage,

(_tcslen(sendMessage)+1)*sizeof(TCHAR),

&sendSize,

NULL

)))          // 

{

_tprintf(_T("WriteFile error! \n"));

return -1;

}

FlushFileBuffers(hNamePipe);

 

//recvSize -> NULL 포함한 바이트 수

if(!(ReadFile(

hNamePipe,

recvMessage,

sizeof(recvMessage)-sizeof(TCHAR)*1,

&recvSize,

NULL

)))

{

printf("ReadFile error! \n");

return -1;

}

recvMessage[recvSize/sizeof(TCHAR)-1] = _T('\x00');

 

_tprintf(_T("Recv Message : %s \n"),recvMessage);

}

 

return 1;

}

 

int _tmain(int argc,TCHAR* argv[])

{

HANDLE hNamePipe;

TCHAR pipe_name[] = _T(PIPE_NAME);     // #define 한 파이프 이름

 

_tprintf(_T("==== Server ==== \n"));

//NamedPipe 생성

hNamePipe = CreateNamedPipe(

pipe_name,

PIPE_ACCESS_DUPLEX,

PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,

PIPE_UNLIMITED_INSTANCES,

0,

0,

20000,       // 대기 Timeout 시간

NULL

);

if(hNamePipe == INVALID_HANDLE_VALUE)

{

printf("CreateNamePipe error! \n");

return -1;

}

 

while(1)

{

//생성한 Named Pipe의 핸들을 누군가 얻어갈 때까지 대기..

if(!(ConnectNamedPipe(hNamePipe,NULL)))

{

CloseHandle(hNamePipe);

return -1;

}

else

{

if(ConnectClient(hNamePipe) == -1)

break;

}

}

 

DisconnectNamedPipe(hNamePipe);

CloseHandle(hNamePipe);

_tprintf(_T("Program exit! \n"));

return 1;

}

 

 

클라이언트 코드

 

#include <stdio.h>

#include <stdlib.h>

#include <Windows.h>

#include <tchar.h>

 

#define PIPE_NAME "\\\\.\\pipe\\test_pipe"     // 서버의 파이프 이름과 동일한 파이프 사용

 

int ConnectServer(HANDLE hNamePipe)

{

TCHAR recvMessage[100];

TCHAR sendMessage[100];

DWORD recvSize;

DWORD sendSize;

 

while(1)

{

if(!(ReadFile(

hNamePipe,

recvMessage,

sizeof(recvMessage)-sizeof(TCHAR)*1,

&recvSize,

NULL

)))

{

_tprintf(_T("ReadFile error! \n"));

return -1;

}

 

recvMessage[recvSize/sizeof(TCHAR)-1] = _T('\x00');

_tprintf(_T("Recv Message : %s \n"),recvMessage);

 

_tprintf(_T("Input Send Message : "));

_tscanf(_T("%s"),sendMessage);

 

if(!(WriteFile(

hNamePipe,

sendMessage,

(_tcslen(sendMessage)+1)*sizeof(TCHAR),

&sendSize,

NULL

)))

{

_tprintf(_T("WriteFile error! \n"));

return -1;

}

FlushFileBuffers(hNamePipe);

}

 

return 1;

}

 

int _tmain(int argc, TCHAR* argv[])

{

TCHAR pipe_name[] = _T(PIPE_NAME);

HANDLE hNamePipe;

 

_tprintf(_T("==== Client ==== \n"));

while(1)

{

                // 파이프 이름으로 핸들 열기

hNamePipe = CreateFile(pipe_name,GENERIC_READ | GENERIC_WRITE, 0,NULL,OPEN_EXISTING,0,NULL);

if(hNamePipe == INVALID_HANDLE_VALUE)

{

_tprintf(_T("CreateFile error! \n"));

return -1;

}

 

DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;

if(!(SetNamedPipeHandleState(hNamePipe,&pipeMode,NULL,NULL)))

{

_tprintf(_T("SetNamedPipeHandleState error! \n"));

CloseHandle(hNamePipe);

return -1;

}

else

{

if(ConnectServer(hNamePipe) == -1)

break;

}

}

CloseHandle(hNamePipe);

 

return 0;

}