'API & MFC'에 해당되는 글 48건

  1. 2010.01.25 파일매핑예제
  2. 2010.01.25 WNDCLASS 구조체
  3. 2010.01.25 스레드의 함정
  4. 2010.01.24 스레드
  5. 2010.01.24 이벤트
  6. 2010.01.24 세마포어
  7. 2010.01.24 파일매핑 사용순서
  8. 2010.01.24 Dll이란?
  9. 2010.01.20 파이프 추가내용
  10. 2010.01.18 소켓통신(함수정리) 1

- 파일 오픈                                                                  hF=CreateFile("test.txt")

- 파일 내용을 메모리에 올린다                                        hMapF=CreateFileMapping(hF)

- 메모리에 올려진 첫번째 주소를 얻는다.                          pF=MapViewOfFile(hMapF)

- 첫번째 주소로 메모리 내용을 조작한다.

- 중간중간에 변경된 내용을 강제로 디스크에 쓰게만든다.    FlushViewOfFile(pF)

- 해제.                                                                        UnmapViewOfFile(pF);

- 해제.                                                                        CloseHandle(hMapF);

- 파일 닫기.                                                                 CloseHandle(hF);

<예제>

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

 

int main(int argc, char *argv[])
{
 HANDLE hF, hMapF;
 DWORD fSize, i;
 char *pF, *pFtmp;

 

 hF=CreateFile("test.txt",GENERIC_READ|GENERIC_WRITE, 0,
                                  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

 

 fSize=GetFileSize(hF,NULL);

 

 hMapF=CreateFileMapping(
                                         hF,                          //file handle
                                         NULL,
                                         PAGE_READWRITE,
                                         0,                           //file size
                                         0,                           //file size
                                         NULL);                    //map name
 if(hMapF==NULL)
 {
  printf("CreateFileMapping() fail");
  CloseHandle(hF);
  return 1;
 }


 pF=MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,0);
 
 pFtmp=pF;

 for(i=0;i<fSize;i++)
 {
  *pFtmp=(*pFtmp+1);
  pFtmp++;
 }

 

 //메모리 내용을 강제로 파일에 쓴다.
 FlushViewOfFile(pF, 0);

 

 UnmapViewOfFile(pF);

 CloseHandle(hMapF);

 CloseHandle(hF);


 return 0;
}





Share Memory를 만드는 프로세스:

CreateFileMapping->MapViewOfFile->UnmapViewOfFile->CloseHandle


Share Memory를 Open하는 프로세스:

OpenFileMapping->MapViewOfFile->UnmapViewOfFile->CloseHandle

 

<예제>

<공유메모리를 만들고 공유메모리에 데이터를 써넣는 프로그램>

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

#pragma pack(1)

typedef struct tag_SMTEST
{
 char c;
 int  i;
 short s;
} SMTEST;


int main(int argc, char *argv[])
{
 HANDLE hMapF;
 SMTEST *psm;

 

// JJBSMTEST라는 이름으로 공유메모리를 만든다.

 hMapF=CreateFileMapping(
                                         INVALID_HANDLE_VALUE,
                                         NULL,
                                         PAGE_READWRITE,
                                         0,    
                                         sizeof(SMTEST),    
                                         "JJBSMTEST");   
 if(hMapF==NULL)
 {
  printf("CreateFileMapping() fail");
  return 1;
 }
 psm=(SMTEST *)MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,sizeof(SMTEST));
//이후부터 psm 포인터만 읽으면 파일의 내용을 자유롭게 액세스할 수 있다. 
// 파일이 프로세스의 주소 공간에 맵되어 있으므로 포인터를사용하면 연결된 파일의 원하는 부분을 읽을 수 있다.

 psm->c='a';
 psm->i=100;
 psm->s=10;

 

//아래 프로그램을 실행할수있게 시간을 주자

 Sleep(10000);
 
 UnmapViewOfFile(psm);

 CloseHandle(hMapF);

 return 0;
}

  

<예제>

<공유메모리에 접근하여 데이터를 출력하는 프로그램.>

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

#pragma pack(1)

typedef struct tag_SMTEST
{
 char c;
 int  i;
 short s;
} SMTEST;


int main(int argc, char *argv[])
{
 HANDLE hMapF;
 SMTEST *psm;

// JJBSMTEST라는 이름으로 공유메모리에 접근한다.

 hMapF=OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "JJBSMTEST");
 
 if(hMapF==NULL)
 {
  printf("OpenFileMapping() fail");
  return 1;
 }
 psm=(SMTEST *)MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,sizeof(SMTEST));

 

 //공유메모리에 설정된 내용을 출력한다.
 printf("c:%c i:%d, s:%d\n",psm->c,psm->i,psm->s);
 
 UnmapViewOfFile(psm);

 CloseHandle(hMapF);

 return 0;
}

<예제> 파일을 메모리에 올려놓고 마음대로 불러다 쓴다.

typedef struct Member
{
 char Id[256];
 char name[256]; 
}Member;


Member * member;
Member mem[1000];

void Init()
{

 int i=0;
  
 for(i=0; i<1000; i++)
 {
  strcpy(mem[i].Id,   "22");
  strcpy(mem[i].name,   "22");
 }
}


