티스토리 뷰

190705-1
 
 

교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.

 

 
메일슬롯예제를 했습니다.
 
 WriteFilre, ReadFile() 등을 IO함수라고 한다. 일반적으로 IO함수의 동작을 설명한다. OS에는 일반적으로 버퍼가 있다. 또 다른 OS의 또 다른 APP이 있을 때. IO함수는 모두 동일하게 동작한다. IO함수의 일은 바로 이렇다. APP 버퍼에 쓰는 동작이다. OS레벨에서 만들어 놓은 Write Buffer에 쓰게됩니다. 즉 APP레벨의 버퍼에서 OS레벨의 버퍼에 데이터를 나르는 작업을 말합니다. 여기서 버퍼란 임시적으로 사용되는 메모리이며 속도 향상을 위해 사용되는 것은 캐쉬라고 합니다. 일반적인 조회 작업에서 특정 데이터를 많이 조회할 경우에 카운팅을 하여 캐쉬라는 변수에 저장해 놓는 것이다. 이후 조회 작업시 캐쉬를 먼저 조회하는 순서로 조회한다. 하지만 없는 경우 캐쉬를 거치게되므로 효율이 떨어질 수도 있다.
 다시. IO함수가 하는 일은 같다. OS가 만들어 놓은 버퍼는 OS레벨에 존재(혹은 API라이브러리 레벨에 존재)한다. APP버퍼는 우리가 만든 메모리에 속한다. (선언한 버퍼 변수) Write, Read 작업은 APP버퍼 <-> OS버퍼 사이를 옮기는 작업이라고 보면된다.
 IO는 하드웨어 측면에서 보면, 모든 내용은 메인 메모리(RAM)에 있어서 입출력을 한다. RAM에 가져오는 작업, 내보내는 작업을 IO라고 하는 것이다. SW측면에서도 비슷한데 IO는 파일입출력, 네트워크입출력, DB입출력 등 을 위해서 APP버퍼 <-> OS버퍼 사이에서 데이터를 오고가게하는 것이라고 보면된다.  
 
 
메일슬롯 서버코드
//윈도우 API 정복 김상형저 소스코드
 
#include <windows.h>
 
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("MailSlot1");
HANDLE hMail;
 
#pragma region MyRegion
 
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
     ,LPSTR lpszCmdParam,int nCmdShow)
{
    기본 코드 생략
}
#pragma endregion
 
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    DWORD cbMessage, cbRead,cbMesCount;
    TCHAR lpBuffer[256];
    TCHAR *Mes="왼쪽 버튼을 누르면 메시지를 받습니다";
    switch (iMessage) {
    case WM_CREATE:
        hMail=CreateMailslot(
            "\\\\.\\mailslot\\Test",//메일슬롯 이름 (*로컬 네트워크상에서 만든 것이다.)
            0, // 메일슬롯의 버퍼 크기
            0, // ReadFile()의 타임아웃 대기시간 설정(MAILSLOT_WAIT_FOREVER이면 데이터가 있을때 까지 무한 대기상태로..) (0이면 기다리지 않음)
            NULL // 보안 속성 (상속여부)
            );
        if (hMail==INVALID_HANDLE_VALUE)
            MessageBox(hWnd,"메일슬롯 만들기 실패","에러",MB_OK); //실패시 출력
        return 0;
    case WM_LBUTTONDOWN: //* L버튼시 메일함 확인
        GetMailslotInfo(hMail,NULL,&cbMessage,&cbMesCount,NULL); //* 3,4번 인수 : 아웃 파라미터 각각 메세지의 크기, 메일통안에 편지개수
        if (cbMessage == MAILSLOT_NO_MESSAGE) {
            MessageBox(hWnd,"대기중인 메시지가 없습니다","알림",MB_OK);
            return 0;
        }
 
        // 메세지가 들어와있다면 ReadFile로 내용물을 읽어온다.
        ReadFile(
            hMail, //* 메일슬롯 핸들
            lpBuffer, //* 메모리버퍼
            cbMessage, //* 읽을 크기(일반적으로 최대 사이즈)
            &cbRead, //* 실제 받은 바이트수
            NULL //* 오버랩드 구조체의 주소 (비동기 입출력에 사용된다.)
        );
        MessageBox(hWnd,lpBuffer,"읽은 메시지",MB_OK);
        return 0;
    case WM_PAINT:
        hdc=BeginPaint(hWnd, &ps);
        TextOut(hdc,50,50,Mes,lstrlen(Mes));
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        CloseHandle(hMail);
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
 
 
메일슬롯 클라이언트 코드
#include <windows.h>
 
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass=TEXT("MailSlot2");
 
#pragma region MyRegion
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
     ,LPSTR lpszCmdParam,int nCmdShow)
{
   기본 코드 생략
}
#pragma endregion
 
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    DWORD cbWritten;
    HANDLE hFile;
    static int Count=1;
    TCHAR lpMes[128];
    TCHAR *Mes="왼쪽 버튼을 누르면 메시지를 보냅니다";
    switch (iMessage)
    {
    case WM_LBUTTONDOWN:
 
        hFile=CreateFile( //* 메일 슬롯에 연결
            "\\\\.\\mailslot\\Test",//* (로컬네트워크에서) 메일슬롯 이름지정하여 연다. Test라는 이름을 가진 메일 슬롯
            GENERIC_WRITE, //* 열겠다. 쓰기형태로 열겠다.(보내기형태)
            FILE_SHARE_READ, //* 파일이 오픈이 될 때 공유모드 설정.(읽기 접근을 요청했을시 연속된 열기가 허용된다.)
            NULL,
            OPEN_EXISTING,//* 이미 존재할 때만 오픈한다.
            FILE_ATTRIBUTE_NORMAL,
            NULL
        );
        if (hFile==INVALID_HANDLE_VALUE)
        {
            MessageBox(hWnd,"메일슬롯을 열 수 없습니다","에러",MB_OK);
            return 0;
        }
        wsprintf(lpMes,"Mailslot Test Message : #%d",Count++);
        WriteFile(hFile,lpMes,lstrlen(lpMes)+1,&cbWritten,NULL); //* 메일슬롯에 메일을 보낸다. 널문자포함
        CloseHandle(hFile);
        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));
}
 
