시스템 프로그래밍

8-3. 파이프 방식의 IPC

CalebHong 2022. 5. 20. 12:31

IPC별 특성

  메일슬롯 이름없는 파이프 이름있는 파이프
방향성 단방향, 브로드캐스팅 단방향 양방향
통신범위 제한 없음 부모 자식 프로세스 제한 없음

 

이름없는 파이프

 - PC 이름이 없음을 의미

 - 부모 프로세스가 만들 파이프를 통해 서로 데이터를 송/수신할 수 있음(위험 요소로 작용)

 

이름있는 프로그래밍 모델

 1) CreateNamedPipe 함수를 통해 파이프를 생성하지만 바로 외부와 통신은 불가

 2) ConnectNamedPipe 함수로 연결 대기 상태로 전환

 3) Client의 CreateFile 함수 호출에 의해 파이프에 연결하여 데이터를 송/수신

 

예제) NamedPipe_Server.cpp

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <windows.h>

#define BUF_SIZE 1024

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)
		{
			_tprintf(_T("CreatePipe Failed"));
			return -1;
		}

		BOOL isSuccess;
		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;
	LPDWORD fileNameSize;

	isSuccess = ReadFile(
		hPipe,		// 파이프 핸들
		fileName,	// read 버퍼 지정
		MAX_PATH * sizeof(TCHAR), // read 버퍼 사이즈
		fileNameSize, // 수신한 데이터 크기
		NULL
	);

	if (!isSuccess || fileNameSize == 0)
	{
		_tprintf(_T("Pipe read message error! \n"));
		return -1;
	}

	FILE* filePtr = _tfopen(fileName, _T("r"));

	if (filePtr == NULL)
	{
		_tprintf(_T("File open fault! \n"));
		return -1;
	}

	DWORD bytesWritten = 0;
	DWORD bytesRead = 0;

	while (!feof(filePtr))
	{
		bytesRead = fread(dataBuf, 1, BUF_SIZE, filePtr);

		WriteFile(
			hPipe,			// 파이프 핸들
			dataBuf,		// 전송할 데잍 버퍼
			bytesRead,		// 전송할 데이터 크기
			&bytesWritten,	// 전송된 데이터 크기
			NULL
		);

		if (bytesRead != bytesWritten)
		{
			_tprintf(_T("Pip write message error! \n"));
			break;
		}
	}
	
    // 버퍼를 비우는 함수
	FlushFileBuffers(hPipe);
    // 파이프를 통한 통신 연결을 해제하는 함수
	DisconnectNamedPipe(hPipe);
	CloseHandle(hPipe);
	return 1;
}

 - 클라이언트에서 WaitNamedPipe 함수를 사용할 때 시간을 입력하지 않으면 서버에서 파이프 생성시 지정한 시간 동안 기다리게 됨