void FileSet()
{
 DWORD dwWritten;
 
 
 hFile = CreateFile("c:\\jinyong.dat", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
 
 if(hFile!=INVALID_HANDLE_VALUE)
 {
  WriteFile(hFile, mem, sizeof(Member)*1000, &dwWritten, 0);
 }
 
 CloseHandle(hFile);
}


void Mapping()
{
 HANDLE hFile2;

 int i=0;
 hFile2 = CreateFile("c:\\jinyong.dat", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
 if(hFile2 != INVALID_HANDLE_VALUE)
 {
  hMap = CreateFileMapping(hFile2, NULL, PAGE_READWRITE, 0, 0, NULL);
  member = (Member *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 }
 printf("%s\n",member[2].Id);
 printf("%s\n",member[3].name);

}
 

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

레지스트리  (0) 2010.02.02
o/s의 role  (0) 2010.01.28
WNDCLASS 구조체  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
Posted by 아몰라

 typedef struct tagWNDCLASS
{
      UNIT style;
      WNDPROC lpfnWndProc;
      int cbClsExtra;
      int cbWndExtra;
      HINSTANCE hInstace;
      HICON hIcon;
      HCURSOR hCursor;
      HBRUSH hbrBackground;
      LPCSTR lpszMenuName;
      LPCSTR lpszClassName;
}WNDCLASS;

lpszClassName - 등록하고자 하는 윈도우 클래스의 이름을 나타내는 문자열이며 윈도우 클래스의 구분에 사용된다.

hInstace - 윈도우 클래스를 등록한 응용 프로그램의 인스턴스 핸들이다. 이 멤버가 지정한 응용 프로그램이 이 윈도우 클래스의 소유주가 되며 소유주가 파괴되면 윈도우 클래스도 같이 파괴된다. 메인 윈도우를 만들 때는 WinMain으로 전달된 hHinstance 인수를 그대로 대입하면 된다.


lpfnWndProc - 메시지 처리 함수를 지정한다. 이 클래스로부터 만들어진 윈도우에 메시지가 전달되면 이 멤버가 지정하는 함수로 메시지가 전달되어 윈도우 고유의 처리를 하게 된다. 메인 윈도우 하나로 구성된 프로그램이라면 이 멤버의 값은 선택의 여지없이 WndProc이 될 것이나 차일드 윈도우나 팝업 윈도우가 있다면 다른 이름이 될 수도 있다.

hCursor - 클래스 커서를 지정한다. 이 클래스로부터 만들어진 윈도우의 작업영역에 마우스가 위치해 있을 때 이 멤버가 지정하는 커서가 사용된다. 리소스에 커서를 추가하고 LoadCursor 함수로 읽어 커서 핸들을 대입하거나 디폴크 커서 중 하나를 대입한다.

hIcon - 타이틀 바의 좌상단에 보여줄 아이콘과 윈도우가 최소화되었을 때 보여줄 아이콘을 지정한다. NULL일 경우 아이콘을 그려야할 때 운영체제가 WM_ICONERASEBKGND 메시지를 보내는데 이 때 원하는 아이콘을 직접 그려야한다.

hbrBackground - 윈도우의 작업영역을 칠할 배경 브러시를 지정한다. GetStockObject나 그 외 브러시를 만드는 함수를 사용하여 브러시 핸들을 얻은 후 이 멤버에 대입한다.

lpszMenuName -  이 클래스로부터 만들어진 윈도우가 사용할 메뉴를 지정한다.

style - 윈도우 클래스의 스타일을 지정한다. CreateWindow 에서 지정하는 개별 윈도우의 스타일과는 다르지만 결국은 이 클래스로부터 만들어지는 윈도우에 영향을 미친다.

cbClsExtra - 윈도우 클래스에서 사용하고자 하는 여분의 메모리양을 바이트 단위로 지정한다. 운영체제는 윈도우 클래스를 등록할 때 이 멤버가 지정하는만큼의 메모리를 추가로 할당한다.

cbWndExtra - cbClsExtra와 유사하되 개별 윈도우에서 사용하고자 하는 여분의 메모리양을 지정한다. 운영체제는 CreateWindow로 개별 윈도우를 만들 때마다 이 멤버가 지정하는만큼의 메모리를 추가로 할당한다.

출처 - 윈도우즈 API 정복 , 김상형 지음

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

o/s의 role  (0) 2010.01.28
파일매핑예제  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
Posted by 아몰라

주 스레드의 데이터 직접 참조

- 작업 스레드는 주 스레드에 대해 완전히 독립적이어야 하며 주 스레드가 어떤 동작을 하더라도 자신의 작업을 완료할 수 있어야 한다. 그러기 위해서는 작업거리도 자신만의 것을 가져야 하며 주 스레드는 작업 스레드를 위해 사본을 작성하여 전달해야 한다.

예)프린터, 인쇄스레드는 주 스레드가 편집하고 있는 문서가 아닌 별도의 사본을 가져야 하며 사본을 인쇄해야 한다. 주 스레드가 편집하는문서를 바로 인쇄하려고 하면 문서의 뒤쪽은 사용자가 새로 편집한 내용이 될 것이다.


스레드의 실행 순서나 실행 시간에 대해 어떠한 가정도 해서는 안된다.


- 스레드의 작업 시간이 얼마가 걸릴지는 실제로 돌려 보기 전에는 알 수 없다. 마찬가지로 두 스레드가 동시에 실행될 때 어떤 스레드가 먼저 시작하거나 끝날 것이라는 것도 가정해서는 안된다. 스레드는 완전히 독립적인 작업을 해야 하므로 순서가 있는 작업은 스레드로 분리해서는 안되며 만약 정 필요하다면 동기화해야 한다. 스레드의 작업 시간이나 실행, 종료 순서는 확률적으로 계산 할 수 있다하더라도 절대적이지는 않다.


스레드는 항상 재진입 가능하다는 것을 염두에 두어야 한다.

- 스레드가 호출하는 함수에서 이런 실수를 할 가능성이 많은데 스레드가 호출하는 모든 함수들은 항상 재진입 가능성을 염두에 두고 누가 자신을 호출 하더라도 문제 없이 동작하도록 작성해야 한다.

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

파일매핑예제  (0) 2010.01.25
WNDCLASS 구조체  (0) 2010.01.25
스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
Posted by 아몰라
WinMain과 메시지 루프, WndProc, 일반 함수들을 오가며 메시지를 처리하는 일련의 코드들을 스레드 라고한다.

프로세스는 단지 존재하기만 하는 껍데기일 뿐, 실제 작업은 스레드가 담당한다. 프로세스 생성시 하나의 주 스레드가 생성되며 대부분의 경우 주 스레드가 모든 작업을 처리하고 주 스레드가 종료되면 프로세스도 같이 종료된다.
주스레드 = 프로세스


그리고 주스레드 실행도중에 다른 작업을 같이 하고싶으면 스레드를 여러개 더 추가 할 수 있는데 그 스레드들을 실행하는 도중에 주스레드가 종료되면 실행중인 보조 스레드들도 다 종료된다.


스레드생성

HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)


LPSECURITY_ATTRIBUTES lpThreadAttributes - 스레드의 보안 속성을 지정하는데 자식 프로세스로 핸들을 상속하지 않는 한 NULL로 지정하면 된다.

DWORD dwStackSize - 스레드의 스택 크기를 지정하는데 스레드끼리 상호 안정된 동작을 하기 위해 스레드별로 별도의 스택이 할당된다. 스택의 초기 크기를 0으로 지정하면 주 스레드(Create Thread를 호출한 스레드) 와 같은 크기를 가진다. (기본적으로 스레드의 스택은 1M가 예약되며 프로세스의 주소 공간은 2G이므로 생성 가능한 스레드 개수는 약 2000개이다.)

LPTHREAD_START_ROUTINE lpStartAddress -  스레드의 시작 함수를 지정 

스레드 시작함수의 원형 - DWORD WINAPI ThreadFunc(LPVOID lpParameter)

LPVOID lpParameter - 시작 함수로 전달할 작업내용이다. 없을 경우 NULL

DWORD dwCreationFlags - 생성할 스레드의 특성을 지정하는데 0이면 물론 아무 특성 없는 보통 스레드이다. CREATE_SUSPENDED 플래그를 지정하면 스레드를 만들기만 하고 실행은 하지 않는다. 중지된 스레드를 실행 할때는 Resume Thread 함수를 호출한다.

LPDWORD lpThreadId - 스레드를 만든 후 스레드의 ID를 리턴하기위한 출력용 인수로이므로 DWORD형의 변수를 하나 선언한 후 그 변수의 번지를 넘기면 된다. 스레드 ID가 필요한 경우는 별로 없는데 이 경우는 NULL을 전달한다.

CreateThread 함수는 스레드를 만든 후 스레드의 핸들을 리턴하며 에러가 발생했을 경우 NULL을 리턴한다. 리턴된 스레드의 핸들은 이후 이 스레드를 제어하고자 할 때 사용하는데 생성 후 스레드를 더 이상 조작하지 않을 경우 곧바로 핸들을 닫아도 된다. 스레드 핸들과 스레드 자체는 다르므로 핸들을 닫는다고 해서 스레드가 종료되는 것은 아니다. 여섯 번째 인수로 스레드 ID도 리턴 되는데 핸들과 ID의 차이에 대해서 아래에 간략히 적어보겠다.



핸들 - 프로세스 내에서 해당 객체를 액세스할 때 사용하는 한정적인 값이며 이 핸들을 사용하여 객체를 마음대로 조작할 수 있다. (C++의 지역변수)
ID -  시스템 전역적인 값이며 다른 프로세스 ID와 절대 중복되지 않는다. 그래서 프로세스끼리 ID를 전달함으로써 목적이 되는 프로세스 핸들을 다시 오픈할 수 있다. 실행 중인 프로세스의 ID는 작업 관리자에서 쉽게 확인할 수 있다.
(C++에서 Get 함수)

정리 - 프로세스 ID는 프로세스간의 구분을 위한 중복되지 않는 식별값일 뿐이며 ID로부터 직접 프로세스를 제어할 수는 없다. ID로부터 핸들을 발급받아야만 비로소 이 객체를 제어할 수 있다.


스레드종료

자식 쓰레드가 작업을 할 때 주 쓰레드는 자식 쓰레드를 만들기만 하고 종료 상태에는 별로 관심을 두지 않는 것이 보통이다. 특별한 경우를 제외하고 두 쓰레드는 서로 독립적으로 실행될 뿐이다. 그러나 주 쓰레드는 적어도 자식 쓰레드가 종료되었는지의 여부는 주기적으로 조사해 봐야 한다. 이때 사용되는 함수가 GetExitCodeThread 함수이다.

 

BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode);

 

