190704-3
파이프
교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.
IPC - 파이프
-
단방향 파이프
-
양방향 파이프
-
이름있는 파이프 : 이름으로 언제든지 커널오브젝트 핸들을 얻을 수 있다.
-
이름없는 파이프
지금 실습은 양방향, 이름있는 파이프
Client : 요청
Server : 응답
우리 예제는 이름있는 양방향 파이프 이면서 서버와 클라이언트 개념이 존재한다. (멀티 파이프)
파이프 서버가 mp라고 알려주면 클라이언트가 파이프를 만들어 달라고 요청한다. -> 파이프가 만들어지고 파이프의 한쪽을 핸들로 클라이언트가 갖는다. 서버쪽도 파이프의 한쪽의 핸들은 서버가 갖는다. 라고 생각하자. -> 클라이언트에서 먼저 발송 -> 서버가 받는다. -> 다시 클라이언트에 전송
다시. 클라이언트2번이 mp라는 이름으로 통신한다면 또 독립적인 파이프가 만들어진다. 한쪽 핸들은 클라이언트2번 나머지 쪽 핸들은 서버가.
서버
//윈도우 API 정복 김상형저 소스
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("MultiPipe1");
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
, LPSTR lpszCmdParam, int nCmdShow)
{
기본 코드 생략
}
// 차일드의 요청을 처리한다.
DWORD WINAPI PipeThread(LPVOID temp)
{
HANDLE hPipe = (HANDLE)temp;
TCHAR szInput[255],/*애플리케이션 버퍼*/ szOutput[255];
DWORD dwRead, dwWritten;
BOOL bSuc;
// 요청을 받고 연산을 한 후 응답을 보낸다.
for (;;) { //*주고받기
bSuc = ReadFile(hPipe, szInput/*이 버퍼에 받는다.*/, 255, &dwRead, NULL);
//* ReadFile : 데이터를 읽는 함수. 또한 블록함수다. 읽을 때 까지 블록
if ((bSuc == FALSE) || (dwRead == 0)) { // 클라이언트가 통신을 종료했을 경우
break;
}
if (lstrcmp(szInput, "one") == 0) lstrcpy(szOutput, "하나");
if (lstrcmp(szInput, "two") == 0) lstrcpy(szOutput, "둘");
if (lstrcmp(szInput, "three") == 0) lstrcpy(szOutput, "셋");
if (lstrcmp(szInput, "four") == 0) lstrcpy(szOutput, "넷");
if (lstrcmp(szInput, "five") == 0) lstrcpy(szOutput, "다섯");
bSuc = WriteFile(hPipe, szOutput, lstrlen(szOutput) + 1, &dwWritten, NULL);
// * WriteFile : 이 또한 블럭함수. 모두 데이터를 전송할 때까지 반환하지 않는다. // 클라이언트가 안받아도 파이프에 박어놓기만 해도되서 ReadFile보다 대부분 빠르다.
if ((bSuc == FALSE) || (dwWritten == 0)) { // 클라이언트가 통신을 종료했을 경우
break;
}
}
// 파이프 해제
FlushFileBuffers(hPipe); // 파이프의 출력 버퍼가 빌 때까지 대기 * 버퍼에있는 데이터를 밀어서 없앤다(또는받는다)
DisconnectNamedPipe(hPipe); // 파이프 연결이 끊기고 클라이언트가 에러를 인식한다.
CloseHandle(hPipe); // 파이프 인스턴스를 닫는다.
return 0;
}
// 클라이언트 하나당 하나씩의 스레드를 만든다.
DWORD WINAPI MainThread(LPVOID temp)
{
HANDLE hPipe;
DWORD ThreadID;
BOOL bCon;
for (;;) {
// 파이프 생성
hPipe = CreateNamedPipe( //*이름있는 파이프를 생성한다.
"\\\\.\\pipe\\MultiPipe", //파이프 이름 * 이름을 알아야 접속요청을 할 수 있다. 접속요청을 받아들였을 때 하고하하는 동작을 수행할 수 있다.
// "\\\\"는 ms가 만들어놓은 프로토콜 상이라는 뜻이다.
// "." 은 현재 컴퓨터
// "MultiPipe" : 파이프의 이름이다.
PIPE_ACCESS_DUPLEX, // Read, Write 모두 * 양방향 가능한 파이프로 생성
PIPE_TYPE_BYTE, //바이트 단위 입출력 or PIPE_TYPE_MESSAGE(파일의 바이너리, 텍스트 모드와 같다)
3, // 최대 인스턴스 3개 *파이프가 3개 인스턴스를 생성할 수 있다.
4096, //출력버퍼 크기(지정할뿐 시스템이 크기 설정)
4096, //입력버퍼 크기(0 디폴트 크기)
20000, //WaitNamedPipe함수의 만료 시간(밀리세컨드 단위)을 서버에서 시장한다. 클라이언트는 NMPWAIT_USE_DEFAULT_WAIT로 타임아웃을 지정한다.
NULL //보안속성
);// 이미 3개 만들어져있을 경우 -1을 반환하여 효력이 없다.
// 차일드 대기. 접속되면 차일드 요청 처리 스레드 생성
bCon = ConnectNamedPipe(hPipe, NULL); //* 대기함수 : 호출시 클라이언트가 접속하는지 대기한다. (블락상태)
if ((bCon == FALSE) && (GetLastError() == ERROR_PIPE_CONNECTED))
bCon = TRUE;
if (bCon == TRUE) { // TRUE면 잘 접속한 것이다.
CloseHandle(CreateThread(NULL, 0, PipeThread, (LPVOID)hPipe, 0, &ThreadID));//클라언트가 접속했다면 파이프쓰레드를 하나 생성한다.
}
else {
CloseHandle(hPipe);
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
DWORD ThreadID;
TCHAR* Mes = "클라이언트로부터의 접속을 대기중이며 요청을 처리합니다";
switch (iMessage) {
case WM_CREATE:
CloseHandle(CreateThread(NULL, 0, MainThread, NULL, 0, &ThreadID));
//* MainThread 라는 함수를 실행하는 쓰레드를 생성한다.
//* 파이프 클라이언트가 파이프의 이름으로 접속하는지 대기하기 위해서 만든 쓰레드
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 50, 50, Mes, lstrlen(Mes));
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
클라이언트
#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass=TEXT("MultiPipe2");
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
,LPSTR lpszCmdParam,int nCmdShow)
{
기본 코드 생략
}
TCHAR Mes[255]="파이프 서버를 실행시켜 주십시오";
#define random(i) (rand() % i) // i만큼 숫자가 발생한다.
// 서버로 요청을 보내 결과를 받아온다.
DWORD WINAPI MainThread(LPVOID temp)
{
HANDLE hPipe;
TCHAR szInput[255], szOutput[255];
DWORD dwRead, dwWritten;
TCHAR arInput[5][10]={"one","two","three","four","five"};
BOOL bSuc;
// 서버가 파이프를 생성할 때까지 무한 대기한다.
for (;;) {
if (WaitNamedPipe("\\\\.\\pipe\\MultiPipe",NMPWAIT_WAIT_FOREVER)==TRUE) {
//WaitNamedPipe : 인스턴스가 남지 않는다면 Wait하는 함수(우리가 정해준 개수는 최대 3개)
hPipe=CreateFile("\\\\.\\pipe\\MultiPipe",GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING/*존재할 때만 접속요청*/,0,NULL); // 파이프를 연결하는 함수. 만들어놓은 파이프를 연결한다.
if (hPipe!=INVALID_HANDLE_VALUE)
break;
}
}
for (;;) {
// one~five중 하나를 난수로 선택한다.
lstrcpy(szInput,arInput[random(5)]);
// 요청을 보낸 후 응답을 받는다.
bSuc=WriteFile(hPipe,szInput,lstrlen(szInput)+1,&dwWritten,NULL); // * 요청을 보낸다
if ((bSuc==FALSE) || (dwWritten==0))
break;
ReadFile(hPipe,szOutput,255,&dwRead,NULL); // 응답을 읽어온다
// 응답을 화면으로 출력한다.
wsprintf(Mes,"%s=%s",szInput,szOutput);
InvalidateRect(hWndMain,NULL,TRUE);
UpdateWindow(hWndMain);
Sleep(500);
}
// 서버가 먼저 종료된 경우
lstrcpy(Mes,"서버가 종료되었습니다.");
InvalidateRect(hWndMain,NULL,TRUE);
// 파이프를 해제하고 결과를 메인 윈도우에 출력한다.
CloseHandle(hPipe);
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
DWORD ThreadID;
switch (iMessage) {
case WM_CREATE:
hWndMain=hWnd;
srand(GetTickCount()); // 랜드함수 씨드값 초기화한다.
CloseHandle(CreateThread(NULL,0,MainThread,NULL,0,&ThreadID)); // 쓰레드 생성한다.
return 0;
case WM_PAINT:
hdc=BeginPaint(hWnd, &ps);
TextOut(hdc,50,50,Mes,lstrlen(Mes)); // 문자열 출력한다.
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
'System Programming' 카테고리의 다른 글
[system programming] HeapAlloc, HeapDestroy, HeapCreate (0) | 2019.07.08 |
---|---|
[system programming] 메일슬롯(Mailslot), FileMapping, UnmapViewOfFile (0) | 2019.07.07 |
[system programming] CHECKER3.C -- Mouse Hit-Test Demo Program No. 3 (0) | 2019.07.05 |
[system programming] IPC 메세지, COPYDATASTRUCT (0) | 2019.07.05 |
[system programming] 플래그, 자원 관리 클래스 (0) | 2019.07.05 |