IPC 메모리맵파일
가상 메모리의 개념을 응용한 것이다. 물리메모리와 프로세스메모리를 매핑해놓고 실제 물리메모리를 사용하는 방법이다. 그런데 매핑시에 서로 다른 프로세스가 같은 물리메모리위치를 매핑하고 사용하는 것이 메모리 맵 파일이다.
동일한 메모리를 가상 메모리와 매핑 시킨다. (파일 없이 매핑을 하게되는 것이다!)
메모리 맵 파일 : 파일을 메모리 처럼 RW 해보자
//윈도우 API 정복 김상형저 소스코드.
 
#include <windows.h>
 
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass=TEXT("MemShare1");
 
#pragma region MyRegion
 
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
     ,LPSTR lpszCmdParam,int nCmdShow)
{
    기본 코드 생략
}
#pragma endregion
 
#define WM_SYNCSHAREMEMORY WM_USER+1
#define MAXSHAREMEMORY 1024
#define ID_EDIT 100
 
HWND hEdit;
HANDLE hFMap;
TCHAR *PtrInFile;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HWND hTarget;
    TCHAR *Mes="메모리 맵 파일을 사용하여 두 프로세스가 메모리를 공유하는 예제";
 
    switch (iMessage) {
    case WM_CREATE:
        //* 에디트 박스 만들기
        hEdit=CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER |
            WS_VSCROLL | ES_MULTILINE, //* 수직 스크롤 달기 | 엔터쳤을 때 개행가능
            10,10,500,200,hWnd,(HMENU)ID_EDIT,g_hInst,NULL);
        SendMessage(hEdit,
            EM_LIMITTEXT, //* 최대 텍스트 길이 만큼 가지도록해라
            MAXSHAREMEMORY,
            0);
 
        hFMap=CreateFileMapping(//* 메모리 맵 객체를 생성하고 이후 호출시엔 오픈한다.
            INVALID_HANDLE_VALUE, //파일 페이징을 사용한 메모리 공유
            NULL, // 보안 속성
            PAGE_READWRITE, // 읽기,쓰기 모드
            0, // 상위 4bte
            MAXSHAREMEMORY, //하위 4byte
            "MEMSHAREMAPPING" // 파일 매핑 오브젝트 이름 (이름을 지정하여 다른 프로세스에서도 핸들을 얻을 수 있다.)
            );
        PtrInFile=(TCHAR *)MapViewOfFile(hFMap, FILE_MAP_ALL_ACCESS,0,0,MAXSHAREMEMORY);
        // 메모리맵 핸들을 주면서, 내 가상주소에 매핑시킨다. 시작주소가 PtrInFile 이 되는 것이다.
        return 0;
    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case ID_EDIT:
            switch (HIWORD(wParam)) {
            case EN_CHANGE: // 입력시 발생하는 메세지
                GetWindowText(hEdit,PtrInFile,MAXSHAREMEMORY); // PtrInFile 메모리에 써진다.
                hTarget=FindWindow(NULL,"MemShare2");
                if (hTarget)
                    SendMessage(hTarget,WM_SYNCSHAREMEMORY,0,0);
                break;
            }
        }
        return 0;
    case WM_LBUTTONDOWN:
    case WM_SYNCSHAREMEMORY:
        SetWindowText(hEdit,PtrInFile); // PtrInFile 내용을 에디트 박스에 올린다.
        return 0;
    case WM_PAINT:
        hdc=BeginPaint(hWnd, &ps);
        TextOut(hdc,10,220,Mes,lstrlen(Mes));
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        UnmapViewOfFile(PtrInFile); //매핑을 제거한다.
        CloseHandle(hFMap);
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
 
댓글
댓글쓰기 폼