hThread

쓰레드의 핸들 값

lpExitCode

쓰레드의 종료 코드조사를 위한 인수

 

 

때로는 작업 중간에 쓰레드를 종료해야 하는 경우가 있다. 예를 들어 다운로드를 받는 스레드를 만들었는데 중간에 사용자가 다운로드를 취소했다면 더 이상 이 쓰레드는 존재할 필요가 없다. 

쓰레드를 강제 종료할 때 사용되는 함수는 ExitThread 이다.

 

VOID ExitThread (DWORD dwExitCode);

ExitThread 는 쓰레드가 스스로 종료할 때 사용하는데 인수로 종료 코드를 넘겨준다. 쓰레드가 ExitThread 를 호출하면 자신의 스택을 해제하고 연결된 DLL을 모두 분리 후 파괴된다.

TerminateThread는 쓰레드 핸들을 인수로 전달받아 해당 쓰레드를 강제로 종료한다.

 





'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

WNDCLASS 구조체  (0) 2010.01.25
스레드의 함정  (0) 2010.01.25
이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Posted by 아몰라


이벤트란 어떤 사건이 일어났음을 알리는 동기화 객체이다?

 

-       크리티컬섹션, 뮤텍스, 세마포어는 주로 공유자원을 보호하기 위해 사용되는 데 비해 이벤트는 그보다는 스레드간의 작업 순서나 시기를 조정하고 신호를 보내기 위해 사용한다.

 

 

이벤트는 윈도우의 메시지와 유사하다?

 

-       사용자가 키보드 누를 때 WM_KETDOWN 메시지를 윈도우 프로시저에게 보내 처리하게 하는 것처럼 정렬이나 다운로드가 끝났을 때 이벤트를 보내 관련된 다른 작업을 하도록 지시할 수 있다.

 

 

자동 리셋 이벤트

대기 상태가 종료되면 자동으로 비신호상태가 된다.

수동 리셋 이벤트

스레드가 비신호상태로 만들 때까지 신호상태를 유지한다.

 

 

이벤트 함수정리

 

이벤트생성함수

 

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL blnitialState, LPCTSTR lpname);

 

lpEventAttributes

보안속성

bManualReset

TRUE이면 수동 리셋 이벤트 FALSE이면 자동 리셋 이벤트

blnitialState

TRUE이면 이벤트를 생성함과 동시에 신호상태로 만든다.

lpname

이름

세마포어와 마찬가지로 첫번째, 네번째인자는 프로세스동기화와 관련있다.

 

 

n  이벤트가 뮤텍스나 크리티컬섹션과 또 다른 점은 대기 함수를 사용하지 않고도 임의적으로 신호상태나 비신호상태를 설정할 수 있다는 점이다. 이때 쓰는 함수가 아래와 같다.

 

신호상태변경함수

 

BOOL SetEvent(HANDLE hEvent)

BOOL ResetEvent(HANDLE hEvent)

 

SetEvent

신호상태로 만든다.

ResetEvent

비신호상태로 만든다.

이런 상태변화가 대기중인 스레드에게는 일종의 신호로 전달된다.

 

 

 

자동 리셋 이벤트

 

       대기 상태를 풀 때 자동으로 이벤트를 비신호상태로 만든다는 뜻이다.

       여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하지않다.

 

 

수동 리셋 이벤트

 

       대기 상태를 풀 때 신호 상태를 그대로 유지하고 ReSerEvent 함수로 일부러 비신호상태로 만들 때만 상태가 변경된다.

        여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하다.



함수 사용 예제

 

HANDLE hEvent;

DWORD WINAPI ThreadSend(LPVOID temp)

{

             WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기

             HDC hdc=GetDC(hWndMain);

             TextOut(hdc,210,100,"전송완료",8);

             ReleaseDC(hWndMain, hdc);

             return 0;

}

 

DWORD WINAPI ThreadSave(LPVOID temp)

{

             WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기

             HDC hdc=GetDC(hWndMain);

             TextOut(hdc,110,100,"저장완료",8);

             ReleaseDC(hWndMain, hdc);

             return 0;

}

 

DWORD WINAPI ThreadCalc(LPVOID temp)

{

             HDC hdc=GetDC(hWndMain);

             for (int i=0;i<10;i++) {

                           TextOut(hdc,10,50,"계산중",6);

                           GdiFlush();

                           Sleep(300);

                           TextOut(hdc,10,50,"기다려",6);

                           GdiFlush();

                           Sleep(300);

             }

             TextOut(hdc,10,50,"계산완료",8);

             ReleaseDC(hWndMain, hdc);

             SetEvent(hEvent);   //신호상태로 바꿔줌

             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:

                           hWndMain=hWnd;

                           hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);  //수동이벤트

                          

                           //hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); // 자동 이벤트

                           return 0;

             case WM_LBUTTONDOWN:

                           InvalidateRect(hWnd,NULL,TRUE);

                           ResetEvent(hEvent);

                           CloseHandle(CreateThread(NULL, 0, ThreadCalc, NULL, 0, &ThreadID));

                           CloseHandle(CreateThread(NULL, 0, ThreadSave, NULL, 0, &ThreadID));

                           CloseHandle(CreateThread(NULL, 0, ThreadSend, NULL, 0, &ThreadID));

                           return 0;

             case WM_PAINT:

                           hdc=BeginPaint(hWnd, &ps);

                           TextOut(hdc,10,10,Mes,lstrlen(Mes));

                           EndPaint(hWnd, &ps);

                           return 0;

             case WM_DESTROY:

                           CloseHandle(hEvent);

                           PostQuitMessage(0);

                           return 0;

             }

             return(DefWindowProc(hWnd,iMessage,wParam,lParam));

 

