728x90
IPC의 특성
- 메일 슬롯
-> 방향성 : 단방향, 브로드캐스팅
-> 통신범위 : 제한 없음
- 이름없는 파이프
-> 방향성 : 단방향
-> 통신범위 : 부모-자식 프로세스 간
- 이름있는 파이프
-> 방향성 : 양방향
-> 통신범위 : 제한 없음
이름없는 파이프
- 파이프의 핸들 값을 통해 읽기, 쓰기에 접근
- 부모-자식 프로세스 간 통신이 가능
-> 부모 프로세스에서 생성한 파이프의 핸들 값이 자식 프로세스로 상속이 가능하기 때문
- 파이프 생성 : CreatePipe()
BOOL CreatePipe(
PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize
);
HANDLE hReadPipe, hWritePipe;
CreatePipe(
&hReadPipe, // 파이프의 출구(읽기)에 접근할 수 있는 핸들
&hWirtePipe, // 파이프의 입구(쓰기)에 접근할 수 있는 핸들
NULL, 0);
- 읽기, 쓰기 : WriteFile(), ReadFile()
ReadFile(
hReadPipe,
recvString,
byteWirtten,
&bytesRead,
NULL
);
WriteFile(
hWritePipe,
sendString,
lstrlen(sendString)*sizeof(TCHAR),
&byteWritten,
NULL
);
이름 있는 파이프
- server 측(파이프 생성하는 쪽)
-> CreateNamedPipe() : 파이프 생성
-> ConnectNamedPipe() : 파이프를 연결 대기 상태로 전환
// namedpipe_server.cpp
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#define BUF_SIZE 1024
int CommToClinet(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, // 최대 인스턴스 갯수 = 보유 가능 파이프 갯수
// createpipe 처음 호출할때만 설정이 됨
// 다음에 호출할 때도 유지하는 것이 좋음
BUF_SIZE, // 출력 버퍼 사이즈
BUF_SIZE, // 입력 버퍼 사이즈
20000, // 클라이언트 타임-아웃
// 연결 요청을 기다리는 시간(ms)
NULL // 보안 설정
);
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(_T("Create pipe failed"));
return -1;
}
BOOL isSuccess = 0;
isSuccess = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (isSuccess)
CommToClinet(hPipe);
else
CloseHandle(hPipe);
} // 여러 클라이언트가 순차적으로 접속하기 위해 무한 루프
return 1;
}
int CommToClinet(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)
{
_tprintf(_T("Pipe read message error! \n"));
return -1;
}
FILE* filePtr = _tfopen(fileName, _T("r")); // 수신된 데이터의 파일을 열기
if (filePtr == NULL)
{
_tprintf(_T("File open error!!\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)
{
_tprintf(_T("Pipe write message error!!!\n"));
break;
}
} // open 한 파일의 데이터를 읽어와서 클라이언트에 데이터 송신
FlushFileBuffers(hPipe); // 버퍼를 비워줌
DisconnectNamedPipe(hPipe); // 파이프를 소멸
CloseHandle(hPipe);
return 1;
}
- client 측(파이프에 접속하려는 쪽)
-> CreateFile() : 호출에 의한 파이프 연결(오픈)
// namedpipe_client.cpp
#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; // 연결이 되었다면 while을 빠져나옴
if (GetLastError() != ERROR_PIPE_BUSY)
{
_tprintf(_T("Could not open pipe\n"));
return 0;
} // 연결 요청 시간이 지난 것을 확인
if (!WaitNamedPipe(pipeName, 20000))
{
_tprintf(_T("Could not open pipe\n"));
return 0;
} // 설정한 연결 요청 시간동안 대기
// 시간 설정을 안하면 서버에서 설정한 시간만큼 대기
} // 서버에 연결을 요청하기 위한 무한 루프
DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; // 읽는 모드를 메시지 기반 모드 설정
BOOL isSuccess = SetNamedPipeHandleState(
hPipe, // 파이프 핸들
&pipeMode, // 변경할 파이프 모드
NULL,
NULL
); // 위에 설정한 모드대로 변경
if (!isSuccess)
{
_tprintf(_T("SetNamedPipeHandleState failed!\n"));
return 0;
}
LPTSTR fileName = _T("news.txt");
DWORD bytesWritten = 0;
isSuccess = WriteFile(
hPipe, // 파이프 핸들
fileName, // 전송할 메시지
(_tcslen(fileName) + 1) * sizeof(TCHAR), // 메시지 길이
&bytesWritten, // 전송된 바이트 수
NULL
); // 데이터 송신
if (!isSuccess)
{
_tprintf(_T("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;
}
- 서버 프로젝트 폴더 안에 news.txt가 있어야 함
- client 에서 보낸 파일명을 받아서 그 파일명의 파일을 열어 내용을 다시 클라이언트에 전송
728x90
'Programming > System Programming' 카테고리의 다른 글
윈도우즈 시스템 프로그래밍 - 9. 스케줄링 알고리즘과 우선순위(1) (0) | 2020.07.20 |
---|---|
윈도우즈 시스템 프로그래밍 - 8. 프로세스간 통신2(3) (0) | 2020.07.19 |
윈도우즈 시스템 프로그래밍 - 8. 프로세스간 통신2(1) (0) | 2020.07.19 |
윈도우즈 시스템 프로그래밍 - 7. 프로세스간 통신(2) (0) | 2020.07.19 |
윈도우즈 시스템 프로그래밍 - 7. 프로세스간 통신(1) (0) | 2020.07.19 |