WM_CREATE에서 이벤트 객체를 생성하는데 이 때 두 번째 인수로 TRUE를 지정하여 수동 리셋 이벤트가 되도록하였다.

 

가장 위 에 있는 계산스레드가 실행이되는데 계산이 완료되면 SetEvent함수를 호출하여 신호상태로 만든다.

신호상태로 바뀌어지면 대기하고있던 스레드들이 모두 실행 할 수 있다.

 

, 자동리셋은 같은 상황에서 계산스레드가 끝나고 다른 스레드가 실행되는데 그 스레드가 대기함수를 거치면서 신호를 비신호상태로 바꿔놓음으로서 다른 스레드들은 또 대기를 해야한다.



출처 - 윈도우즈 API 정복 , 한빛미디어

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
세마포어  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
Posted by 아몰라

 

세마포어는 뮤텍스와 유사한 동기화 객체이다?

 

-      뮤텍스는 하나의 공유 자원을 보호하기 위해 사용하지만 세마포어는 제한된 일정 개수를 가지는 자원을 보호하고 관리한다.

 

 

세마포어는 사용가능한 자원의 개수를 카운트하는 동기화 객체이다?

        

-      유효자원이 0이면 즉 하나도 사용 할 수 없으면 세마포어는 비신호상태가 되며 1이상이면, 즉 하나라도 사용할 수 있으면 신호상태가 된다.

 

 

 

신호상태

스레드의 실행을 허가하는 상태이다.

신호상태의 동기화 객체를 가진 스레드는 계속 실행할 수 있다. (신호등의 파란불)

비신호상태

스레드의 실행을 허가하지 않은 상태이다.

신호상태가 될 때까지 스레드는 블록된다. (신호등의 빨간불)



세마포어 개념을 위한 예)

 

-      네트워크를 통해 프로그램을 다운받는 프로그램을 만든다.

 

n  동시에 여러 개의 자료를 다운로드 받는 것이 가능하기는 하지만 별로 효율적이지는 않다.

n  어차피 네트워크의 대역폭은 정해져 있는 것이므로 한꺼번에 다운로드 받는다고 해서 빨라지는 것도 아니고 그렇다고 순서대로 받는 것은 불편하다.

n  동시에 받되 최대 3개까지만 동시 다운로드가 가능하도록 하고싶다.

n  실제 다운로드 툴이나 웹 브라우저도 일정 개수까지만 동시 다운로드를 지원한다.

 

 

 

 

이경우 자원이란 다운로드 권한이라 표현할 수 있을 것이며 세마포어는 이 권한을 카운트 한다. 세마포어의 초기값을 3으로 설정하고 사용자의 요구가 있을 때마다 다운로드 스레드를 생성한다. 스레드에서는 WaitForSingleObject함수를 호출하여 자신이 사용할 수 있는 권한이 아직 남아 있는지 검사해 보고 가능하다면 다운로드 루프로 진입한다. 이때 대기 함수는 세마포어의 카운트를 1감소시켜 자원이 하나 줄어들었음을 기록한다.

 

두번째, 세번째 스레드가 다운로드를 시작하면 세마포어의 카운트는 0이 되며 비신호상태가 된다. 그러면 이후부터 생성되는 스레드는 다운로드 루프로 진입하지 못하고 자원이 사용가능해질 때 까지 대기하게 된다. 대기중에 첫번 째 스레드가 다운로드를 완료하면 세마포어를 풀 것이고 그러면 세마포어는 다시 1증가하여

신호상태가된다.

 

 

 

세마포어 함수정리

 

 

 

세마포어 생성함수

HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG llnitialCount, Long lMaximumCount, LPCTSTR lpName);

 

lpSemaphoreAttributes

보안속성

llnitialCount

초기값(최대사용개수에 대한 값)

lMaximumCount

최대사용개수(몇 개의 스레드를 실행시킬수 있나)

lpName

이름

첫번째 , 네번째 인자는 프로세스간의 동기화에 사용된다. 한 프로세스에서만 사용 할 시 NULL 값을 주면된다.

 

 

DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

 

hHandle

하나의 동기화 객체가 신호상태가 되기를 기다린다.

dwMilliseconds

타임 아웃 시간

<dwMilliseconds>

1/1000초 단위로 지정하는데 이 시간이 경과하면 설사 동기화 객체가 비신호상태이더라도 즉시 리턴함으로써 무한 대기를 방지한다. 타임 아웃을 INFINITE로 짖어하면 신호상태가 될 때까지 무한정 대기한다.

 

 

 

WaitForSingleObject 리턴값

 

WAIT_OBJECT_0

hHandle 객체가 신호상태가 되었다.

WAIT_TIMEOUT

타임 아웃 시간이 경과하였다..

WAIT_ABANDONED

포기된 뮤텍스

 

 

 

세마포어의 카운트를 증가시켜주는 함수

 

BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);

 

hSemaphore

자원을 반환할  세마포어

lReleaseCount

자신이 사용한 자원의 개수를 알려준다.

lpPreviousCount

이전 카운트를 리턴받기 위한 참조 인수

세번째 인자는 이 값에 관심이 없으면 NULL을 넘기면 된다.

 

함수 사용 예제

프로시저실행시

HANDLE hSem;

hsem = CreateSemaphore(NULL, 3, 3 , NULL);

 

마우스왼쪽버튼클릭시

HANDLE hThread;

hThread = CreateThread(NULL, 0, ThreadDownLoad, NULL, 0 , &ThreadID);

 

스레드 진입시

// 다운로드 화면표시 초기화

WaitForSingleObject(hSem, INFINITE);

// 다운로드 실행화면 표시

설명

-      같은 프로세스 내에서 사용할 것이므로 이름을 줄 필요는 없으며 보안 속성도 지정하지 않았다.

-      다운로드 가능 최대 개수는 3으로 설정했으며 처음부터 3개의 자원이 다 사용 가능하므로 초기값도 3이다.

-      왼쪽버튼클릭시 스레드가 생성되고 다운로드 실행화면이 표시된다. 네번째 클릭하게되면  해당 스레드는 WaitForSingleObject에서 대기하다가 어느 스레드가 종료되면 세마포어가 신호상태로되고 기다리던 스레드는 실행하게된다.



출처 - 윈도우즈 API 정복 , 한빛미디어

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Posted by 아몰라

 파일매핑 순서

1) CreateFile API로 파일을 연다.

2) CreateFileMapping API로 그 파일에 대한 파일 매핑 객체를 생성한다.

3) MapViewOfFile API로 파일 매핑 객체의 뷰를 생성한다.

 

HANDLE CreateFileMapping(                             //반환값: 객체 핸들 , 실패시 = INVALID_HANDLE_VALUE 반환

      HANDLE hFile,                                           //파일 핸들

      LPSECURITY_ATTIRBUTES lpAttrs,               //보안 속성

      DWORD flProtect,                                        //접근 허가 , 액세스 타입(PAGE_READONLY,

PAGE_READWRITE,PAGE_WRITECOPY)


      DWORD dwMaxSizeHigh,                            //매핑할 크기의 상위 32비트     , 둘다 0이면 전체파일

      DWORD dwMaxSizeLow,                            //매핑할 크기의 하위 32비트     , 둘다 0이면 전체파일

      LPCTSTR lpName);                                    //객체명 , 첫번째 인수를 NULL로 주었을때 다른 프로세스와
                                                                       동기화하기 위한 목적

 

뷰를 만들어 가상 주소 공간에 매핑! >>

매핑해서 파일 읽고 쓰려면 MapViewOfFile API로 '뷰'를 생성해야한다.

뷰는 실제 파일 내용이 매핑되는 가상 주소 영역.

 

LPVOID MapViewOfFile(                      //반환값: 맵핍항 프로그램상의 주소

      HANDLE hFileMapObj,                  //파일 매핑 객체 핸들 ,

      DWORD dwDesiredAccess,         //필요한 접근 제한 액세스 타입(FILE_MAP_WRITE,FILE_MAP_READ,FILE_
                                                     MAP_ALL_ACCESS,FILE_MAP_COPY)

      DWORD dwFileOfsHigh,              //뷰를 실행할 범위의 시작 오프셋 상위 32비트

      DWORD dwFileOfsLow,               //뷰를 실행할 범위의 시작 오프셋 하위 32비트

      SIZE_T dwBytesToMap);             //뷰를 실행할 범위의 크기

  

뷰의 메모리에서 범위를 지정하여 파일 갱신>>

 

BOOL FlushViewOfFile (                                   //반환값: 처리 성공 여부

      LPCVOID lpBaseAddr,                                //갱신할 영역 시작 주소

      DWORD dwNumberOfBytes);                        //갱신할 영역 크기

 

뷰 해제하기 >>

BOOL UnmapViewOfFil(                                    //반환값: 처리 성공 여부

      LPCVOID lpBaseAddr);                               //해체할 뷰의 시작주소

 

파일 매핑 객체 자체가 불 필요하게 될 경우엔 CloseHandle API로 닫기!!

 

 

이름붙은 파일 매핑 객체 핸들을 다른 프로세스에서 가져와 사용하기 >>

HANDLE OpenFileMapping(                               //반환값: 객체 핸들

      DWORD dwDesiredAccess,                         //필요한 접근 권한

      BOOL bInheritHandle,                                 //자식 프로세스에 상속할 것인가?

      LPCTSTR lpName);                                    //객체명  

[출처] 파일매핑|작성자 숙녀라면


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Hooking  (0) 2010.01.15
Posted by 아몰라

  라이브러리

라이브러리(Library)란 함수,데이터,타입 등 여러가지 프로그래밍 요소들의 집합이며 보통 LIB확장자를 가진다. (DLL사용시 h,dll파일 필요) 자주 사용되는 표준적인 함수를 매번 직접 작성해서 사용하는 것은 지나치게 시간 소모적이므로 표준화할 수 있는 함수를 미리 만들어서 모아 놓은 것이 라이브러리이다. 라이브러리를 한 번 구축해 놓기만 하면 다시 만들 필요없이 불러서 사용할 수 있으므로 개발 속도도 빨라지고 신뢰성도 확보할 수 있다.

 

한글 입출력을 하는 라이브러리를 생각해 보자. 한글은 무척 복잡한 언어이기 때문에 한글을 사용하는 모든 프로그램에서 한글 입출력 함수를 일일이 만들어 사용하기 어렵다. 그래서 누군가가 한 번만 한글 입출력 함수를 만들어 라이브러리로 배포하면 나머지 사람들은 이 라이브러리에 있는 함수를 불러 한글을 출력하기도 하고 입력받기도 한다.

 

  STATIC LINK

 

ProA.exe를 만드는 사람은 자신의 고유 코드만 ProA.cpp에 작성하고 HAN.LIB와 연결하면 한글 입출력 기능을 가진 ProA.exe. 실행 파일을 만들 수 있다. HAN.LIB에 있는 함수와 데이터는 링커에 의해 실행 파일에 그대로 옮겨지면 실행 파일의 일부분이 된다.

 이런 전통적인 라이브러리 연결 방법을 정적 링크(Static Link)라고 하면 컴파일시에 라이브러리에 코드를 실행파일에 복사한다.

 

 

  DLL

DLL은 동적 링크(Dynamic Link)를 사용한다. 동적 링크란 컴파일시에 함수의 코드가 실행 파일에 복사되는 것이 아니라 실행 중에 라이브러리에 있는 함수를 호출하는 방법을 말한다.

ProA.exe를 만드는 사람은 자신의 고유 코드만 ProA.cpp에 작성하고 이 소스를 컴파일하여 ProA.exe를 만든다. ProA.cpp에서는 한글 입출력 함수를 호출하지만 ProA.exe파일에는 한글 입출력 함수가 포함되어 있지 않다. 대신 ProA.exe는 한글 입출력 함수의 위치에 대한 정보를 가지고 있으며 이 프로그램이 실행될 때 HAN.DLL이 메모리에 같이 로드되며 ProA.exe에서 HAN.DLL에 있는 함수를 호출한다.

 

  DLL의 장점

     한 코드를 여러 프로그램이 동시에 사용하기 때문에 메모리가 절약된다.

     정적링크를 사용하는 경우 실행 파일에 라이브러리의 함수가 모두 포함되어 실행파일이 커지지만 DLL을 사용하는 프로그램은 크기가 작다.

     DLL을 교체하여 프로그램의 성능을 향상시키기 쉽다.

     리소스의 교체가 가능하다.

     코드의 양이 적어지므로 디버깅이 용이해진다

     혼합 프로그래밍이 가능해 진다

     프로그래머끼리 분담 작업이 용이하며 재사용성도 뛰어나다.

 

 

  정적링크와 동적 링크

정적 링크

컴파일 시에 함수가 실행 파일에 연결된다. 실행 파일에 함수의 코드가 복사되기 때문에 실행 파일의 크기가 커지는 단점이 있지만 실행 파일은 완전한 단독 실행 파일이 된다. 실행파일에 함수의 코드가 포함되어 있기 때문에 컴파일이 끝나면 라이브러라 파일(LIB)이 없어도 프로그램을 실행할 수 있다.

동적 링크

실행시에 함수가 실행 파일에 연결된다. 실행 파일에는 호출할 함수의 정보만 포함되고 실제 함수 코드는 복사되지 않ㅇ므로 실행 파일의 크기가 작아진다. 하지만 실행 파일은 함수에 대한 정보만 가지고 있을 뿐 실제 코드를 가지고 있지는 않으므로 프로그램 실행시에 DLL이 꼭 있어야 한다.

 

*  DLL관리

 윈도우가 DLL을 어떻게 관리하는지를 상상해 보자. 클라이언트 프로그램인 ProA.exe가 실행되면 이 프로그램의 실행에 필요한 HAN.DLL함수도 메모리로 같이 로드될 것이다. DLL은 자신을 로드한 프로세스의 가상 주소 공간에 맵핑되면 따라서 DLL은 메모리,스택,핸들을 프로세스와 공유하게 된다.

 

 두 번째 클라이언트인 ProB.exe가 실행될 때는 HAN.DLL이 이미 메모리에 올라와 있으면 HAN.DLL은 읽어올 필요가 없으며 ProB.exe만 읽어온다. 대신 윈도우는 ProB.exe의 주소 영역에 HAN.DLL이 로드된 메로리를 맵핑시켜 ProB.exe에서도 HAN.DLL의 함수를 자유롭게 호출할 수 있도록 한다. 세번째 클라이언트인 ProC.exe가 실행될 때도 마찬가지로 같은절차를 거칠 것이며 이 상태에서는 세 개의 클라이언트 프로그램이 하나의 DLL을 공유한다.

 

 

 DLL은 가상 메모리에 한 번 로드되면 다시 로드되지 않는다. 단 코드의 경우만 드렇지 DLL의 고유 변수는 클라이언트 프로그램이 실행될 때마다 매번 다시 메모리를 할당받아야 한다. 클라이언트 프로그램끼리 코드는 공유하지만 데이터는 공유할 수 없기 때문이다. C++클래스의 멤버 함수는 이 클래스로부터 만들어지는 모든 객체가 가 공유하지만 멤버 변수는 개별적으로 가지는 것과 마찬가지이다.

 

 예를 들어 HAN.DLL에 현재 입력 상태가 한글 모드인지 영문 모드인지를 기억하는 변수가 있다고 하자. 이 변수의 값은 클라이언트 프로그램별로 다를 수 있기 때문에 프로그램끼리 공유할 수 없다. 만약 이 변수를 공유한 상태에서 ProA.exe에서 한글 입력 상태로 바꾸면 ProB.exe ProC.exe도 같이 한글 입력 상태로 바뀌어 버릴 것이며 이는 논리적으로 바람직하지 못한 결과를 가져온다. 이런 식으로 DLL내부의 값을 기억하는 변수는 공유가 불가능하기 때문에 클라이언트 프로그램이 실행될 때마다 다시 메모리를 할당받아야 한다.

 

DLL이 메모리에서 지워지는 시기는 언제 쯤일까? 필요가 없어진 DLL은 당연히 메모리에서 사라져야 하지만 DLL은 사용자가 직접 사용하는 것이 아니기 때문에 종료시기를 쉽게 판단할 수 없다. DLL을 처음 메모리로 올린 ProA.exe가 종료될 때 HAN.DLL을 종료하는 방법이 가장 쉽게 떠올릴 수 있는 방법이다. 그러나 최초 DLL을 로드한 ProA.exe가 종료되어도 ProB.exe ProC.exe가 이 DLL을 계속 사용하고 있을 수도 있기 때문이다. DLL이 메모리에서 삭제되어야 할 시기는 DLL을 사용하는 모든 클라이언트 프로그램이 종료되었을 때이다.

 

윈도우는 DLL별로 사용 카운트라는 것을 유지하고 있으며 클라이언트 프로그램이 실행될 때마다 카운트를 1씩 증가시키고 클라이언트가 종료될 때마다 카운트를 1 감소시킨다. 이렇게 사용 카운트를 유지하면서 카운트가 0이 될 때 DLL을 메모리에서 삭제하면 아무런 문제가 없다.

ProA.exe실행

ProB.exe실행

ProC.exe실행

ProA.exe종료

ProC.exe종료

ProB.exe종료

HAN.DLL로드

 

 

 

 

HAN.DLL삭제

COUNT = 1

COUNT = 2

COUNT = 3

COUNT = 2

COUNT = 1

COUNT = 0

 

 

*  DLL접속

__declspec

DLL을 사용하려면 우선 함수를 제공하는 DLL에서는 자신이 제공하고자 하는 함수에 대한 정보를 밖으로 공개해 놓아야 하며 이 동작을 EXPORT라고 한다. 반대로 DLL을 사용하는 클라이언트에서는 어떤 DLL에 있는 어떤 함수를 사용하겠다고 선언해야 하는데 이 동작을 IMPORT라고 한다. 즉 함수를 제공하는 측은 어떤 함수를 제공하겠다는 선언이 있어야 하며 함수를 사용하는 측에서는 어떤 함수를 사용하겠다는 선언이 있어야 한다.

 

 

__declspec은 함수에 대한 정보를 제공하는 선언문이며 엑스포트 또는 임포트하는 함수 앞에 수식어로 이 문구가 있어야 한다. 원형은 다음과 같으며 앞의 밑줄이 두 개임을 유의하다

 

__declspec(extended-attribute) declaratory

 

__declspec문은 기억부류(Storage Class)에 관한 정보를 단순화,표준화하며 원래의 C++에는 없는 문장이지만 마이크로소프트에서 C++문법을 확장한 예 중 하나에 해단한다. 언뜻 보기에는 괄호가 있어 함수같지만 컴파일러가 제공하는 키워드이다. 기억 부류의 속성을 괄호 안에 인수로 지정한다. 사용가능한 인수는 네 가지

가 있다.

인수

설명

Thread

TSL(Thread Local Storage) 데이터로 지정한다. 이 지정자가 붙은 변수는 해당 스레드에서만 사용할 수 있는 변수가 된다.

Naked

접두(prolog),접미(epilog)를 생성하지 않는다. 어셈블리 언어를 사용하여 직접 접두,접미를 달고자 할 때 사용한다. 어셈블리 언어를 사용하여 가상 디바이스 드라이버를 작성할 때 이 기억부류를 사용한다. 함수에만 적용되며 변수에는 적용되지 않는다.

Dllimport

DLL에 있는 데이터,오브젝트,함수를 임포트한다. DLL에 있는 이렇게 생긴 함수를 앞으로 사용하겠다는 선언이다

dllexport

DLL에 있는 데이터,오브젝트,함수를 엑스포트한다. DLL이 사용하는 클라이언트(실행파일이거나 또는 다른 DLL)에게 DLL의 정보를 명시적으로 제공하는 역할을 한다.

Dllexport로 함수를 선언하면 DEF파일의 Exports란에 이 함수를 명시하지 않아도 되며 __export 키워드를 대체한다.

 

 

n  사용방법

 

DLL에서 엑스포트

extern “c” __deslpsec(dllexport) 함수원형;

client에서 임포트

extern “c” __deslpsec(dllimport) 함수원형;

 
암시적 연결 & 명시적 연결

  암시적 연결

함수가 어느 DLL에 있는지 밝히지 않고 그냥 사용한다. 프로젝트에 임포트 라이브러리를 포함해야 하며 윈도우즈는 임포트 라이브러리의 정보를 참조하여 알아서 DLL을 로드하고 함수를 찾는다. 클라이언트 프로그램이 로드될 때 DLL이 같이 로드되거나 이미 DLL이 로드되어 있으면 사용 카운트를 1 증가시킨다. 클라이언트 프로그램이 실행될 때 DLL이 로드되므로 실행시 연결이라고 한다.

n  임포트 라이브러리 DLL파일 찾는 순서

     클라이언트 프로그램이 포함된 디렉토리

     프로그램의 현재 디렉토리

     윈도우의 시스템 디렉토리

     윈도우 디렉토리

     PATH환경 변수가 지정하는 모든 디렉토리

만약 이 순서대로 DLL을 찾아보고 원하는 DLL이 발견되지 않으면 클라이언트 프로그램은 다음과 같은 에러메세지를 출력하고 실행을 종료한다.

 

 

 

※ 암시적 연결 실습

     새 프로젝트를 만든다(Win32 Dynamic-Link Library 형태로 생성)

 

     함수를 작성한다.

xyz.c

#define DLL_SOURCE

#include "xyz.h"   // 이 안에 있는 DLLFUNC __declspec(dllexport)로 된다.

 

int Add( int a, int b )

{

             return a + b;

}

xyz.h

#ifdef DLL_SOURCE

             #define DLLFUNC __declspec(dllexport)  

#else

             #define DLLFUNC __declspec(dllimport)

#endif

 

#include <windows.h>

 

EXTERN_C DLLFUNC int Add( int a, int b);

 

 

     컴파일하면 DLL파일,LIB파일이 생성된다.

 

     XYZ.Dll , XYZ.lib , XYZ.h 파일을 사용할 폴더에 복사한다.

     사용할 프로젝트에서 사용하고자 하는 DLL의 임포트 라이브러리를 프로젝트에 포함시킨다

 혹은  #pragma comment(lib, "xyz.lib")

Usxxyz.cpp

#include <windows.h> // user32.dll의 모든 함수 선언.

#include <stdio.h>

// DLL 사용하기

#include "xyz.h"                                                          // 관련 헤더 include

#pragma comment(lib, "xyz.lib")                      // 라이브러리 추가

void main()

{

MessageBox(0,"A","",MB_OK);

 

int s = Add(10,20);                           // DLL 함수 사용

printf("결과 : %d\n", s);

 

void* p1 = GetModuleHandle( "xyz.dll");

printf("xyz.dll 주소 : %p\n", p1);

printf("Add 주소 : %p\n",    Add);

}

 

정상적으로 값 30이 메시지박스로 뜨고 콘솔창에는 결과와 각각의 주소값이 출력

 


명시적연결의 사용법은 적지않았다
장점만 알아보고 가겠다.

    명시적 연결의 장점

  1. 필요할 때만 DLL을 읽어와 사용하기 때문에 메모리와 리소스가 절약된다. 암시적 연결의 경우 프로그램이 시작 될 때 DLL도 같이 메모리로 올라오므로 프로그램 실행중에 항상 DLL이 메모리에 상주하고 그만큼 메모리가 더 소비된다.
  2. 경우에 따라 사용할 DLL을 교체할 수 있다. LoadLibray에서 DLL 이름을 문자열로 줄 수 있으므로 상황에 맞게 DLL을 선택적으로 사용할 수 있다. 마찬가지로 호출할 함수도 문자열로 지정하므로 선택 가능하다.
  3. 필요한 DLL이 없는 경우에도 프로그램을 실행할 수 있다. 물론 이 경우 DLL에게 분담된 작업은 제대로 처리할 수 없겠지만 최소한 프로그램이 실행되지도 못하는 상황은 발생하지 않는다. DLL이 없을 경우 다른 방법으로 문제를 해결하거나 최소한 에러 메시지라도 보여줄 수 있다. 반면 암시적 연결의 경우는 DLL이 없으면 아예 실행을 시작할 수 조차 없다.
  4. 클라이언트 프로그램의 시작이 빠르다. 암시적 연결은 클라이언트 실행전에 DLL을 읽어와야 하는데 필요한 DLL의 개수가 수십개가 넘으면(실제로 그정도 된다)이 시간이 무시 못할 정도로 길어질 수도 있다.명시적 연결은 일단 프로그램이 실행된 후 필요할 때 DLL을 로드하므로 신속하게 실행된다. 최종 사용자 입장에서는 이 정도 시간 차이가 굉장히 크게 느껴진다.

 















'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

세마포어  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Hooking  (0) 2010.01.15
서비스  (0) 2010.01.13
Posted by 아몰라

CreatePipe, CreateNamedPipe
파이프가 없을시 생성
있을시 접근한 클라이언트와 통신하기위한 핸들값을 반환 


check = ConnectNamedPipe 클라이언트가 접속하기를 대기하였다가 접속하면 함수 종료

DisconnectNamedPipe() - CloseHandle
 파이프를 파괴할수 있긴하나 디스콘넥을 안하면 다시 재준비가 안된다. (예) 백화점 직원 - 커피마시러가는 상황


스레드 주의점

스레드는 고유한 스택 정보를 갖고있다. 그러므로 스레드를호출할때 지역변수의 주소를 넘기는것은 위험하다.
같은 주소가 나올 수 있기 때문에 동적할당을 이용 하는 방법이있다.

 

CreateThread - 이러한 진입점을 가진 스레드를 생성해달라. (생성시켜도 바로 생성되서 실행되지않음)


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
Hooking  (0) 2010.01.15
서비스  (0) 2010.01.13
IPC란?  (0) 2010.01.12
Posted by 아몰라

접속 기반 프로토콜(Connection Oriented Protocol)



SOCKET PASCAL FAR socket(int af, int type, int protocol);

참고주소 : http://msdn.microsoft.com/en-us/library/ms740506(VS.85).aspx

특정 전송 서비스 제공자로 바인드 될 소켓을 생성한다.

리턴 : 성공시 소켓의 핸들. 실패시 INVALID_SOCKET.

af : address family를 정한다.

 - AF_INET(IPv4), AF_IPX, AF_APPLET!ALK, AF_NETBIOS, AF_INET6(IPv6), AF_IRDA, AF_BTH

type : 새로운 소켓이 어떤 형태인지 정한다.

 - SOCK_STREAM : OOB data 전송 메카니즘을 가진 순서화된 신뢰성 있는 양방향, 접속 기반 바이트 스트림을 제공한다.

 - SOCK_DGRAM : 고정된 최대 크기의 신뢰성 없고 접속하지 않는 버퍼인 데이터그램을 제공한다.

 - SOCK_RAW : Layer 3 프로그래밍을 하고 싶을 때

   예시) ping(컴퓨터가 살았나 죽었나, round-trip), tracert

protocol : 사용될 프로토콜

 - IPPROTO_TCP, IPPROTO_UDP


well-known port(0~1024) : 사람들이 자주 사용하는 포트. 21: ftp, 23: telnet, 25 : SMTP, 80 : web


Socket Address 구조체

참고주소 : http://msdn.microsoft.com/en-us/library/aa252969(VS.60).aspx

struct sockaddr_in{

    short            sin_family;

    unsigned short      sin_port;

    struct   in_addr      sin_addr;

    char               sin_zero[8];

};


sin_family : address family ( AF_INET이어야 한다. )

sin_port : 16비트 포트 번호. htons계열의 함수가 필요하다.

sin_addr : IP 주소. inet_addr함수나 htonl계열의 함수가 필요하다.

sin_zero : 사용되지 않음.


int pascal FAR bind(SOCKET s, struct sockaddr FAR *addr, int namelen);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737550(VS.85).aspx

소켓 핸들과 소켓 구조체를 연관시키고 시스템에게 묶어달라고(bind) 요청한다.

소켓과 지역(현재 컴퓨터) 주소를 연관시킨다.

리턴 : 성공시 0. 실패시 SOCKET_ERROR. 더 자세한 오류코드는 WSAGetLastError를 참고.

s : bind되지 않은 소켓을 나타내는 descriptor

name : sockaddr 구조체로부터 소켓을 지정할 주소

namelen : 바이트 단위. name 전달인자 값의 길이


int PASCAL FAR listen(SOCKET s, int backlog);

참고주소 : http://msdn.microsoft.com/en-us/library/ms739168(VS.85).aspx

포트를 감시모드로 바꾼다.

들어오는 접속에 대해 듣고 있는 상태의 소켓으로 만든다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 접속되지 않고 bind된 소켓을 나타내는 descriptor

backlog 

 - 기라디는 접속 큐의 최대 길이. (로스터에 올라간 사람 수. 최소 1이상)

 - SOMAXCONN이면 최대로 합리적인 값으로 backlog를 설정.


SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737526(VS.85).aspx

클라이언트가 올 때까지 blocking되었다가 클라이언트가 접속하면 요구를 받아준다.

소켓으로 들어오는 시도를 한 접속을 허가한다.

s : listen 함수에 의해 listen 상태인 소켓을 나타내는 descriptor

addr : 접속한 개체의 주소를 받는 버퍼의 포인터. 접속 peer 프로세스(클라이언트)의 주소를 리턴한다.

addrlen : addr 전달인자를 가리키는 구조체의 길이를 포함한다.


int pascal FAR connect(SOCKET s, struct sockaddr FAR *addr, int namelen);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737625(VS.85).aspx

특정 소켓으로 접속한다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 접속되지 않은 소켓을 나타내는 descriptor

name : 접속이 설정될 sockaddr 구조체의 포인터

namelen : name 전달인자가 가리키는 sockaddr 구조체의 길이(바이트 단위)


port to port connection

single server는 2개의 소켓을 가진다.

multi server는 n+1 개의 소켓을 가진다.


Blocked : 현실적으로 어느 코드 부분에 멈춰 있음

Blocking : 호출을 하면 정지할 가능성이 있는 코드. 오류나 결과가 나올 때까지 멈춰 있음.

예시) 윈도우즈 상에서 '응답 없음' 표시(잠재적으로 멈출 수 있는 코드 : 파일, 네트워크)


nonblocking : 호출하자마자 바로 리턴한다. 결과가 나올 때까지 반복 호출. 프로그램이 멈출 일이 없다.


asynchronous mode : 결과가 나올 때 시그널, 인터럽트, 메세지를 보내서 확인한다. 프로그램이 멈출 일이 없다. WSA계열 함수(Windows Socket Asynchronous)



 way handshake 방식을 통해 접속을 설정한다.

send() <-> recv()

socket은 패킷을 받아 buffer(수십K바이트)에 보관한다.


패킷단위

스트림단위

소켓단위(버퍼)


send buffer : send() 함수는 보낼 내용을 send buffer에 담는 역할을 한다. 프로그래머가 신경 쓸 필요가 없다.

receive buffer : recv() 함수는 receive buffer에 있는 받을 내용을 가지고(읽어) 온다.


send buffer가 꽉 차있다면 send(), write() 함수는 기다려야 한다. (blocking)

receive buffer가 비어 있는데 recv(), read() 함수는 기다려야 한다. (blocking)


int send(__in  SOCKET s, __in  const char *buf, __in  int len, __in  int flags);

참고주소 : http://msdn.microsoft.com/en-us/library/ms740149(VS.85).aspx

접속된 소켓에 데이터를 보낸다.

리턴 

성공시 len 전달인자에서 보내질 요청된 수보다 작을 가능성이 있는 보내진 바이트 수.

실패시 SOCKET_ERROR

s : 접속된 소켓을 나타내는 descriptor

buf : 보낼 데이터를 포함한 버퍼의 포인터

len : buf가 가리키는 데이터의 길이(바이트 단위)

flags : 호출하는 방법을 정의하는 집합.


int recv(__in   SOCKET s, __out  char *buf, __in   int len, __in   int flags);

참고주소 : http://msdn.microsoft.com/en-us/library/ms740121(VS.85).aspx

접속된 소켓이나 바인드된 비접속 소켓으로부터 데이터를 받는다.

리턴 : 성공시 받은 바이트 수 실패시 SOCKET_ERROR

s : 접속된 소켓을 나타내는 descriptor

buf : 들어올 데이터를 받을 버퍼 포인터

len : buf가 가리키는 데이터의 길이(바이트 단위)

flags : 함수에 행동에 영향을 줄 집합


비동기 소켓방식

버퍼의 상태를 확인해 주는 함수를 이용한다.

 


윈도우즈 비동기 소켓 방식

WSAAsyncSelect(소켓 핸들, 윈도우 핸들, 윈도우즈 user-defined message, 소켓 이벤트)

소켓 이벤트(4)가 발생하면 윈도우즈 user defined message(3)를 윈도우 핸들(2)에 보낸다.

소켓 하나에 user defined message는 하나만 등록 가능하다.

※ 취소하는 경우 : e = WSAAsyncSelect(socket, hWnd, 0, 0); 


int WSAAsyncSelect(__in  SOCKET s, __in  HWND hWnd, __in  unsigned int wMsg, __in  long lEvent);

참고주소 : http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx

소켓에 대한 네트워크 이벤트의 윈도우 기반 알림(notification)을 요청한다.

s : 이벤트 알림(notification)이 요구되는 소켓을 나타내는 descriptor

hWnd : 네트워크 이벤트가 발생할 때 메세지를 받게 될 윈도우 핸들.

wMsg : 네트워크 이벤트가 발생할 때 받게될 (사용자 정의) 메세지.

lEvent : 응용 프로그램이 관심있는 네트워크 이벤트의 조합을 나타내는 비트마스크


소켓 이벤트(lEvent)

FD_READ : receive 버퍼에 무엇인가 들어왔다.

FD_WRITE : send 버퍼에 쓸 수 있다.

FD_OOB : FD_READ의 특수한 형태.

FD_ACCEPT : 접속 요구가 들어왔다.

FD_CONNECT : 접속이 되었다. 서버와 연결에 성공하였음.

FD_CLOSE : 상대방과 socket 연결이 끊어짐.


윈도우 프로시저를 호출할 때 전달되는 인자

wParam : 소켓 식별자

LOWORD(lParam) : 발생한 이벤트 종류. WSAGETSELECTEVENT(lParam)와 같은 뜻

HIWORD(lParam) : 에러 상태. WSAGETSELECTERROR(lParam)와 같은 뜻


closesocket() : 유닉스는 소켓 닫는 함수를 close()를 쓰지만 윈도우즈는 closesocket을 사용한다.


int closesocket(__in  SOCKET s);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737582.aspx

현재 존재하는 소켓을 닫는다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 닫을 소켓을 나타내는 descriptor



출처 http://blog.daum.net/sdr1982/

'API & MFC > 네트워크프로그래밍' 카테고리의 다른 글

EventSelect란?  (0) 2010.02.05
ASyncSelect 예제  (1) 2010.02.04
소켓통신의 라이브러리 사용 선택 시 고려사항  (0) 2010.02.02
소켓함수 예제(로그인서버)  (0) 2010.01.25
OSI 모델 And Ip계층  (0) 2010.01.18
Posted by 아몰라
이전버튼 1 2 3 4 5 이전버튼