CString lRunFilName;

char lProgramPath[ 255 ];


GetModuleFileName( NULL, lProgramPath, _MAX_PATH );

lRunFilName = lProgramPath;

lRunFilName.Delete( lRunFilName.ReverseFind( '\\' ) + 1, lRunFilName.GetLength() - lRunFilName.ReverseFind( '\\' ) );

lRunFilName += "lex.exe";

'NativeCode > mfc' 카테고리의 다른 글

파일 찾기  (0) 2010.03.18
폴더 선택 다이알로그 BROWSEINFO  (0) 2010.03.18
하위 경로까지의 모든 파일 목록 얻기  (0) 2010.03.18
프로세스 찾아 죽이기  (0) 2010.03.18
하드 용량 체크  (0) 2010.03.18

#include <tlhelp32.h>


bool CH7TrayDlg::KillProcess( CString sExeName )

sExeName.MakeUpper(); 

HANDLE hSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPPROCESS, 0 ); 

if ( (int)hSnapshot != -1 ) 

PROCESSENTRY32 pe32 ; 

pe32.dwSize=sizeof(PROCESSENTRY32); 

BOOL bContinue ; 

CString strProcessName; 

if ( Process32First ( hSnapshot, &pe32 ) ) 

do 

strProcessName = pe32.szExeFile; //strProcessName이 프로세스 이름; 

strProcessName.MakeUpper(); 

if( ( strProcessName.Find("H7.EXE",0) != -1 ) ) 

HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pe32.th32ProcessID ); 

if( hProcess ) 

DWORD       dwExitCode; 

GetExitCodeProcess( hProcess, &dwExitCode); 

TerminateProcess( hProcess, dwExitCode); 

CloseHandle(hProcess); 

CloseHandle( hSnapshot ); 

return TRUE; 

return FALSE; 

bContinue = Process32Next ( hSnapshot, &pe32 ); 

} while ( bContinue ); 

CloseHandle( hSnapshot ); 

return FALSE;

}

'NativeCode > mfc' 카테고리의 다른 글

파일 찾기  (0) 2010.03.18
폴더 선택 다이알로그 BROWSEINFO  (0) 2010.03.18
하위 경로까지의 모든 파일 목록 얻기  (0) 2010.03.18
현재 위치 구하기  (0) 2010.03.18
하드 용량 체크  (0) 2010.03.18

void CDiskInfo::SearchDisk()
{
      DWORD   dwDiskInfo;
      int    i, nCount;

      InitDiskInfo();
      dwDiskInfo = GetLogicalDrives();

      for( i = 0 ; i < DISK_COUNT ; i ++ )
      {
            if( ( dwDiskInfo & m_dwDiskDriveData[i] ) != 0x0000 )
            {
                  CString  strDrive;
                  strDrive += 'A' + i;
                  strDrive += ":\\";
                  m_arrayDiskDriver.Add(strDrive);
            }
      }

      char  szDrive[MAX_PATH];
      GetLogicalDriveStrings(MAX_PATH, szDrive);
      // szDrive를 파싱하여 드라이브 목록을 얻어 올 수 있다.

      nCount = m_arrayDiskDriver.GetUpperBound() + 1;
      m_nTotalDisk = nCount;
      for( i = 0 ; i < nCount ; i ++ )
      {
            DISK_INFO_DATA  diskData;
            diskData.strDrive = m_arrayDiskDriver.GetAt(i);
            SearchDiskInfo(m_arrayDiskDriver.GetAt(i), &diskData);
            m_arrayDiskSize.Add(diskData);
      }
}


GetLogicalDirves는 현재 컴퓨터의 Dirve 목록을 DWORD의 각 비트별로 채워주는 함수 있습니다. 이부분에 대한 설명을 생략하도록 하겠습니다. 소스에 있는 GetLogicalDirveStrings가 조금 더 쉬울 수도 있습니다.

아무튼 이런 과정을 통해서 컴퓨터 내의 드라이브 전체 목록을 얻어 오고 각 드라이브 명을 C:\ 이런 식으로 저장합니다.


SearchDiskInfo를 살펴 보도록 하겠습니다.


void CDiskInfo::SearchDiskInfo(LPCTSTR lpDriver, LPDISK_INFO_DATA lpData)
{
      LONGLONG  lFreeBytesAvailable, lTotalBytes, lTotalFree;
      UINT   DiskType;
 
      DiskType = GetDriveType(lpDriver);
      lpData->diskType = DiskType;
 
      if( DiskType == DRIVE_FIXED ) // 고정 디스크(Hard Disk)일 경우만 디스크 크기를 구한다.
      {
            GetDiskFreeSpaceEx(lpDriver, (PULARGE_INTEGER)&lFreeBytesAvailable, (PULARGE_INTEGER)&lTotalBytes, (PULARGE_INTEGER)&lTotalFree);
  
            lpData->lDiskFreeSize = lTotalFree;
            lpData->lDiskSize = lTotalBytes;
      }
      else       // 플로피, 시디롬등의 용량은 0으로 한다.
      {
            lpData->lDiskFreeSize = 0;
            lpData->lDiskSize = 0;
      }
}


생각보도 간단 합니다. DIskType을 검사해서 고정디스크 인 경우만 용량을 확인 합니다. 구지 설명을 드리지 않아도 이해하실 수 있을 것 같습니다. DISK_INFO_DATA는 제가 사용하기 위해서 만든 구조체 입니다. 소스를 보시면 이해하실 수 있을 것입니다.


이렇게 컴퓨터 전체 드라이브의 용량을 조사 한 후 GUI를 통해서 보여 주기만 하면 됩니다. 제가 만든 프로그램은 GUI가 허접하니 잘 만들어 보시길 ^^

'NativeCode > mfc' 카테고리의 다른 글

파일 찾기  (0) 2010.03.18
폴더 선택 다이알로그 BROWSEINFO  (0) 2010.03.18
하위 경로까지의 모든 파일 목록 얻기  (0) 2010.03.18
현재 위치 구하기  (0) 2010.03.18
프로세스 찾아 죽이기  (0) 2010.03.18

InstallOptions 는 지정한 값을 읽을때 READ 매크로와 WRITE 매크로를 제공합니다.

문법 -

!insertmacro MUI_INSTALLOPTIONS_READ $VAR "ioFile.ini" "Field #" "Name" !insertmacro MUI_INSTALLOPTIONS_WRITE "ioFile.ini" "Field #" "Name" "Value"

아래의 스크립트는 ffdshow.ini 에서 Field 1 값의 state 값을 읽어옵니다. state 값에는 Field 1 컨트롤의 여러 상태가 저장됩니다(컨트롤이 선택되었는지 여부등). 이 값을 1(선택됨) 과 비교하여 같으면 레지스트리를 입력하고 다르면 2번째 명령으로 내려가 레지스트리 쓰기를 건너뛰게 합니다.

!insertmacro MUI_INSTALLOPTIONS_READ $R0 "ffdshow.ini" "Field 1" "State" ; XviD

StrCmp $R0 "1"  0 +2

WriteRegDWORD HKCU SoftwareGNUffdshow xvid 0x00000001

이정도면 InstallOptions 를 이용해 페이지를 추가하는데 별 문제가 없을 듯 합니다.

더 궁금한 사항이 있으시면 글 남겨주세요.


Function .onInstSuccess

!insertmacro MUI_INSTALLOPTIONS_READ $R0 "test01.ini" "Field 3" "State"

WriteRegStr HKLM "${PRODUCT_PRIMARY_KEY}" "text" "$R0"

FunctionEnd

'Programming > tool' 카테고리의 다른 글

VS2008로 작성한 프로젝트를 VS2005열기  (0) 2010.03.18
Visual Studio 2008 설정  (0) 2010.03.18
NSIS 기초지식  (0) 2010.03.18
같은 페이지에 계속 머무르기  (0) 2010.03.18
라디오버튼 컴포넌트 선택 기능 구현  (0) 2010.03.18

NSIS의 장점 :

파일크기가 작다.

거의대부분의 윈도와 호환된다.

특수한 압축방식으로 최소한의 오버헤드와 따로 자동압축풀림 기능을 사용할 필요가 없습니다.

스크립트 방식으로 인스톨러의 모든 동작을 직접 제어할 수 있습니다.

다국어를 지원합니다.

인터페이스나 대화상자를 편집할 수 있습니다.

필요한 기능은 플러그인으로 추가할 수 있습니다.

웹을 통한 설치, 패치를 지원합니다.

NSIS는 쉽게 하나의 설치마법사에 여러 프로젝트를 통합하거나 라이트, 풀 버전등을 만듭니다.


간단한 NSIS 문법:

NSIS는 기본적으로 간단한 텍스트 파일입니다.

주석 :

";", "#" 이후의 문장은 주석입니다.

/* 와 */ 사이의 문장은 주석입니다.

명령:

명령 (인자)입니다.

예) File "myfile.exe"

플러그인 : 플러그인 이름::명령 (인자)

숫자 :

10진수 - 일반적인 수

16진수 - 앞에0x를 붙입니다.

8진수 - 앞에 0를 붙입니다.

색표현 - HTML 표현방식을 따르지만 앞에 #를 붙이지 않습니다.

문자열 :

'' 와 " 를 모두 사용할 수 있습니다.

"Hi There" -> Hi There

"I''ll be happy" -> I''ll be happy

`And he said to me "I''ll be fucked!"` -> And he said to "I''ll be fucked"

NSIS는 제어문자로 $ 를 사용합니다.

변수 : 변수명 앞에 $를 붙입니다.

- 명령이 긴 경우 명령의 끝에 를 붙인 후 다음 줄에 이어서 적으면 됩니다.



NSIS - Section 이란?

NSIS에 있어서 섹션이란 매우 중요합니다.

섹션은 보통, 다른 설치마법사 제작기에서 다른 이름으로 많이 있습니다.

컴포넌트, 기능(Feature), 구성요소 등으로 말이죠.

이름만 다르고 이들과 하는 일은 같습니다.

즉, 제작자가 어떤 프로그램을 설치하려고 할때 그 프로그램을 구성하는 하나의 구성요소 라고 할 수 있습니다.

파일이 모여서 섹션이 되고 섹션이 모여서 프로그램이 되는거죠.


NSIS - Page 에 대해서...

NSIS로 만들 수 있는 설치마법사 중 대개는 화면에 뭔가 보여주면서 선택을 하게 됩니다. 당연한가요? Page에 관련된 일련의 명령들은 바로 이러한 화면을 제어합니다. 순서, 보여지는 형태, 언어, 동작 등 많은 것들을 제어합니다. 또한, NSIS에서는 NSIS에서 내장해서 자체적으로 제공하는 화면 말고 CustomPage 라고 하여 사용자가 원하는 화면을 만들어서 보여줄 수 있습니다. (InstallOptions 라는 플러그인이 있고, Codec xPack에서 ffdshow 옵션을 설정하는 화면에서 쓰였습니다.)

페이지를 다룰때는 일단 기본적으로 Page, UninstPage(설치제거용) 두가지 명령을 쓰며 Page나 UninstPage의 확장판으로 PageEx라는 명령이 있습니다.

일단 페이지를 만든다고 치면 각 페이지들의 순서를 정해야 할 것입니다. 여기서 NSIS스크립트만의 편리성이 드러납니다. NSIS 스크립트는 위에서 아래로 차례로 순차적으로 실행된다고 언급한 적이 있습니다. 즉, 배열하려는 Page 순서대로 스크립트에서 한줄씩 차례대로 적어주기만 하면 됩니다.

ex) Page license;

Page components

이렇게 적으면 NSIS는 라이센스 화면을 보여주고 다음에 컴포넌트 선택 화면을 보여줍니다.

NSIS에서 자체적으로 제공하는 페이지들.. (license, components, directory, instfiles, uninstConfirm) 입니다. instfiles는 설치/제거 모두에 쓰입니다.

또한 이렇게 순서만 정하면 재미가 없을겁니다. NSIS에서는 이렇게 순서를 정하면서 동시에 간단한 동작이나 형태를 지정해 줄 수 있습니다. 물론, 이렇게 하기위해서는 NSIS의 함수에 대해서 알아야합니다. 또한, Page, UninstPage 의 인자에 대해서도 알아야겠죠.


Page

custom [creator_function] [leave_function] [caption]OR (license|components|directory|instfiles|uninstConfirm) [pre_function] [show_function] [leave_function]

UninstPage

custom [creator_function] [leave_function] [caption]OR (license|components|directory|instfiles|uninstConfirm) [pre_function] [show_function] [leave_function]

입니다.~

질문은 밑에 적어주세요~


Sections

섹션이란 앞에서도 언급했듯이 NSIS란 설치관리자의 핵심을 이루는 것입니다. NSIS는 반드시 하나 이상의 섹션을 포함해야하며 이 섹션들은 아래와 같은 규칙하에 그 밑의 명령들로 관리됩니다.

. 각 섹션은 0개 이상의 명령을 포함합니다. (하나도 없을 수도 있습니다).

. 섹션은 설치마법사에의해 순서대로 실행되며 ComponentText 가 설정되어 있다면 사용자는 각 보이는 섹션을 선택하거나 해제할 수 있습니다.

. 만약 섹션의 이름이 ''Uninstall'' 이거나 섹션 이름앞에 ''un.'' 이라는 접두어를 붙이면 이것은 설치제거때에만 쓰입니다.



- Section Commands

AddSize size_kb

설치관리자에게 현재 섹션이 추가로 ''size_kb'' 키로바이트 만큼 필요하다고 알려줍니다. 이 명령은 오직 섹션에서만 유효합니다.

Section AddSize 500 SectionEnd


Section

[/o] [([!]|[-])section_name] [section index output]

새로운 섹션을 시작합니다. 만약 섹션이름이 빈공간이거나 - 로 시작하면 이 섹션은 숨김 속성을 가져서 사용자에게 보이지 않습니다. 만약 섹션이름이 ''Uninstall'' 이거나 ''un.''으로 시작하면 설치제거 섹션으로 사용됩니다. 섹션 인덱스 출력 변수가 설정되면 이 매개변수는 !defined 매크로에 의해 섹션 인덱스 값이 설정되고 SectionSetText 등의 관리명령에서 사용됩니다. 섹션이름이 !로 시작하면 굵은 글씨로 보이고 /o 를 설정하면 기본적으로 선택해제된 상태가 됩니다.

Section "-hidden section"

SectionEnd


Section # hidden section

SectionEnd


Section "!bold section"

SectionEnd


Section /o "optional"

SectionEnd


Section "install something" SEC_IDX

SectionEnd


SectionEnd

현재 열린 섹션을 닫습니다.


SectionIn

insttype_index [insttype_index] [RO]

이 명령은 현재 섹션이 기본적으로 속하게 될 설치유형을 설정합니다.복합적인 SectionIn 명령은 모두 합해져서 나타납니다. 만약 RO 매개변수를 지정하면 이 섹션은 읽기전용으로 사용자는 상태를 변경할 수 없습니다. 최로 설치 유형은 InstType 명령에 의해 최초 1부터 차례대로 붙어나갑니다.

InstType "full"

InstType "minimal"


Section "a section"

SectionIn 1 2

SectionEnd


Section "another section"

SectionIn 1

SectionEnd


SectionGroup

[/e] Caption [section_group_name index output]

섹셕 그룹이란 섹션들을 포함하는 섹션으로 섹션들을 보기좋게 모아서 나타날 때 사용합니다.섹션 그룹을 설정하며 반드시 SectionGroupEnd 명령으로 닫아야 합니다. 또한 반드시 하나 이상의 섹션을 포함해야 합니다. !로 이름이 시작하면 굵은 글씨체로 나타납니다. /e 를 설정하면 섹션그룹은 펼쳐져서 나타납니다. 만약 섹션이름이 ''un.''으로 시작하면 설치제거 섹션으로 사용됩니다. 섹션 인덱스 출력 변수가 설정되면 이 매개변수는 !defined 매크로에 의해 섹션 인덱스 값이 설정되고 SectionSetText 등의 관리명령에서 사용됩니다.

SectionGroup "some stuff"

Section "a section"

SectionEnd

Section "another section"

SectionEnd

SectionGroupEnd


SectionGroupEnd

섹션그룹을 닫습니다.


Uninstall Section

''Uninstall'' 이라는 특별한 섹션은 설치제거마법사를 생성하기 위해 반드시 만들어야합니다. 이 섹션에서 설치했던 파일, 레지스트리 등을 삭제합니다.

Section "Uninstall"Delete $INSTDIRUninst.exe ; delete self (see explanation below why this works)Delete $INSTDIRmyApp.exeRMDir $INSTDIRDeleteRegKey HKLM SOFTWAREmyApp SectionEnd

제일먼저 Delete 명령으로 설치제거마법사를 삭제합니다. 왜냐하면 설치제거마법사는 윈도 임시 디렉토리로 복사되어 그곳에서 실행되기 때문입니다.설치제거때 $INSTDIR 값은 설치제거마법사가 있는 곳입니다. 반드시 설치마법사가 있는 곳과 같지는 않습니다.

'Programming > tool' 카테고리의 다른 글

Visual Studio 2008 설정  (0) 2010.03.18
NSIS 값 읽어오기  (0) 2010.03.18
같은 페이지에 계속 머무르기  (0) 2010.03.18
라디오버튼 컴포넌트 선택 기능 구현  (0) 2010.03.18
사용자 페이지 추가하기  (0) 2010.03.18

ps. 같은 페이지에 계속 머무르기

이러한페이지체제는기본적으로지정한 함수에 진입해서 MUI_INSTALLOPTIONS_DISPLAY 를 호출하는 순간 화면에 페이지가 나타나고 그 함수안에서 MUI_INSTALLOPTIONS_DISPLAY 다음에 있는 명령들이 끝나면 다음 페이지로 넘어갑니다. 즉 어떤 조건이 되었을때 다시 MUI_INSTALLTOPTIONS_DISPLAY를 호출해주면 됩니다.


예)

${Do}

  MUI_INSTALLOPTIONS_DISPLAY_RETURN

pop $R0

${While} $R0 != "success"

이런식으로 하면 $R0 의 값이 "success" 가 아닌동안 게속 돕니다



원본 위치 <http://jgh0721.tistory.com/entry/InstallOptions-2-를-이용하여-사용자-페이지-추가하기

'Programming > tool' 카테고리의 다른 글

NSIS 값 읽어오기  (0) 2010.03.18
NSIS 기초지식  (0) 2010.03.18
라디오버튼 컴포넌트 선택 기능 구현  (0) 2010.03.18
사용자 페이지 추가하기  (0) 2010.03.18
실행순서  (0) 2010.03.18

NSIS - Section을 선택할 때 라디오버튼 기능을 넣자!

라디오 버튼 기능을 하려면 몇 가지 순서가 있습니다.

1. Sections.nsh 라는 NSIS에서 제공하는 섹션 관리 헤더파일 참조.

2. 섹션에 섹션인덱스 값을 부여한다.

3. .onInit 함수에 섹션의 선택값을 특정 변수에 저장한다. (주로 $1같은 변수..)

4. .selOnChange 에서 매크로를 이용하여 구현한다.



1.일단 기본적으로 Section 관련 내용을 선언해둔 파일을 집어넣어야 합니다.

!include "Sections.nsh"

이걸로 자신의 스크립트안에 섹션 관리 헤더파일을 집어넣습니다.


2.이제 섹션에 섹션 인덱스 값을 부여해야죠

예) Section "fsfds" abc

이렇게 하면 fsfds라는 섹션에 abc라는 섹션인덱스 변수를 설정한 것 입니다.

NSIS는 abc라는 섹션인덱스 변수를 통해 fsfds에 접근하는거죠

abc는 NSIS에서 쓸때는 ${abc}라고 적습니다.


3. 이제 .onInit 함수를 만듭니다.

예)

Function .onInit

StrCpy $1 ${g1o1}

FunctionEnd

만약, Section "fsfds" abc

Section "qwrqweq" qew

이렇게 두 개의 섹션을 라디오 버튼으로 만들려고 하고 이중에 abc를 기본선택으로 두려면 위와 같이 함수를 만들면 됩니다.


4. .onSelChange 함수를 만듭니다.

Function .onSelChange

!insertmacro StartRadioButtons $1

!insertmacro RadioButton ${abc}

!insertmacro RadioButton ${qew}

!insertmacro EndRadioButtons


FunctionEnd

abc와 qew라는 섹션 인덱스가 어디에 쓰였는지만 보면 쉽게 적용가능합니다.

'Programming > tool' 카테고리의 다른 글

NSIS 값 읽어오기  (0) 2010.03.18
NSIS 기초지식  (0) 2010.03.18
같은 페이지에 계속 머무르기  (0) 2010.03.18
사용자 페이지 추가하기  (0) 2010.03.18
실행순서  (0) 2010.03.18

이번엔 InstallOptions 플러그인을 사용해 인스톨러에 사용자 페이지를 추가하는 법을 알아보겠습니다.

준비물 : NSIS, HM NIS Edit

NSIS는 당연히 필요하겠구요, HM NIS Edit는 추가할 사용자 페이지를 쉽게 만들어줍니다. 그렇지 않으면 일일이 ini 파일을 직접 수정해서 좌표값 입력해 가며 만들어야합니다. OTL... 굉장한 노가다 입니다.

제가 만든 NSIS 한글 배포본에 HM Nis Edit 가 포함되어 있으니 이걸 사용하시면 됩니다.


일단 추가할 사용자 페이지를 만들어야하니 HM Nis Edit를 실행합니다.

그리고 파일 메뉴에서 인스톨옵션 파일 만들기를 선택하면 아래와 같은 화면이 나타납니다.


이제 위 화면에서 추가할 페이지의 컨트롤등을 넣어주면 됩니다.

작성하면 이제 ini 파일을 저장하고 스크립트에 페이지를 추가하는 명령을 넣으면 됩니다.


페이지를 추가하려면 세가지 과정이 필요합니다.

일단 인스톨러 초기화 콜백함수인 .onInit 함수 에서 ini파일을 임시디렉토리에 풀어줍니다.

두번째로 page 명령으로 페이지를 추가합니다.

세번째로 사용자페이지에서 사용할 함수를 작성합니다.


여기서는 예제로 저의 코덱팩 스크립트를 발췌했습니다.


1) 아래처럼 .onInit 함수에서 ini 파일을 풀어주는 매크로를 추가합니다.

(첫번째 매개변수) ${Codec}ffdshow.ini 파일은 ini파일이 있는 디렉토리이고 (두번째 매개변수) ffdshow.ini 파일은 임시디렉토리에 풀때 사용할 파일명 입니다.

Function .onInit

!insertmacro MUI_INSTALLOPTIONS_EXTRACT_AS "${Codec}ffdshow.ini" "ffdshow.ini"

FunctionEnd


2) Page 명령으로 추가합니다.

아래와 같이 Page custom 명령으로 추가할 페이지를 삽입합니다. 페이지는 순서대로 나타납니다.

여기서는 ffdshow 디코더 설정화면이 컴포넌트 선택화면 다음에 나타나게 됩니다.

custom - 사용자 페이지를 추가한다는 뜻

ffdshow - 사용자 페이지를 나타내는 등의 역할을 하는 함수 이름. 다음에 작성합니다.

!insertmacro MUI_PAGE_COMPONENTS

Page custom ffdshow ; ffdshow 디코더 설정 화면

!insertmacro MUI_PAGE_INSTFILES


3) 이제 마지막으로 ffdshow 함수를 작성합니다.

아래와 같은 형식으로 함수를 작성합니다. 함수이름은 물론 page 명령에서 지정한 이름으로 만들어야합니다. 아래 스크립트에서는 ffdshow 디코더 설정화면이기때문에 ffdshow를 설치할 때만 나타나야 합니다. 그래서 앞의 세개의 명령이 섹션 정보를 얻고 ffdshow 섹션이 선택되었을때만 페이지를 보여줍니다.


매크로 - MUI_HEADER_TEXT - 사용자 페이지의 제목입니다. 자세한 설명은 한글화한 도움말을 참조하세요.

매크로 - MUI_INSTALLOPTIONS_DISPLAY - 이 매크로를 넣지 않으면 ffdshow 함수가 호출되어도 페이지는 보여지지 않습니다. 즉, 보여줄려고 메모리상에 페이지만 만들어놓고 끝나게 되어버리지요. 이때 보여줄 페이지는 아까 MUI_INSTALLTOPTIONS_EXTRACT_AS 매크로에서 두번째 매개변수로 지정한 이름을 적습니다.

Function ffdshow

SectionGetFlags ${ffdshow} $2

IntCmp $2 ${SF_SELECTED} start end end

start:

!insertmacro MUI_HEADER_TEXT 'ffdshow decoder' 'ffdshow decoder 를 사용할 확장자를 선택하세요'

!insertmacro MUI_INSTALLOPTIONS_DISPLAY "ffdshow.ini"

end:

FunctionEnd


이렇게 하면 페이지 추가가 끝납니다.

이제 컴파일하면 페이지가 나타납니다.

이후 페이지에서 지정한 값을 받는 법등은 도움말에 나타나있습니다.


예) 위에서 사용한 ffdshow 에서 사용자 선택한 값을 읽어오는 스크립트 입니다.

'Programming > tool' 카테고리의 다른 글

NSIS 값 읽어오기  (0) 2010.03.18
NSIS 기초지식  (0) 2010.03.18
같은 페이지에 계속 머무르기  (0) 2010.03.18
라디오버튼 컴포넌트 선택 기능 구현  (0) 2010.03.18
실행순서  (0) 2010.03.18

NSIS 스크립트는 기본적으로 위에서 아래로 순서대로 실행이 된다지만 약간 헷갈리기도 합니다.

컴파일타임명령과 특히 이곳저곳에 섞이는 인스톨러 속성 명령때문이 아닌가 합니다.


--------------

컴파일 타임 명령 - 컴파일되면서 그때 그때 실행되면서 실행 인스톨러에는 영향을 미치지 않습니다.


예로 (현재 디렉토리 c: est est 이고 압축할 파일은 C: est est.exe일때)


Section -PrePare

!cd ..

File 'test.exe'

SectionEnd


이렇게 하면 컴파일러가 컴파일하면서 디렉토리를 한번 상위 디렉으로 이동해서 test.exe 를 압축합니다.


Section -PrePare

File '.. est.exe'

SectionEnd


과 같은 결과입니다. 사실상 거의 쓸일이 없습니다만...

컴파일 타임 명령은 주로 !define 명령이 사용됩니다. 컴파일 타임 명령은 인스톨 속성 명령과 달리 실행 순서가 되야 실행됩니다.


인스톨러 속성 명령

인스톨러를 초기화합니다. 컴파일러는 인스톨 속성 명령을 스크립트 전체를 분석해서 한번에 모아서 적용시킵니다. 즉, 섹션등에 포함되거나 하지만 않으면 스크립트 위치에 상관이 없습니다.

즉, 스크립트 맨위에 Name 명령있거나 맨 뒤에 Name 명령이 있거나 전혀 상관없습니다.


콜백 함수


Function .onInit

인스톨러가 실행되어 초기화가 막 끝난 시점. 보통 인스톨러가 시작되기 전 조건 검사 등을 여기서 검사합니다. (특정 프로그램을 종료시킨다거나. 등등..)


Function .onGUIInit

인스톨러 화면을 메모리에 불러들이고 보여주기 직전


섹션 또는 사용자 함수

섹션이 순서대로 진행되며 섹션에서 함수들을 호출합니다.


Function .onInstSuccess

설치가 끝나고 윈도가 닫히기 직전에 호출

대개 위와 같은 순서를 거칩니다. 중간 중간에 이벤트에 따라 아래와 같은 콜백 함수가 호출되기도 합니다.

-----------


Function .onInstFailed

인스톨 과정 중 언제든지 실패하면 호출됨


Function .GUIEnd

설치화면이 닫힌 직후에 호출됩니다. 설치 성공여부등에 전혀 상관 없습니다. 즉, 컴포넌트 페이지에서 컴포넌트 선택하다가 그냥 취소 눌러서 종료시켜도 화면이 사라질때 호출됩니다.


Function .onMouseOverSection

컴포넌트 선택화면에서 마우스 커서가 섹션위에 위치할 때 호출됩니다.


Function .onRebootFailed

인스톨 중에 Reboot 명령으로 재부팅을 시도했지만 실패하면 호출됩니다.


Function .onSelChange

컴포넌트 페이지에서 선택한 섹션이 변경되면 호출됩니다.

... 등등의 콜백함수가 있습니다. (^^)

'Programming > tool' 카테고리의 다른 글

NSIS 값 읽어오기  (0) 2010.03.18
NSIS 기초지식  (0) 2010.03.18
같은 페이지에 계속 머무르기  (0) 2010.03.18
라디오버튼 컴포넌트 선택 기능 구현  (0) 2010.03.18
사용자 페이지 추가하기  (0) 2010.03.18

WDK에서는 드라이버에서 사용하기 위한 리스트를 제공한다. 리스트 뿐만아니라

KQUEUE, KDVICE_QUEUE, IO_REMOVE_LOCK, MDL 을 제공하고 있다.

아래는 LIST_ENTRY의 사용 예이다.

Snap2.bmp


참고 사이트: http://groups.google.co.kr/group/endless-creation/web/드라이버에서+링크드+리스트+구현시+참고사항

http://www.pyrasis.com/blog/17

'Programming > WinDriver' 카테고리의 다른 글

NDIS Driver 01) 시작  (0) 2010.05.02
DDK 개발 환경 구축  (0) 2010.04.18
NDIS/TDI  (0) 2010.03.18
Lookaside list  (0) 2010.03.18
Fast I/O  (0) 2010.03.18

Heap 관리자는 메모리 블럭의 크기가 무작위로 결정되기 때문에 인접한 free 블럭을 합치기 위해 많은 CPU 시간을 요구하게 됩니다.


항상 고정된 크기의 메모리 블럭만을 사용한다면 heap을 관리하는데 있어 훨씬 효율적인 방식으로 사용이 가능한데 예를 들면

큰 메모리 블럭을 미리 할당하여, 이를 주어진 크기로 조각냅니다. 블럭이 heap에 리턴되면 실제로 해제하는 것이 아니라 사용이

끝남으로 표시하면서 사용하게 되는데, 이에 대한 몇가지 문제점이 있습니다.


너무 많은 메모리를 할당할 경우는 메모리 낭비를 가져올 수 있고, 너무 적게 할당할 경우는 알고리즘이 동작하지 않거나 더 많은 블럭을 얻으려고 heap 관리자를 너무 자주 사용하게 되는 것입니다.


Microsoft에서는 이러한 단점을 극복하기 위해 lookaside list 객체를 제공합니다.


lookaside list

  1. lookaside list 객체 초기화시 시스템에게 작업할 단위 메모리 블럭의 크기를 알립니다. ( 용량은 운영체제가 탄력적으로 감지합니다. )
  2. 메모리 블럭을 할당하기 위해서 시스템은 일단 하나의 블럭의 제거를 시도합니다.
    1. 더 이상 남은 블럭이 없다면 메모리 pool에서 빼옵니다.
  3. 메모리 블럭을 반환하려면, 시스템은 리스트에 되돌리기를 시도하게 되며, 리스트가 꽉 차면 일반 heap 관리 루틴을 사용해서 pool에 블럭을 되돌립니다.

시스템은 실제 사용에 따라 모든 lookaside list의 depth를 정기적으로 조작합니다.

  • 시스템에 최근 접근하지 않았거나, 총 시간에서 5% 이상 액세스 하지 않은 lookaside list에 대해 depth를 감소 시킵니다.
  • 처음의 새 리스트 값인 4 이하로는 줄어들지 않습니다.
  • driver verifier 실행시는 모든 lookaside list의 depth는 모두 0으로 바뀝니다. ( 메모리 오류와 관련된 드라이버 문제를 발견하기 쉽게 하기 위해서 입니다. )

Lookaside list 지원 함수

Lookaside list를 지원하는 함수는 paged / non-paged 두 분류로 나뉘게 됩니다.

  • ExInitializeNPagedLookasideList  / ExInitializePagedLookasideList : Lookaside list를 초기화 한다.
  • ExAllocateFromNPagedLookasideList / ExAllocateFromPagedLookasideList : 고정된 크기의 블럭을 할당한다.  
  • ExFreeToNPagedLookasideList / ExFreeToPagedLookasideList : 해제해서 lookaside list로 다시 돌려준다.
  • ExDeleteNPagedLookasideList / ExDeletePagedLookasideList : Lookaside list를 삭제한다.


lookaside list 객체를 위해 메모리를 확보하고 나서 적절한 초기화 루틴을 호출합니다.


각 함수에서 첫 번째 인수는 이미 공간을 확보해둔 (N)PAGED_LOOKASIDE_LIST 객체에 대한 포인터입니다. Allocate와 Free는 heap에서 메모리를 할당하거나 해제할 수 있는 루틴들에 대한 포인터 입니다. ExAllocatePoolWithTag와 ExFreePool을 쓸 시에는 이 인수들을 NULL로 하면 됩니다. blocksize 인수는 리스트에서 할당하는 메모리 블럭의 크기를 나타냅니다. tag는 이러한 각 블럭의 앞에 붙은 32비트 태그 값입니다.


리스트에서 메모리 블럭을 할당하려면 적절한 AllocateFrom 함수를 호출한다.

PVOID p = ExAllocateFromPagedLookasideList(pagelist);

PVOID p = ExAllocateFromNPagedLookasideList(nonpagedlist);

블럭을 리스트로 다시 돌리려면 적절한 FreeTo 함수를 호출하면 됩니다.

ExFreeToPagedLookasideList(pagedlist, p);

ExFreeToNPagedLookasideList(nonpagedlist, p);

마지막으로 리스트를 제거하려면 적절한 Delete 함수를 호출하면 됩니다.

ExDeletePagedLookasideList(pagedlist);

ExDeleteNPagedLookasideList(nonpagedlist);

'Programming > WinDriver' 카테고리의 다른 글

NDIS Driver 01) 시작  (0) 2010.05.02
DDK 개발 환경 구축  (0) 2010.04.18
NDIS/TDI  (0) 2010.03.18
_LIST_ENTRY  (2) 2010.03.18
Fast I/O  (0) 2010.03.18

2006/10/31 19:10


복사http://blog.naver.com/dbtalk/110010329621


Fast I/O는 Cached file을 read/write함에 있어서 IRP를 만들지 않고 가능하게 해줍니다.
 
ReadFile를 예로 들어 Fast I/O의 흐름을 설명하면 다음과 같습니다.


순서1. NtReadFile에서 요청된 data가 Cached data인지 또는 Synchronous I/O인지를 판단하여

         Yes이면 File system driver를 호출합니다.
 
순서2. File system Driver에서는 Fast I/O가 가능한지를 판단하여 가능하면 Cache manager로

          제어를 넘긴다.


순서3. Cache Manager가 실제 Data를 I/O를 요청한 Process buffer로 복사한다.
 
순서4. 만약 순서1 또는 순서2에서 조건이 만족하지 않으면 IRP를 만들어서 I/O를 수행한다.


-- 부가 설명 --


일반적으로 File system에서의 I/O 요청은 
(1) File system driver(FSD)
(2) Cache Manager
(3) Memory Manager
(4) File system driver 재 진입
(5) DISK I/O 순으로 IRP 가 처리됩니다.
 
이 과정에서 Synchronous, buffered I/O 인 경우 I/O 요청은 결국 Cache Manager가 처리하게 된다. FSD는 단지 IRP를 Cache Manger에게 전달하는 역할 뿐이다.
따라서 Fast I/O는 IRP를 생성하고 FSD를 호출하는 부담을 줄이고 막바로 Cache Manger의 service를 호출 하는 방식이다.
fast의 원래 목적인 Synchronous, Buffered I/O read/write를 지원하면서 좀 더 확장되어 여러가지 FSD 함수들도 Fast I/O로 서비스 되고 있다.

'Programming > WinDriver' 카테고리의 다른 글

NDIS Driver 01) 시작  (0) 2010.05.02
DDK 개발 환경 구축  (0) 2010.04.18
NDIS/TDI  (0) 2010.03.18
_LIST_ENTRY  (2) 2010.03.18
Lookaside list  (0) 2010.03.18

1. 새로운 테이블의 생성(CREATE TABLE)


CREATE TABLE 테이블명(

필드명 데이터타입 [NOT NULL]

{, 필드명 데이터타입 [NOT NULL]}*

[, PRIMARY KEY(필드명)]

)


ex) CREATE TABLE userdb (   

      name CHAR(8),                            //CHAR 문자수가 M개인 문자열을 뜻한다.

      id VARCHAR(10) NOT NULL,          //VARCHAR 문자수가 최대 M개인 문자열을  뜻한다.

      email VARCHAR(40),

      sex CHAR(1),

      PRIMARY KEY(id)

      )


2. 생성된 테이블의 변경(ALTER TABLE)

:생성하면서 미처 정의하지 못한 필드를 추가할수 있으며, 데이터 타입도 바꿀수 있다.

ALTER TABLE user add name VARCHAR(30)      
  //필드추가

or

CHANGE [COLUMN] 기존필드명 새필드명 필드타입        //필드속성 변경

or

ALTER TABLE user DROP [COLUMN] 필드명                //필드삭제


ex) ALTER TABLE 테이블명 ADD addr VARCHAR(100)    //주소 필드를 추가


     ARTER TABLE 테이블명 CHANGE addr address VARCHAR(255) 

    // 주소필드(addr)의 이름을 address로 수정. 또한 글자수도 최대 255자로 변경.


3. 생성된 테이블의 삭제(DROP TABLE)

DROP TABLE 테이블명


4. 데이터 검색(SELECT)


SELECT [DISTINCT] 필드명 {, 필드명}*

FROM 테이블명 {, 테이블명}*

[WHERE 조건검색]

[ORDER BY 필드명[ASC or DESC] {, 필드명 [ASC or DESC]}*]

[GRUB BY 필드명 {, 필드명}*]

[HAVING 검색조건]


ex) SELECT name, id FROM userdb WHERE level = 'B'


//테이블 userdb에서 사용자 등급이 'B'인 사용자의 레코드를 찾아서 사용자의 이름과 아이디 필드를 출력한다.


검색 중복 제거

SELECT DISTINCTlevel FROM userdb


조건 검색 (WHERE)

SELECT name, id, email FROM userdb WHERE milage > 3000 AND sex = 'M'

// 마일리지가 3천이하이고, 남자를 검색.

WHERE절에는 비교연산자 >,>=,<,<=,=와 AND,OR,NOT같은 연산자를 사용할수 있다.


검색결과의 정렬 (ORDER ~DESC or ASC)

SELECT name,id,milage FROM userdb WHERE milage >= 3000 ORDER BY milge >= 3000 ORDER BY milage DESC

//마일리지가 3천 이상인 사람의 이름, 아이디, 마일리지를 출력하되 마일리지가 높은 순으로 출력.


SELECT name, id, milage FROM userdb WHERE milage >= 3000 ORDER BY milage ASC

or

SELECT name, id, milage FROM userdb WHERE milage >= 3000 ORDER BY milage


오름차순 정렬 : ASC,  내림차순 정렬 : DESC,  명령어 없을땐 오름차순으로 정렬됨.


산술 계산  문자열 처리

SELECT name, '님의 마일리지는 ', milage, '점 입니다' FROM userdb WHERE milage >= 3000 ORDER BY milage


그룹 함수를 이용한 검색

count (필드명)      //조건을 만족하는 레코드의 개수

sum   (필드명)      //해당 필드값의 합

min    (필드명)      //해당 필드의 값중 최소값

max   (필드명)      //해당 필드의 값중 최대값

avg    (필드명)      //해당 필드의 평균값


ex) SELECT count(*) FROM user WHERE sex = 'F'

//user 테이블에서 여성사용자가 몇 명이나 되는지를 함수로 검색.

     SELECT avg(milage) FROM user WHERE sex = 'F'

//user 테이블에서 여성사용자들의 평균 마일리지 값을 출력한다.


GROUP BY를 이용한 검색

기본구조

SELECT sex, max(milage), min(milage), avg(milage) FROM 테이블명 GROUP BY sex


HAVING을 이용한 검색

: group by로 지정한 필드에 대하여 추가로 검색 조건을 지정할 때 사용한다.

기본구조

SELECT sex, max(milage), min(milage), avg(milage) FROM user GROUP BY sex HAVING sex = 'F'


BETWEEN~AND IN 연산자를 이용한 검색

: 마일리지가 3000이상 4000이하인 여자의 이름과 이메일, 마일리지, 성별을 출력한다.

SELECT name, email, milage, sex FROM user WHERE sex = 'F' AND milage BETWEEN 3000 AND 4000;


LIKE를 이용한 검색

: WHERE 조건절에서 가장 많이 사용하는 검색 조건 연산자이며 보통 LIKE 문을 사용하여 필드값의 문자열을 검색한다.

SELECT name FROM user WHERE name LIKE '%현%'

// '현'이라는 문자를 포함하는 모든 레코드를 검색한다. '현%' 은 시작문자중 검색.


NULL 값을 갖는 데이터 검색

: 특정 필드의 값이 NULL 값인 레코드를 검색하기위해 IS NULL문을 사용한다.

SELECT name, id FROM user WHERE email IS NULL


LIMIT 연산자를 이용한 검색

: 검색된 레코드의 개수를 정하여 가져오는 것.

SELECT name, id, milage FROM user LIMIT 3or 1,3 (1부터 3개의 코드를 가져온다)


5. 생성된 테이블의 변경(ALTER TABLE)

ALTER TABLE의 기본 형식

필드추가 - ADD 필드명 필드타입

필드속성 변경 - CHANGE 기존필드명 새필드명 필드타입

필드삭제 - DROP 필드명


ALTER TABLE user ADD COLUMN addr VARCHAR(100)    //생략가능하며 처음 생성시의 타입과

or                                                                                  동일하게 해야됨.

ALTER TABLE user ADD addr VARCHAR(100)


6. 새로운 데이터의 삽입 (INSERT)

INSERT INTO 테이블명 VALUES(필드값: '이현재' ,'sindee' , 639 , ...);

//문자는 작은따옴표를 사용하되 숫자는 그냥 사용.


7. 데이터의 수정 (UPDATE) : 반드시 WHERE 절로 조건을 명시해야 된다.

UPDATE use SET sex = 'F' WHERE name = '이현재'

WHERE 절로 검색 조건을 명시하지 않으면 테이블(use)내의 모든 레코드의 필드값(sex)이 새로 설정한 필드(sex)값으로 수정된다.


8. 데이터의 삭제 (DELETE) : 조건 명시 않으면 모두 삭제된다.

DELETE FROM lee2 [WHERE 검색조건]

DELETE FROM use WHERE id = '관제';

'NativeCode > SQLite Cpp' 카테고리의 다른 글

CppSQLite 사용법. (라이브러리 포함)  (0) 2010.03.18
SqlConnection  (0) 2010.03.18
SqlCommand  (0) 2010.03.18

Snap2.png


Snap1.png

'NativeCode > SQLite Cpp' 카테고리의 다른 글

CppSQLite 사용법. (라이브러리 포함)  (0) 2010.03.18
SQL Query  (0) 2010.03.18
SqlCommand  (0) 2010.03.18
  • SqlCommand 클래스

    • DB에 필요한 명령을 전달하거나 그 결과를 받아올 때 사용하는 클래스
  • SqlCommand에서 사용할 수 있는 명령들

    • 단일 값 및 레코드 셋을 반환하는 select, create, alert, drop 같은 DDL(Data Definition Language) 명령
    • grant, deny, revoke 같은 DCL(Data Control Language) 명령
    • insert, update, delete 같은 DML(Data Modification Language) 명령
  • SqlCommand 클래스 주요 함수

    • ExecuteNonQuery()

      • SQL 문을 실행하고 처리된 행의 개수를 반환
    • ExecuteReader()

      • 쿼리를 Connection에 보내고 SqlDataReader를 생성
    • ExecuteScalar()

      • 쿼리를 실행하고 쿼리에서 반환된 결과 집합의 첫 번째 행의 첫 번째 열 반환
    • ExecuteXmlReader()

      • 쿼리를 Connection에 보내고 XmlReader 객체를 생성


Snap2.png




Snap2(1).png


Snap4.png

'NativeCode > SQLite Cpp' 카테고리의 다른 글

CppSQLite 사용법. (라이브러리 포함)  (0) 2010.03.18
SQL Query  (0) 2010.03.18
SqlConnection  (0) 2010.03.18

TcpListener 생성 및 Start

  • IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
  • TcpListener tcp_Listener = new TcpListener(ipAddress, 3000);
  • Tcp_Listener.Start();
  • TcpListener 클라이언트 대기

    • TcpClient client = tcp_Listener.AcceptTcpClient();
  • 클라이언트가 접속했을 때 NetworkStream으로부터 스트림 얻어내기

    • NetworkStream ns = client.GetStream();
    • StreamReader reader = new StreamReader(ns);
  • 스트림으로부터 데이터 읽기

    • string msg = reader.ReadLine();
  • NetworkStream 으로부터 출력 스트림 생성 및 데이터 기록하기

    • StreamWriter writer = new StreamWriter(ns);
    • writer.WriteLine(msg);
    • writer.Flush();
    • writer.WriteLine(msg);
    • wirter.Flush();
  • 스트림 닫기

    • writer.Close();
    • reader.Close();
    • client.Close();

'ByteCode > C#' 카테고리의 다른 글

SmtpMail 클래스로 보내기  (0) 2010.03.19
SmtpClient 클래스로 메일 보내기  (0) 2010.03.19
IP 주소 관련 클래스  (0) 2010.03.18
TCP Socket  (0) 2010.03.18
TCP/IP Socket with C#  (0) 2010.03.18

클래스설명
IPAddress IP 주소를 나타내는 클래스
IPHostEntry 하나의 호스트에 대한 상세 정보를 제공하는 클래스
Dns 호스트 이름을 IP 주소로 변환할 때 사용하는 클래스
IPEndPoint IP 주소와 포트로 네트워크 종단점 정보를 가져 오는 클래스


  • IPAddress 클래스

C#에는 IP 주소를 처리하기 위해 IPAddress, IPEndPoint 클래스가 정의되어 있다. IPAddress 클래스는 주로 단일 IP 주소를 나타낼 때 사용한다.

IPAddress addr = IPAddress.Parse("192.168.0.1");


IPAddress 클래스는 4개의 예약 필드를 갖고 있습니다.

예약 필드명설명
Any 로컬 시스템에서 사용할 수 있는 IP 주소를 나타낼 때
Broadcast 로컬 네트워크의 IP 브로드캐스트 주소를 나타낼 때
Loopback 시스템의 루프백 주소를 나타낼 때
None 시스템에 네트워크 인터페이스가 없음을 나타낼때.



  • IPEndPoint 클래스

IPEndPoint는 로컬 주소를 바인드하거나 소켓과 원격 주소를 연결할 때 사용된다.

Snap3.png


  • IP 주소 정보 출력하기

Snap6.png

'ByteCode > C#' 카테고리의 다른 글

SmtpClient 클래스로 메일 보내기  (0) 2010.03.19
C# Socket Helper Class  (0) 2010.03.18
TCP Socket  (0) 2010.03.18
TCP/IP Socket with C#  (0) 2010.03.18
Stream, Dgram 설명  (0) 2010.03.18

Snap1.png Snap9.pngSnap10.png

'ByteCode > C#' 카테고리의 다른 글

C# Socket Helper Class  (0) 2010.03.18
IP 주소 관련 클래스  (0) 2010.03.18
TCP/IP Socket with C#  (0) 2010.03.18
Stream, Dgram 설명  (0) 2010.03.18
데이터 전송  (0) 2010.03.18
  1. TCP/IP 소켓 프로그래밍 with C#
    1. 기본 용어 해석
    2. 중요 클래스
      1. IPAddress
      2. IPHostEntry
      3. DNS
      4. TcpClient
      5. EndPoint
      6. IPEndPoint
      7. TcpListener
      8. NetworkStream
      9. UdpClient
      10. .Net Socket
      11. SocketException
    3. .NET 입출력 클래스
    4. 넌 블로킹 입출력
    5. 멀티 플렉싱
    6. 스레드
    7. 비동기 입출력
    8. 다중 수신자
      1. 브로드 캐스트
      2. 멀티 캐스트
    9. 연결 종료
    10. 버퍼 교착상태
    11. TCP 소켓 생존 주기
    12. TCP 연결 종료
    13. 디 멀티 플렉스
  2. 실무자를 위한 C# 네트워크 프로그래밍
    1. C# 프로그램 컴파일및 실행
    2. C# 프로그램 디버깅
    3. 네트워크 트래픽 관리
      1. WinPcap 드라이버
      2. WinDump
      3. Analyzer
    4. 네트워크 패킷 분석
      1. 이더넷 계층
      2. IP 계층
      3. TCP 계층
      4. UDP 계층
    5. IP 주소 정보 찾기
    6. 네트워크 상에서의 데이터 이동
    7. 프로세스
    8. 스레드
    9. 스레드 풀

TCP/IP 소켓 프로그래밍 with C#

기본 용어 해석

컴퓨터 네트워크는 통신 채널로 연결된 많은 기기들로 이루어진다. 이러한 기기들을 호스트(hosts)와 라우터(routers)라 한다.
프로토콜(protocol)이란 통신하는 프로그램 간에 주고받는 패킷의 내용과 방법에 대한 규약.
호스트 간에만 데이터를 전달하는 IP와는 달리 한 프로그램으로부터 다른 프로그램까지의 데이터 전송 전 과정을 관리하므로 TCP와 UDP는 단말간 전송 프로토콜(end-to-end transport protocol)이라고 한다.
TCP는 신뢰 가능한 바이트 스트림 채널(reliable byte-stream channel)을 제공하고 연결 기반(connection-oriented) 프로토콜이기 때문에 통신하는 두 컴퓨터의 TCP 연결이 확립되어야 한다. 이러한 연결의 확립은 통신하는 두 컴퓨터의 TCP 프로토콜 구현간에 핸드쉐이크 메시지(handshake message)를 주고 받는 것으로 이루어진다.

UDP는 이와 반대로 IP에서 발생한 문제들을 복구하려 하지 않는다. 오히려 단순한 IP의 최선형(best-effort) 데이터그램 서비스를 확장하여 어플리케이션 프로그램 간에서도 이 서비스를 이용할 수 있도록 만든다.

이름 해석 서비스(name-resolution service)는 여러 소스로부터 정보를 취합한다. 이러한 소스들 중에는 DNS(domain name system)와 로컬 설정 데이터베이스(local configuration database)가 대표적이다. DNS는 도메인 네임(domain name)을 인터넷 주소와 기타 다른 정보로 매핑하는 분산 데이터 베이스. 로컬 설정 데이터베이스는 일반적으로 운영체제 자체 시스템으로 도메인 네임과 인터넷 주소의 매핑 작업을 로컬에서 수행한다. 윈도우는 hosts텍스트 파일에 unix기반 시스템은 /etc/hosts 파일이 존재한다.

URL(universal resource locator)은 이름을 해석하여 인터넷 주소를 확인한다.
포트(port)는 IANA(Internet Assigned Number Authority)가 잘 알려진 포트(well-known port)를 지정한다.

디렉터리 서비스(directory service)는 클라이언트가 디렉터리 구조를 통해 서버가 제공하는 서비스와 서버 내부의 장소들을 열람하는 서비스.

소켓(socket)란 어플리케이션이 데이터를 주고 받을 수 있는 하나의 추상적인 통로이다. 각 소켓은 프로토콜 집합(protocol suite)과 이 집합내의 여러개의 서로 다른 프로토콜 스택(stack)을 참조하게 된다. 오늘날 TCP/IP에서 사용하는 주요 소켓은 스트림소켓(stream socket)과 데이터그램 소켓(datagram socket)이다. 스트림 소켓은 IP를 근본으로 단말간 프로토콜(end-to-end protocol)로 사용하기 때문에 안정적인 바이트 스트림 서비스를 제공한다. 데이터 그램 소켓은 역시 IP를 근본으로 한 UDP소켓을 단말간 프로토콜로 이용하기 때문에 어플리케이션에서 단일 메시지당 65,500 바이트 길이의 메시지까지 전송할 수 있는 최선형(best-effort) 데이터그램 서비스를 제공한다.

빅엔디언(big-endian)은 최상위 바이트가 가장 먼저 전송되고 최하위 바이트가 가장 나중에 전송되는 순서이다.
대부분의 네트워크 프로토콜에 쓰이는데 네트워크 바이트 오더(network byte order)라고도 한다. 그외 자바(java)와 같은 언어에도 쓰인다.
리틀엔디언(little-endian)은 최상위 바이트가 가장 나중에 전송되고 최하위 바이트가 가장 먼저 전송되는 순서이다.
윈도우 운영체제의 주요 아키텍처인 인텔, AMD, 알파 기반의 컴퓨터는 리틀 엔디언을 사용한다.

중요 클래스

IPAddress

// IP네트워크가 갖는 하나의 인터페이스에 대한 주소를 반환
public IPAddress(long address);

public static short HostToNetworkOrder?(short);
public static int HostToNetworkOrder?(int);
public static long HostToNetworkOrder?(long);
public static short NetworkToHostOrder?(short);
public static int NetworkToHostOrder?(int);
public static long NetworkToHostOrder?(long);

public static IPAddress Parse(string address);
// 도트 표기로 된 스트링 형태의 IP주소를 IPAddress인스턴스로 변환

public static readonly IPAddress Any; // 0.0.0.0
public static readonly IPAddress Broadcast; // 255.255.255.255
public static readonly IPAddress Loopback; // 127.0.0.1

IPHostEntry?

// Dns 클래스의 GetHostByName?(), GetHostByAddress?(), GetHostEntry?()로 반환되는 컨테이너 클래스
public string HostName? { get; set; }
public string[] Aliases { get; set; }
public IPAddress[] AddressList? { get; set; }

DNS

// DNS로 부터 호스트명 또는 IP주소와 관련된 정보를 수집할 수 있는 여러 정적 메소드
public static IPHostEntry
? GetHostByAddress?(IPAddress address);
public static IPHostEntry? GetHostByAddress?(string address);
public static IPHostEntry? GetHostByName?(string hostname);
public static string GetHostName?();
public static IPHostEntry? GetHostEntry?(IPAddress address);
public static IPHostEntry? GetHostEntry?(string hostname);

TcpClient?

// 소켓 하위클래스, TCP연결을 통해 다른 호스트와 접속하고, 데이터를 전송하고 수신하는데 사용되는 여러 메소드를 제공
public TcpClient?();
public TcpClient?(IPEndPoint? localEP);
public TcpClient?(string hostname, int port);

public void Close();
public void Connect(IPEndPoint? endpoint);
public void Connect(IPAddress address, int port);
public void Connect(string hostname, int port);
public NetworkStream? GetStream?();

protected Socket Client { get; set; }

public 속성으로 설정 가능한 소켓 옵션
LingerState? // 소켓의 지연시간 설정
NoDelay? // 전송이나 수신 버퍼가 꽉 차지 않을 경우 지연을 방지하는 변수값을 설정
ReceiveBufferSize? // 수신 버퍼의 크기 설정
ReceiveTimeout? // 읽기 작업시 데이터를 수신하기까지 기다리는 시간 설정
SendBufferSize? // 전송 버퍼의 크기 설정
SendTimeout? // 쓰기 작업 시작시 데이터를 송신완료까지 기다리는 시간 설정

EndPoint?

// IPEndPoint?의 추상 클래스

IPEndPoint?

// IP주소와 포트번호 형태로 TCP/IP 엔드 포인트를 나타낸다.
public IPEndPoint?(long address, int port);
public IPEndPoint?(IPAddress address, int port);

public IPAddress Address { get; set; }
public int Port { get; set; }

TcpListener?

// TCP네트워크 클라이언트로부터 들어오는 연결 요청을 대기한다.
public TcpListener?(IPEndPoint? localEP);
public TCpListener?(IPAddress address, int port);

public Socket AcceptSocket?();
public TcpClient? AccepTcpClient?();
public bool Pending(); // 수락 가능한 연결 요청 있을 경우 true
public void Start();
public void Stop();

public EndPoint? LocalEndpoint? { get; }
protected Socket Server { get; }

NetworkStream?

// Stream 클래스의 하위 클래스
public virtual void Close();
public abstract int Read(byte[] buffer, int offset, int length);
public abstract void Write(byte[] buffer, int offset, int length);

public virtual bool DataAvailable? { get; } // 스트림으로부터 읽어들일 데이터가 존재하는 경우 true

UdpClient?

public UdpClient?();
public UdpClient?(int port);
public UdpClient?(IPEndPoint? localEP);
public UdpClient?(string hostname, int port);

public void Close();
public void Connect(IPEndPoint? endpoint);
public void Connect(IPAddress addr, int port);
public void Connect(string hostname, int port);

public byte[] Receive(ref IPEndPoint? remoteEP);

public int Send(byte[] dgram, int length);
public int Send(byte[] dgram, int length, IPEndPoint? endPoint);
public int Send(byte[] dgram, int length, string honstname, int port);

protected Socket Client { get; set; }

.Net Socket

public Socket(AddressFamily?, SocketType?, ProtocolType?);
// TCP 사용시 (Address.Family.InterNetwork?, SocketType?.Stream, ProtocolType?.Tcp)

public Bind(EndPoint? localEP); // 소켓을 결합한다. IPAddress.Any(0,0,0,0)객체와 명시된 포트번호로 구성된 IPEndPoint?인스턴스를 파라미터로 받아서 로컬주소와 포트에 결합한다.
public void Close();
public Connect(EndPoint? remoteEP);
public object GetSocketOption?(SocketOptionLevel?, SocketOptionName?);
public void GetSocketOption?(SocketOptionLevel?, SocketOptionName?, byte[]);
public byte[] GetSocketOption?(SocketOptionLevel?, SocketOptionName?, int);
public void Listen(int backlog); // 연결 요청 큐의 최대 길이
public bool Poll(int microsecond, SelectMode? mode);
// 객체의 상태 확인. SelectMode?.SelectWrite? 쓰기 가능한지 확인, SelectMode?.SelectRead? 읽기 가능한지 확인, SelectMode?.SelectError? 오류 존재 여부 확인

public int Receive(byte[] buffer);
public int Receive(byte[] buffer, SocketFlags? flags);
public int Receive(byte[] buffer, int length, SocketFlags? flags);
public int Receive(byte[] buffer, int offset, int length, SocketFlags? flags);

public int ReceiveFrom?(byte[] buffer, ref EndPoint? remoteEP);
public int ReceiveFrom?(byte[] buffer, SocketFlags? flags, ref EndPoint? remoteEP);
public int ReceiveFrom?(byte[] buffer, int length, SocketFlags? flags, ref EndPoint? remoteEP);
public int ReceiveFrom?(byte[] buffer, int offset, int length, SocketFlags? flags, ref EndPoint? remoteEP);

public static void Select(IList readableList, IList writeableList, IList errorList, int microseconds);

public int Send(byte[] buffer);
public int Send(byte[] buffer, SocketFlags? flags);
public int Send(byte[] buffer, int length, SocketFlags? flags);
public int Send(byte[] buffer, int offset, int length, SocketFlags? flags);

public int SendTo?(byte[] buffer, ref EndPoint? remoteEP);
public int SendTo?(byte[] buffer, SocketFlags? flags, ref EndPoint? remoteEP);
public int SendTo?(byte[] buffer, int length, SocketFlags? flags, ref EndPoint? remoteEP);
public int SendTo?(byte[] buffer, int offset, int length, SocketFlags? flags, ref EndPoint? remoteEP);

public void SetSocketOption?(SocketOptionLevel? optionLevel, SocketOptionName? optionName, byte[] optionValue);
public void SetSocketOption?(SocketOptionLevel? optionLevel, SocketOptionName? optionName, int optionValue);
public void SetSocketOption?(SocketOptionLevel? optionLevel, SocketOptionName? optionName, object optionValue);
/*
SocketOptionLeve? 열거체
옵션이 적용될 계층을 정한다.
IP
Socket
Tcp
Udp

SocketOptionName?
http://dotgnu.org/pnetlib-doc/System/Net/Sockets/SocketOptionName.html

SocketFlags?
DontRoute? 라우팅 테이블을 사용하지 않고 전송한다.
MaxIOVectorLength? 데이터를 전송하고 수신하는데 사용할 WSABUF 구조의 개수에 대한 표준수치를 제공한다.
None
OutOfBand? 대역외(out-of-band) 데이터를 처리한다.
Partial 메시지의 일부를 전송하고 수신할 수 있다.
Peek 현재 수신중인 메시지를 확인한다.
*/

public void Shutedown(SocketShutdown? how);
// 데이터를 전송하고 수신하는 기능을 중단시킨다. SocketShutdown?.Send, SocketShutdown?.Receive, SocketShutdown?.Both

public bool Connected { get; } // 가장 최근 입출력 작업후 객체가 원격 리소스에 연결되어 있는지 나타낸다.
public EndPoint? LocalEndPoint? { get; } // 로컬 엔드 포인트를 가져온다.
public EndPoint? RemoveEndPoint? { get; } // 원격 엔드 포인트를 가져온다.

SocketException?

public override int ErrorCode? { get; } // WinSock? 2.0 에러코드와 일치한다.
public virtual string Message { get; } // 사용자가 읽을 수 있는 오류 메시지

.NET 입출력 클래스

BufferedStream? // 입출력 최적화를 위한 버퍼링을 시행
BinaryReader?/BinaryWriter? // 기본 데이터 타입의 읽기/쓰기를 처리
MemoryStream? // 메모리를 백킹 스토어(backing store)로 하는 스트림을 생성하고, 임시 버퍼와 파일 대용으로 사용할 수 있다.
Stream // 모든 스트림에 대한 기본 추상 클래스
StreamReader?/StreamWriter? // 특정 인코딩을 캐릭터 입출력을 스트림에 대해서 처리
StringReader?/StringWriter? // 특정 인코딩을 캐릭터 입출력을 스트림에 대해서 처리
TextReader?/TextWriter? // 캐릭터 입출력에 대한 기본 추상 클래스로서 StreamReader?/StreamWriter?클래스와 StringReader?/StringWriter?클래스들의 부모클래스이다.

넌 블로킹 입출력

(1) 입출력 상태를 사전에 점검
TcpClient
?클래스로부터 데이터를 읽어들이는 과정에서 NetStream?의 DataAvailable?속성이 true이면 읽을 데이터가 존재하는 것
TcpListener? 클래스로부터 Pending()메쏘드 사용하여 AcceptTcpClient?()메소드 또는 AcceptSocket?() 메소드를 호출하기 전에 연결 요청이 있는지를 점검 있으면 true.
Socket 클래스의 int타입의 Available속성을 통해 읽어들일 데이터의 존재 여부 확인. 네트워크로 부터 수신 했지만, 아직 읽어들이지 않은 데이터량을 바이트 단위의 정수로 기억. 즉 Available 속성이 0보다 클 경우 읽기 동작은 블록을 걸지 않는다.

(2) 블로킹 타임아웃 콜
Socket 클래스의 Poll()메소드. 메소드 인자의 시간 만큼 블록하여 요청을 대기한다.
Socket 클래스의 SetSocketOption?()메소드로 타임아웃(timeout)을 설정한다. TcpClient도? ReceiveTimeout? 속성을 통해 타임아웃을 설정할 수 있다.

(3) 넌 블로킹 소켓
Socket 클래스의 Blocking 속성을 false로 변경한다.

멀티 플렉싱

Socket클래스의 Select()메소드
하나이상의 입출력을 대기하는 소켓 목록을 검색한다.
IList 인터페이스형의 소켓목록중 하나 이상의 입출력이 요청되면, 실행시 소켓 목록은 입출력이 준비된 Socket으로 재구성 된다.

스레드

클라이언트 단위 스레드
스레드 풀

비동기 입출력

(1) 작업이 완료된 시점에서 호출할 콜백(callback)메소드를 지정
(2) 주기적으로 폴링(polling)하면서 메소드가 완료했는지를 확인
(3) 비동기 작업을 완료한 이후 전체가 완료되기까지 블록을 걸어 대기

.NET 프레임워크는 매우 유연한 비동기 API를 제공한다.
프레임워크 라이브러리 뿐 아니라 네트워크 입출력, 스트림 입출력, 파일 입출력, DNS룩업 메소드까지 넌 블로킹 형태로 제공한다.
사용자 메소드를 포함해 어떠한 메소드도 비동기 형태로 재구성할 수 있다. !! 이책의 점위를 넘는다-_-

비동기 입출력은
시작 콜(begin call)과 콜의 결과를 취득하기위한 완료 콜(end call)이 있다.
시작및 완료 동작은 대칭 구조를 이루고 있어 각 시작 메소드는 어디에선가 완료 메소드로 대응해야 한다. 이러한 조치를 취하지 않으면 오랫동안 실행하는 프로그램에서 마무리되지 않는 비동기 콜에 대한 상태 관리가 매우 어려워진다. 메모리 릭이나 CPU 독점과 같은 경우가 생긴다는 이야기..

NetworkStream? 클래스의 비동기 형태 Write, Read
public override IAsynResult? BeginRead?(byte[] buffer, int offset, int size, AsyncCallback? callback, object state);
public override IAsynResult? BeginWrite?(byte[] buffer, int offset, int size, AsyncCallback? callback, object state);

public override int EndRead?(IAsyncResult? asyncResult);
public override void EndWrite?(IAsyncResult? asyncResult);

AsyncCallback? ac = new ASyncCallback?(myMethodToCall?);
...
public static void myMethodToCall?(IAsyncResult? result);
{

// result.AsyncState?는 Begin메소드에서 넘겨준 object형.
// 반드시 Begin과 반대되는 형으로 End해주어야 한다. 예) EndRead?(result); // 인자로 넘어온 result가 들어가야한다. 반환값은 동기함수인 Read()메소드에서 반환하는 값과 같다.
...

}

이런 콜백외의 비동기 콜작업은 효용이 없다.

다중 수신자

일대일(one-to-one) 통신을 유니캐스트(unicast)라 한다.
일대다(one-to-many) 서비스에는 브로드캐스트(braodcast)와 멀티캐스트(multicast) 두가지가 있다.
브로드 캐스트는 모든(로컬) 네트워크 호스트가 동일한 메시지를 수신한다.
멀티 캐스트에서는 메시지가 멀티 캐스트 주소(multicast address)로 전송되고 이 메시지를 수신하고자 하는 호스트만이 네트워크를 통해 이 메시지를 수신하게 된다. 일반적으로 브로드캐스트 혹은 멀티캐스트 동작에는 UDP소켓만이 사용가능하다.

브로드 캐스트

로컬 브로드캐스트(local broadcast)주소 (255.255.255.255)는 동일한 네트워크상의 모든 호스트에 메시지를 전달한다.
이더넷(Ethernet) 네트워크 상의 한 호스트는 동일한 이너넷 상의 모든 호스트에게 메시지를 전달할 수 있지만, 메시지는 라우터에 의해서 전달되지는 않는다. IP주소 또는 직접 브로드 캐스트 주소(Direct boradcast address) 를 명시하는데 이는 해당 네트워크상의 모든 호스트에 메시지를 브로드캐스트하지만, 대부분의 인터넷 라우터는 효율의 이유로 브로드캐스트 메시지를 전송하지 않는다.

사용법은 유니캐스트와 같으며 목적지 주소를 브로드캐스트 주소로 변경하면 된다.

멀티 캐스트

멀티 캐스트는 IP설계시부터 지정된 일전 구간(224.0.0.0 ~ 239.255.255.255)의 멀티캐스트 전용구간이 있다.
유니 캐스트와 차이는 해당 주소가 멀티캐스트용이라는 점과 초기 멀티캐스트 데이터그램에 대해서 TTL(Time to Live)값을 설정해야 한다는 점 뿐이다. TTL값은 데이터가 라우터를 지날때 마다 주로 1씩 감소하며 TTL 값이 0이되면 패킷은 제거된다.

SocketOptionName?.MuilticastTimeToLive?옵션에서 TTL을 설정하며
SocketOptionName?.AddMembership?옵션과 SocketOptionName?.DropMembership?옵션과
UdpClient?의 JoinMulticastGroup?()메소드나 DropMulticastGroup?()메소드로 그룹을 가입하거나 탈퇴하여 멀티캐스트 메시지 수신이 가능하다.

그리고 SocketOptionName?.ReuseAddress?을 적용해야 호스트로부터 동시에 두 개이상의 멀티캐스트 메시지를 수신할수 있다.

연결 종료

Close()메소드를 사용해 연결을 종료할 경우 송,수신 버퍼에 남아있는 내용은 전송이 더 이상 불가하고 Exception을 발생시킨다. Shutdown()메소드를 통해 송,수신버퍼 종료 예약을 하고 송수신이 완료됨을 확인후 Close()메소드를 통해 소켓을 종료시키는게 옳다.

버퍼 교착상태

전송및 수신 큐버퍼는 자신이 동작할 수 있는 용량에 제한이 있다.
서로 Send나 Receive상태로 들어가는 경우 데드락 상태로 들어갈수 있지만...
또한 너무 큰 데이터를 순간적으로 주고 받으려 하는 경우 송, 수빈 버퍼 이상의 데이터를 가지게 되면 전송이 완료되기 전까지 블록 상태가 된다.
만약 서버와 클라이언트가 모두 이런 경우가 생긴다면 역시 서로 데드락의 경우가 발생한다.
가장 간단한 해결방법은 송 수신을 하나의 스레드가 아닌 다른 스레드를 통해 송신과 수신을 분리하여 블록 상태가 들어갔을경우 한방향으로 해결이 되도록 유도해야한다.
처음 네트워크 프로토콜을 정의할 때 부터 고려해서 설계 해야한다.

TCP 소켓 생존 주기

TCP 핸드쉐이크는 3방향 핸드쉐이크가 사용된다. 클라이언트로부터 서버로 전송하는 연결요청과 서버가 클라이언트에게 보내는 확인 응답, 그리고 클리어언트가 다시 서버에 보내는 확인 응답이다.
클라이언트의 Connect()는 두번째 핸드쉐이크가 완료될 경우에 연결 확립이 된다. 서버의 Accept*()의 경우 원래 소켓과는 다른 새로운 소켓을 생성하여 세번의 핸드쉐이크가 완료되면 연결이 확립되고 원래의 소켓은 다시 클라이언트를 대기하게 된다.

TCP 연결 종료

전송 버퍼에 데이터가 남아있는데 그대로 프로그램을 종료할 경우 프로그램이 알지 못하는 상황에서 데이터 손실이 생긴다.
Shutdown()이나 Close()를 통해 종료 핸드쉐이크 교환후 종료해줘야한다.
프로토콜 설계시 Close()메소드를 먼저 호출하는 쪽에서 데이터 수신 여부를 확인후 종료 메소드를 호출하여 Shutdown(옵션)을 통해 Receive, Send를 하나씩 종료해주면 된다.

SocketOptionName?.Linger 은 Close()메소드가 종료 핸드쉐이크를 완료되기를 대기하면 반환하지 않는 시간을 제어한다. 타임아웃을 초단위로 설정한다.

TCP연결을 종료하는데 있어 시간 대기 상태(Time-Wait State)가 있다.
소켓 종료후 네트워크상 똑같은 소켓으로 다시 생성이 되어 전송을 하여 이전 소켓으로 전송된 데이터가 네트워크상 딜레이 있을 경우 어느 소켓에서 발생된 데이터인지 오인이 생길수 있다.
이 대기 시간(quiet time)은 구현에 따라 다르게 설정되는데 적게는 30초에서 4분까지가 된다.(패킷이 네트워크상 존재할 수 있는 최대 시간의 두배)
윈도우는 4분이 기본값이다.
문제는 같은 포트로 소켓을 생성할 수 없다는 점이다. ErrorCode? 값이 10048에 해당하는 Exception을 발생시킨다.

디 멀티 플렉스

실무자를 위한 C# 네트워크 프로그래밍

C# 프로그램 컴파일및 실행

C# 컴파일러
csc (C Sharp Compiler)
커맨드 옵션
/out:filename
/main:classname
/target:target(winexe, dll, module, ...)
/debug : type (실행중인 프로세스에 디버거를 붙이는 기본(full)형식 또는 디버깅 툴에서 접근할 수 있는 .pdb형식인 pdbonly
/resource : resource

C# 프로그램 디버깅

컴파일시 실행파일에 속성변수를 설정함으로 CLR JIT컴파일러로 하여금 코드를 추적하게 만들고, 이로써 디버거에서 참고할 추적 정보를 기록할 프로그래머 데이터베이스(PDB : Programmer DataBase?) 파일을 생성하게된다.
여기서 설정되는 속성 변수는 JITTracking 플래그라 부른다. 이 플래그는 컴파일러로부터 생성된 네이티브 코드를 MSIL명령어로, 또 이 명령어를 결국 원래의 소스 코드로 디컴파일해야 한다는 정보를 CLR JIT컴파일러에 전달한다. 이 모든 정보는 실행 파일에 대한 PDB 파일에 저장된다.

dbgclr (GUI 디버거)
visual studio와 유사한 형식

cordbg (커맨드라인 디버거)
s 소스 코드 한 개 라인을 실행
si 소스 코드 한 개 라인을 실행
so 소스 코드 한 개 라인을 건너뜀
ss 다음 네이티브 또는 IL 명령을 실행
p <arg> 변수 현재 값을 출력
pro 프로그램 실행에 대한 시스템 프로세스 정보를 출력
reg 현재 쓰레드에 대한 CPU 레지스터 정보 출력
run <prog> 디버거에서 prog 프로그램을 실행
break 소스에 브레이크지점 설정 또는 출력
sh 현재 실행중인 코드 라인과, 전후 5개 라인을 출력

IL DASM(Microsoft Intermediate Language Disassembler)

네트워크 트래픽 관리

WinPcap? 드라이버

Politecnico di Torino 의 NetGroup?팀이 개발한 모든 윈도우즈 시스템에서 네트워크 패킷을 수집할 수 있도록 설계.

WinDump?

커맨드 라인 옵션
-a 네트워크와 브로드캐스트 주소를 네임으로 변경
-B size 수신 버퍼 크기를 size로 수정
-c count 패킷을 count만큼만 수집
-D 시스템에서 사용가능한 모든 네트워크 인터페이스를 표시
-e 각 출력줄에 링크 레벨의 정보를 출력
-F file File 파일에 정의된 필터를 적용
-i interface interface네트워크를 모니터링 하는데, interface는 인터페이스 이름 혹은 ?D 명령어로 지정된 인터페이스 번호가 될 수 있다.
-n 주소를 이름으로 변화하지 않도록 설정
-N FQDN(Fully Qualified Domain Name)을 출력하지 않도록 설정
-q 간단한 형태로 패킷 정보를 출력
-r file 덤프 파일 file로부터 패킷을 읽어들임
-S 절대 TCP일련 번호를 출력
-s snaplen 패킷으로 부터 snaplen 만큼의 바이트를 수집. 기본 수치는 68이다.
-t 각 라인에 시간을 출력하지 않음
-w file 결과를 file에 출력
-X 각 패킷을 hex형태와 ASCII형태로 출력
-x 각 패킷을 hex형태로 출력

필터 조건문 적용
windump ip // 네트워크에 흐르는 ip패킷만을 수집
windump ip host 203.241.228.251 // 특정 ip주소로부터 오가는 네트워크 패킷 수집
windump ip src 203.241.228.251 // 특정 ip주소로부터 오는 네트워크 패킷 수집
windump ip host 203.241.228 // 특정 서브넷으로부터 오가는 패킷 수집

Analyzer

GUI사용. 사용 권유.

네트워크 패킷 분석

네트워크 패킷 구성

이더넷 헤더 | IP 헤더 | TCP 헤더 or UDP 헤더 | DATA

이더넷 계층

이더넷 헤더(Ethernet header)는 이더넷 802.2, 이더넷 802.3 그리고 이더넷 버전 2의 세가지 종류의 이더넷 패킷이 있따.
이더넷 802.2, 이더넷 802.3은 IEEE 표준 프로토콜로서 이더넷 계층의 트래픽을 위해서 정의되었다.
이더넷 버전 2는 표준 프로토콜은 아니지만, 이더넷 네트워크에서 가장 흔하게 쓰이는 레거시(legacy) 프로토콜이다. 원도우즈 시스템을 포함해서 거의 모든 장치들은 기본적으로 IP패킷을 전송하는데 이더넷 2프로토콜을 사용한다.

이더넷 헤더
6바이트 길이의 목적지 이더넷(혹은 MAC) 주소 // 3바이트의 벤더 식별자, 또는 OUIO(Orgranizationally Unique Identifier) 와 3바이트 길이의 벤더만의 고유 장치 일련 번호. IANA(Internet Assigned Numbers Authority)가 각 벤더의 MAC주소를 지정.
6바이트 길이의 소스 이더넷(혹은 MAC) 주소
2바이트 길이의 다음 계층 프로토콜 식별자 // IP는 0800
46에서 1500바이트 길이의 데이터 요약 정보(data payload) // 최소 46바이트야 최소 이더넷 의 길이가 64바이트로 맞춰진다.
4바이트 길이의 체크섬(checksum)

IP 계층

IP필드 비트 설명
Version 4 IP헤더 버전 형식(현재 버젼은 4)
Header Length 4 IP 패킷 헤더의 길이(단위 : octet)
Type of Service 8 패킷에 적절한 서비스 품질([BadWikiTag]Qulity of Service) 종류 (실시간 서비스가 많아 짐에 따라 높은 품질을 설정하기도 한다.)
Total Length 16 IP패킷 전체의 길이(단위 : octet)
Identification 16 IP패킷의 고유 식별 ID
Flags 3 패킷의 분할(fragmentation) 여부 및 추가 단편 존재 여부를 나타내는 플래그(항상0의값의 Reserved 플래그|IP패킷이 분할되지 않았다는 것을 나타내는 Don't Fragment(DF)플래그|IP패킷이 분할되었으며, 다른 분할된 단편들이 도착할 것임을 나태내는 More Fragment(MF)플래그)
Flagment offset 13 IP패킷 내의 분할/ 단편의 위치
Time to Live(TTL) 8 패킷이 네트워크 내에서 소멸하지 않고 유지될 수 있는 최고 시간(단위 : 초)
Protocol 8 다음 데이터 계층의 프로토콜 타입 (1:ICMP, 2:IGP, 6:TCP, 8:EGP, 9:CiscoIGP, 17:UDP, 99 CiscoEIGRP)
Header Checksum 16 IP헤더 데이터에 대한 체크섬
Source Address 32 소스 장치의 IP주소
Destination Address 32 목적지 장치의 IP주소
Options 가변 IP패킷 속성을 나타내는 기타 필드

주소 필드

하이비트 네트워크 주소 호스트 주소 타입
0 7비트 24비트 클래스A
10 15비트 16비트 클래스B
110 21비트 8비트 클래스C
1110 0비트 28비트 클래스D

DDN(Dotted Decimal Notaion)으로 표현하면

Class A 0.x.x.x - 127.x.x.x
Class B 128.x.x.x - 191.x.x.x
Class C 192.x.x.x - 223.x.x.x
Class D 224.x.x.x - 254.x.x.x
클래스 D는 두개 부분으로 나뉜다.
IP멀티 캐스트 주소 224.x.x.x - 239.x.x.x
실험적 네트워커 240.x.x.x - 255.x.x.x

TCP 계층

중요한 기능
장치 간에 복수 연결 세션 추적 (소스포트와 목적지 포트)
패킷 오더(순서)의 추적과 잃어버린 패킷에 대한 재전송 요청(일련 번호및 승인 번호)
두 장치간의 연결 스트림을 열고 닫는 기능(TCP플래그)

TCP 필드 비트 설명
Source Port 16 소스 장치 포트 번호(바인딩 하지 않을 경우 임의의 번호로 지정된다.)
Destination Port 16 목적지 장치의 포트 번호
Sequence Number 32 처음 연결되면(Syn bit = 1)을 보내면 차례로 증가한다. (단위 : octet)
Acknowledge number 32 Ack 비트가 1로 set되어있을때, 송신부가 보내야 수신부의 예측값. 즉 향후 송신부에서 보내야할 일련번호에 대한 수신부에서 예측하는 의미. 수신부의 Acknowledge number에서 송신부에서 보낸 초기 일련번호를 빼면 수신부에서 지금까지 받은 TCP데이터의 전체 길이 값을 가지게된다. 물론 올바른 데이터 전송 가정하에 공식이다.
DataOffset? 4 TCP헤더의 길이. 단위는 4 octet (32비트)단위로 offset을 곱해주면 실제 헤더의 길이가 된다. 한마디로 HeaderLength?. 옵션을 사용하지 않으면 5 (즉 octet은 4bit.. 5*4=20.. 바로 TCP헤더 크기)
Reserved 6 예약된 공간
Contorol Bits 6 연결, 연결 해제, 데이터, 응답 등에 대한 정보를 갖는다. 각각 1비트에 해당한다.

U(URG) : Urgent pointer valid flag A(ACK) : Acknowledgement number valid flag. 송신부에 응답할 때 set P(PSH) : Push flag. TCP 데이터가 송신될 때 set R(RST): Reset connection flag. 연결이 끊김(강제)을 나타낼 때 set S(SYN): Synchnonize sequence flag. 연결을 시도하고자 할 때 set F(FIN): End of data flag. 연결을 끊을 때 set
Window 16 수신부에서 현재 수신할 수 있는 TCP 데이터의 갯수. 운영체제 설정마다 다르다.(단위 : octet)
Checksum 16 체크섬
Urgent Pointer 16 URG Flag가 1로 세팅되어있을 경우. UrgentData?의 마지막 시퀀스 정보를 갖는다.
Option 가변 표준 TCP헤더에 없는 정보를 전송할때 쓰임

TCP 세션은
Opening handshake

Session communication

Closing handshake

TCP 연결 상태

CLOSED 세션이 비활성이다.
LISTEN 장치는 특정 포트에서 수집할 데이터를 대기한다.
SYN-SENT 장치는 SYN플래그를 전송하여 세션을 시작하였으며, 원격 장치에서 이를 확인하고 SYN플래그를 재전송 할 것을 대기 중이다.
SYN-RECEIVED 장치는 SYN플래그를 수집하였으며, SYN플래그와 ACK플래그를 다시 전송하여 세션을 시작할 것을 확인하고 원격 장치로 부터 ACK플래그를 대기중이다.
ESTABLISHED 두 장치 모두 opening handshake 절차를 완료했으며 서로간에 데이터 패킷을 전송 할 수 있다.
FIN-WAIT-1 장치에는 FIN플래그를 전송하여 세션을 종료하고자 한다.
FIN-WAIT-2 장치에는 FIN플래그를 수집했고, FIN플래그와 ACK플래그를 전송했다.
LAST-ACK 장치는 FIN플래그를 수집하여 응답으로 FIN플래그를 전송했고, 원격 장치로부터 ACK플래그를 대기중이다.
TIME-WAIT LAST-ACK 상태 이후 장치는 원격 장치에서 추가적인 데이터 전송하지 않는지를 확인한 뒤 정식으로 세션 포트를 닫을 수 있도록 약간의 대기 시간을 갖는다.

UDP 계층

IP통신에 자주 사용되는 또 하나의 하이레벨 프로토콜이다. TCP와는 달리 UDP는 데이터를 전송하는 네트워크 장치간에 비연결(connectionless) 전송경로가 있어
세션 확립 플래그와 연결 상태 등과 관련된 오버헤드가 그다지 많지 않다. (TCP헤더 20바이트, UDP헤더 8바이트) 각 UDP세션은 일방향으로 전송되는 단 한개의 패킷에 지나지 않는다.

UDP 필드 비트 설명
Source Port 16 소스 장치 포트 번호(바인딩 하지 않을 경우 임의의 번호로 지정된다.)
Destination Port 16 목적지 장치의 포트 번호
Payload Length 16 데이터 내용의 길이
CheckSum? 16 체크섬

IP 주소 정보 찾기

1. IPConfig 사용
2. 레지스트리 사용
3. WMI 사용 (Windows Management Instrumentation)

마이크로소프트가 구현한 Web-Based Enterprise Management(WBEM)의 한종류 이다. WBEM은 Distributed Management Task Force. Inc(DMTF) 에서 개발한 것으로 네트워크 환경에서 시스템 정보를 접근하는 표준
윈도우 2000이후, 지원하고 이전 윈도우즈는 WMI Software Developers Kit 를 통해 WMI 시스템을 별도로 설치 할 수 있다. (
http://www.microsoft.com/downloads/search.asp?로 부터 다운)

WMI 내에 있는 WMI Win32_NetworkAdapterConfiguration? 표는 시스템에서 설치된 네트워크 장치와 관련된 정보를 기록하고 있다.

필드 설명
DefaultIPGateway 장치에 할당된 IP 라우터 주소의 어레이
Description 네트워크 장치에 대한 설명
DHCPEnabled 장치가 동적으로 IP주소를 할당하는지의 여부
DHCPServer IP 주소를 할당하기 위해 사용되는 DHCP 서버
DNSHostName? 호스트명을 확인하는데 사용되는 DNS 호스트
IPAddress 장치에 할당된 IP주소의 어레이
IPEnabled 장치가 네트워크 상에서 IP를 사용하는지의 여부
IPSubnet 장치가 사용하는 IP서브넷 주소의 어레이
MACAddress 네트워크 장치에 할당된 이더넷 MAC 주소


using System.Management; 
...
ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'TRUE'");
ManagementObjectCollection queryCollection = query.Get();
foreach(ManagetmentObject mo in queryCollection)
{
...
Console.WriteLine( (string[])mo["IPAddress"] );
}

네트워크 상에서의 데이터 이동

C# 바이너리 데이터 타입

데이터 타입 바이트 설명
sbyte 1 -128 ~ 127 까지의 signed 정수
byte 1 0 ~ 255 까지의 unsigned 정수
short 2 -32,768 ~ 32,767 까지의 signed 정수
ushort 2 0 ~ 65,535 까지의 unsigned 정수
int 4 -2,147,483,648 ~ 2,147,483,647 까지의 signed 정수
uint 4 0 ~ 4,294,967,295 까지의 unsigned 정수
long 8 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 까지의 signed 정수
ulong 8 0 ~ 18,446,744,073,709,551,615 까지의 unsigned 정수
float 4 1.5 * 10^-45 ~ 3.4 * 10^38 까지의 7자리의 유효숫자를 갖는 부동소수
double 8 5.0 * 10^-324 ~ 1.7 * 10^308 까지의 15~16자리의 유효숫자를 갖는 부동소수
decimal 16 1.0 * 10^-28 ~ 7.9 * 10^28 까지의 28~29자리의 유효숫자를 갖는 부동소수

BitConverter? Class

public static byte[] GetBytes([TYPE] value); // 특정 타입을 바이트 배열로 반환 
public static [TYPE] To[TYPE](byte[] value, int startIndex); // 바이트를 특정 타입으로 변환

// string형은 Encoding 클래스의 Encoding.ASCII.GetString()함수 사용

Buffer Class // 기본 형식 배열을 조작

public static void SetByte(Array array, int index, byte value); // 배열 특정 위치의 값을 변경 
public static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count); // 배열의 블록 단위 복수

프로세스

Process class

public static Process GetCurrentProcess(); 

public static Process[] GetProcesses(); // 실행중인 프로세스 전부를 찾는다.

public static Process GetProcessById(int); // 실행중인 프로세스 찾기
public static Process[] GetProcessesByName(string); // 실행중인 프로세스 찾기

public static Process Start(string); // 오버로드 되어있음. 프로그램 이름으로 실행하는 방법외에 인자 넣을수도 있고 ProcessStartInfo 클래스에 정보 채워서 실행 가능.
public void Kill(); // 프로세스 강제 종료
public bool CloseMainWindow(); // 메인 윈도우에 닫기 메시지를 전송하여 종료를 권유. 메인 윈도우가 없거나 모달 대화상자일경우 실패하기도 한다.
public void Close(); // 프로세스 종료. 강제 종료가 아니라 연결된 리소스 전부를 해제후 종료.

스레드

Thread class

Process 클래스의 속성을 통해 Collection을 얻어온다. 
public ProcessThreadCollection Threads {get;}

public Thread(ThreadStart start); //스레드 생성자 델리게이트형 ThreadStart를 요구한다. 

public delegate void ThreadStart(); // 실행할 스레드 메소드를 지정한다.

public void Start();

public Thread(ParameterizedThreadStart start); // ParameterizedThreadStart로 등록하면  

[ComVisibleAttribute(false)]
public delegate void ParameterizedThreadStart(Object obj);

public void Start(Object state); // 스레드에 Object형 매개변수를 전달할 수 있다.

스레드 풀

ThreadPool? class
작업 항목 게시, 비동기 I/O 처리, 다른 스레드 대신 기다리기 및 타이머 처리에 사용할 수 있는 스레드 풀을 제공합니다.

생성자가 없고 모든 메소드는 정적이다.
메소드가 호출되면 운영체제는 자동으로 스레드 풀을 생성하고 25개의 스레드가 등록 가능한 상태가 된다.
타이머 큐 타이머와 등록된 대기 작업도 스레드 풀을 사용된다.
타이머 큐 타이머와 등록된 대기 작업의 콜백 함수는 스레드 풀에 대기하게 된다.
스레드 풀에 있는 스레드에서 작업 항목을 처리하도록 요청하려면

public static bool QueueUserWorkItem(WaitCallback callBack); 
public static bool QueueUserWorkItem(WaitCallback callBack, Object state);

[Serializable]
public delegate void WaitCallback(object state);

사용예)
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc,state));

를 호출하여 사용하게된다. 작업항목을 큐에 대기시킨 후에는 취소할 수가 없다.

이하 시스템 프로그래밍 관련 부분...

// 제한 시간(밀리초)에 부호 있는 32비트 정수를 사용하여 WaitHandle을 기다리는 대리자를 등록합니다. 
public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle, WaitOrTimerCallback, object, int, bool);

// WaitHandle 클래스
공유 리소스에 대한 단독 액세스를 기다리는 운영 체제 관련 개체를 캡슐화합니다

PythonPowered EditText of this page (last modified 2008-11-05 11:01:00)
FindPage by browsing, searching, or an index
Or try one of these actions: DeletePageDeleteUploadedFileLikePagesSpellCheckUploadFile

'ByteCode > C#' 카테고리의 다른 글

IP 주소 관련 클래스  (0) 2010.03.18
TCP Socket  (0) 2010.03.18
Stream, Dgram 설명  (0) 2010.03.18
데이터 전송  (0) 2010.03.18
파일 송수신  (0) 2010.03.18

Socket Programming

-------
소켓
-------
소 켓 이란? 두 프로그램이 네트워크를 통해 서로 통신을 수행 할 수 있도록 양쪽에 생성 되는 링크의 단자이다. 두 소켓이 연결되면 서로 다른 프로세스끼리(프로세스가 원격에 있든지 로컬에 있든지 상관 없다.) 데이터를 전달 할 수 있다. 결국 소켓이 구현됨으로써 네트워크 및 전송 계층의 캡슐화가 가능해 졌다.

소켓은 원래 캘리포니아 버클리 대학 분교에서 UNIX 용으로 개발 되었으며 유닉스에서의 입출력 메소드의 표준인 개방/읽기/쓰기/닫기 메커니즘을 따른다.

-------
소켓 형식
-------
1.        스트림 소켓
스 트림소켓은 양방향으로 바이트 스트림을 전송 할 수 있는 연결 지향형 소켓으로 양쪽 어플리케이션이 모두 데이터를 주고 받을 수 있다는 것을 의미 한다. 스트림소켓은 오류수정, 전송처리, 흐름제어 등을 보장 해 주며 송신된 순서에 따른 중복되지 않은 데이터를 수신 하게 된다. 이 소켓은 각 메시지를 보내기 위해 별도의 연결을 맺는 행위를 하므로 약간의 오버헤드가 존재 한다. 그러므로 소량의 데이터 보다는 대량의 데이터를 보내는 경우에 적당 하다. 스트림소켓은 이러한 품질의 통신을 수행 하기 위하여 TCP 프로토콜을 사용 한다.

2.        데이터그램 소켓
명시적으로 연결을 맺지 않으므로 비 연결형 소켓이라고 한다. 메시지는 대상 소켓으로 전송되며 대상 소켓은 메시지를 적절히 수신 한다. 스트림 소켓을 사용하는 것이 데이터그램 소켓을 사용 하는 것 보다 더 신뢰성이 높은 방법이지만 연결을 수립하는데 드는 오버헤드는 무시 할 수 없다. 데이터그램 소켓을 사용하려면 클라이언트에서 서버로 데이터를 전송 할 때 UDP를 사용 한다. 이 프로토콜에서는 메시지의 크기에 약간의 제한이 있으며 메시지의 확실 한 전달 역시 보장 하지 않으며 통신 중 데이터를 잃어 버리더라도 오류를 되돌리지 않는다.
3.        Raw 소켓
Raw 소켓은 패킷을 가져오면 TCP/IP 스택상의 TCP, UDP 계층을 우회하여 바로 애플리케이션으로 송신하는 소켓이다. 이런 소켓에서 패킷은 TCP/IP 필터를 통해 전달 되지 않으므로 원형 그대로의 패킷을 볼 수 있다. 이는 모든 데이터를 적절히 처리하거나 헤더를 제거하고 이를 파싱 하는 과정은 모두 수신 애플리케이션에서 담당해야 하는 것이다. 실제 Raw 소켓을 이용하여 프로그래밍을 하는 일은 거의 드물며 만약 시스템 소프트웨어나 패킷을 분석하는 프로그램을 개발 시에는 필요 할 수도 있다. 즉 Raw Socket은 저수준 프로토콜 애플리케이션을 작성 할 때 주로 사용 된다고 보면 된다.


---------
포트
---------
여 러 개의 애플리케이션들이 동시에 통신을 수행하기 위하여 포트가 정의 되는데 기본적으로 포트는 IP 주소 표기를 확장 하는 개념 이다. 네트워크에서 패킷을 수신하는 애플리케이션이 동시에 실행 되고 있는 컴퓨터로 연결을 맺을 때 송신자가 알고 있는 수신 애플리케이션의 고유 포트 번호를 이용하여 대상 프로세스를 식별 하는 것이다.

소켓 번호는 컴퓨터의 IP 주소와 TCP 애플리케이션에서 사용하는 포트 번호로 이루어져 있다. IP주소는 인터넷 상에서 유일 하고 포트 번호는 개별 컴퓨터에서 유일하기 때문에 전체 인터넷에서 소켓 번호 또한 유일 한 것이다.

-----------------------
.NET 에서 소켓 다루기
-----------------------
System.Net.Sockets 네임스페이스의 클래스들은 .NET에서 지원하는 소켓들을 제공 한다.

System.Net.Sockets.MulticastOption : IP 멀티캐스트 그룹에 참여 하거나 탈퇴하기 위한 IP 주소 값을 설정 한다.

System.Net.Sockets.NetworkStream : 데이터를 주고 받는 하위 스트림을 구현 한다. 이는 TCP/IP 통신 채널에 대한 연결을 나타내는 고수준 추상형이다. 이 클래스를 이용하여 네크워크 소켓을 통해 데이터를 주고 받을 수 있다. NetworkStream은 버퍼 기능이 지원되지 않으므로 BufferedStream을 중간 저장 매체로 함께 사용 하기도 한다.
System.Net.Sockets.TcpClient : Socket 클래스를 기반으로 하여 작성 되었으며 고수준 TCP 서비스를 제공하여 준다.

System.Net.Sockets.TcpListener : Socket 클래스를 기반으로 작성 되었으며 서버 애플리케이션에서 사용 한다.이 클래스는 들어오는 클라이언트의 연결을 리스닝 하며 애플리케이션에게 연결된 요청을 알려 준다.

System.Net.Sockets.UdpClient : UDP 서비스를 구현하기 위한 클래스

System.Net.Sockets.SocketException : 소켓에서 오류가 존재할 때 발생하는 예외

System.Net.Sockets.Socket : 소켓 애플리케이션의 기본 기능을 제공 한다.


------------------------
System.Net.Sockets.Socket
------------------------
Socket 클래스는 네트워크 프로그래밍에서 중요한 역할을 담당 하는데 클라이언트와 서버 사이의 모든 동작을 수행 한다.윈도우 소켓 API의 해당 하는 메소드로 매핑 된다.

아래는 몇 가지 속성 이다.

AddressFamily : 소켓의 주소 계열을 획득, Socket.AddressFamily 열거형의 값 이다.
Available : 읽을 수 있는 데이터 량을 Return
Blocking : 소켓이 블로킹 모드 인지 확인
Connected : 소켓이 원격 호스트에 연결 되어 있는 지
LocalEndPoint : 로컬 종점을 돌려 줌
ProtocolType : 소켓의 프로토콜 형식을 돌려 준다.
SocketType : 소켓의 타입을 돌려 준다.

아래는 몇 가지 메소드 이다.
Accept() : 들어오는 연결을 다루기 위한 새로운 소켓을 생성
Bind() : 들어오는 연결을 리스닝 하기 위하여 소켓을 로컬종점으로 연결
Close() : 소켓을 종료
Connect() : 원격 호스트에 연결을 맺는다.
Listen() : 리스닝 상탸로 만든다, 이것은 서버 소켓에서만 사용 된다.
Receive() : 연결된 소켓으로부터 데이터를 수신 한다.
Send() : 연결된 소켓으로 데이터를 송신 한다.
Shutdown() : 소켓에 대한 연결을 비 활성화 한다.

----------------------

Server Socket 작성 하기

----------------------

1. 소스 코드를 작성 하기 전에 우선 전체적인 코드를 개략적으로 이해 하기로 하자 .

우선 서버의 입장에서 로컬 종점을 생성 한다 . 리스닝을 위한 소켓을 열기 전에 로컬 종점 주소를 작성 해야 하며 서비스에 대한 종점을 생성 하기 위해 호스트의 IP 주소와 서비스의 포트 번호를 조합하여 TCP/IP 서비스의 고유 주소를 정의 한다 . Dns 클래스는 로컬네트워크 기기에서 지원하는 네트워크 주소에 대한 정보를 되돌려 주는 메소드를 제공 한다 . 로컬 네트워크 기기가 하나 이상의 네트워크 주소를 가지거나 로컬 시스템이 하나 이상의 네트워크 기기를 지원 한다면 Dns 클래스는 모든 네트워크 주소에 대한 정보를 되돌려 주며 애플리케이션은 아 배열에서 적절한 주소를 선택해야 한다 .

// 소켓에 사용할 종점을 설정

IPHostEntry ipHost = DNS.Resolve(“localhost”);

IPAddress ipAddr = ipHost.AddressList[0];

IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

2. 다음은 Socket 클래스의 새로운 인스턴스를 이용하여 스트림소켓을 생성 한다 . 이미 리스닝에 사용 할 로컬 종점을 작성 하였으므로 바로 소켓을 생성 할 수 있다 .

//TCP/IP 소켓을 생성

Socket sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

AddressFamily 열거형은 Socket 인스턴스가 주소를 해석 하기 위해 사용하는 주소 스키마를 나타낸다 . 몇 가지 값들은 아래와 같다 .

AddressFamily.InterNetwork : IP 버전 4 주소

AddressFamily.InterNetwork V6: IP 버전 6 주소

AddressFamily.Ipx : IPX/SPX 주소

AddressFamily.NetBios: NetBios 주소

SocketType 은 TCP 와 UDP 소켓을 구분 하는데 이용 가능한 값은 아래와 같다 .

SocketType.Dgram : 데이터그램을 지원 , Dgram 은 Udp ProtocolType 과 AddressFamily.InterNetwork 와 함께 사용되어야 한다 .

SocketType.Raw : Raw Socket

SocketType.Stream : 스트림 소켓을 지원 , Stream 은 Tcp ProtocolType 과 AddressFamily.InterNetwork 와 함께 사용되어야 한다 .

세번째 파라미터 , 네번째 파라미터는 소켓에 필요한 프로토콜 형식을 정의 한다 . 그 값은 아래와 같다 .

Raw : Raw 패킷 프로토콜

Tcp : TCP

Udp : UDP

Ip : Internet Protocol

•  다음 단계는 Bind() 메소드를 사용하여 소켓에 이름을 부여 한다 . 생성자를 이용하여 소켓을 개방하면 소켓에 아무런 이름도 할강되어 있지 않다 . 즉 Bind() 메소드를 통해 소켓을 Local 종점에 연결 시키는 것이다 .

try {

sListener.Bind(ipEndPoint);

•  이제 소켓이 생성 되었고 , 이름이 바인딩 되었으므로 Listen() 을 사용하여 들어오는 연결에 대해 리스닝을 수행 할 수 있다 . 이때 파라미터에는 큐에 대기중인 연결의 최대 개수를 지정 한다 .

sListener.Listen(10);

•  위에서 리스닝을 했으므로 이젠 Accept() 를 이용하여 클라이언트의 연결을 수신하여 클라이언트와 서버의 이름 연결을 완료 한다 . Accept() 메소드는 대기중인 요청 큐로 부터 먼저 들어온 연결을 가지고 와 이를 처리할 새로운 소켓을 생성 한다 . 새로운 소켓이 생성 되었다고 하더라도 원래 소켓은 계속 리스닝을 수행 하므로 복수의 클라이언트 요청을 처리하기 위해서는 멀티쓰레드를 사용 한다 .

while(true) {

...

Socket handler = sListener.Accept();

•  Send(), Receive() 메소드를 이용하여 데이터를 보내고 , 받는다 .

string data = null;

while(true) {

byte[] bytes = new byte[1024];

// 클라이언트로부터 수신된 데이터

int byteRes = handler.Receive(byte);

// 바이트를 문자열로 변환

data += Encoding.Default.GetString(bytes, 0, byteRec);

// 메시지의 끝인지 확인

if (data.IndexOf(“”) > -1) {

break;

}

}

•  루프를 빠져 나온 후 클라이언트에게 응답을 돌려주기 위해 새로운 바이트 배열을 준비 한다 . 변환을 마친 후 Send() 메소드를 이용하여 데이터를 보내자

string theReply = “Thank you for those ” + data.Length.ToString() + “ characters …”;

byte[] msg = Encoding.Default.GetBytes(theReply);

handler.Send();

•  서버와 클라이언트의 데이터 교환이 끝나면 Close() 를 이용하여 소켓을 종료 한다 . 항상 Close() 를 하기 전에 Shutdown() 을 이용하여 남아 있는 데이터를 확실히 제거 하자 . 각 소켓 인스턴스 마다 Close() 메소드를 호출 해야 한다 .

handler.Shutdown(SocketShutdown.Both);

handler.Close();

SocketShutdown 값은 열거형으로 아래와 같은 값을 취한다 .

Both : 송 . 수신용 소켓 모두

Receive : 수신용

Send : 송신용 소켓

소스 코드는 아래와 같다 .[SocketServer.cs]

using System;

using System.Net.Sockets;

using System.Net;

using System.Text;

public class SocketServer

{

public static void Main (string [] args)

{

// establish the local end point for the socket

IPHostEntry ipHost = Dns.Resolve("localhost");

IPAddress ipAddr = ipHost.AddressList[0];

IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

// create a Tcp/Ip Socket

Socket sListener = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

// bind the socket to the local endpoint and

// listen to the incoming sockets

try

{

sListener.Bind(ipEndPoint);

sListener.Listen(10);

// Start listening for connections

while (true)

{

Console.WriteLine("Waiting for a connection on port {0}",ipEndPoint);

// program is suspended while waiting for an incoming connection

Socket handler = sListener.Accept();

string data = null;

// we got the client attempting to connect

while(true)

{

byte[] bytes = new byte[1024];

int bytesRec = handler.Receive(bytes);

data += Encoding.ASCII.GetString(bytes,0,bytesRec);

if (data.IndexOf("") > -1)

{

break;

}

}

// show the data on the console

Console.WriteLine("Text Received: {0}",data);

string theReply = "Thank you for those " + data.Length.ToString()

+ " characters...";

byte[] msg = Encoding.ASCII.GetBytes(theReply);

handler.Send(msg);

handler.Shutdown(SocketShutdown.Both);

handler.Close();

}

}

catch(Exception e)

{

Console.WriteLine(e.ToString());

}

} // end of Main

}

----------------------

Client Socket 작성 하기

----------------------

1. 클라이언트 코드가 서버와 다른 점은 Connect() 메소드 부분이다 . 이것은 클라이언트가 원격의 서버에 연결 하고자 할 때 사용하는 메소드 이다 . 사용하기 위해서는 우선 원격 종점을 설정 해야 한다 .

// 소켓에 사용할 원격 종점을 설정

IPHostEntry ipHost = DNS.Resolve(“127.0.0.1”);

IPAddress ipAddr = ipHost.AddressList[0];

IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

sender.Connect(ipEndPoint);

Connect() 메소드로 소켓을 종점 파라미터로 지정된 원격 호스트와 연결을 맺는다 . 일단 연결이 이루어 지면 데이터를 보내고 받을 수 있다 .

string theMessage = “This is a test”;

byte[] msg = Encoding.Default.GetBytes(theMessage+””);

// 소켓을 이용하여 데이터를 보냄

int bytesSend = sender.Send(msg);

// 원격으로부터 ( 서버 ) 응답을 수신

int bytesRec = sender.Receive(bytes);

이젠 마지막으로 Shutdown() 을 호출하여 소켓을 해제 한다 . 그리고 Close() 하자

sender.Shutdown(SocketShutdown.Both);

sender.Close();

[ 아래는 SocketClient.cs 의 소스 파일 이다 .]

using System;

using System.Net.Sockets;

using System.Net;

using System.Text;

public class SocketClient

{

// If you specify any text as a command-line argument, it will be sent to the server.

// e.g. SocketClient "Send this text" will send that string

// If no command-line arguments are specified, a default string is sent

public static void Main (string [] args)

{

// data buffer for incoming data

byte[] bytes = new byte[1024];

// connect to a Remote device

try

{

// Establish the remote end point for the socket

IPHostEntry ipHost = Dns.Resolve("127.0.0.1");

IPAddress ipAddr = ipHost.AddressList[0];

IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

Socket sender = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

// Connect the socket to the remote endpoint. Catch any errors

sender.Connect(ipEndPoint);

Console.WriteLine("Socket connected to {0}",

sender.RemoteEndPoint.ToString());

//string theMessage=Console.ReadLine();

string theMessage;

if (args.Length==0)

theMessage = "This is a test";

else

theMessage = args[0];

byte[] msg = Encoding.ASCII.GetBytes(theMessage+"");

// Send the data through the socket

int bytesSent = sender.Send(msg);

// Receive the response from the remote device

int bytesRec = sender.Receive(bytes);

Console.WriteLine("The Server says : {0}",

Encoding.ASCII.GetString(bytes,0, bytesRec));

// Release the socket

sender.Shutdown(SocketShutdown.Both);

sender.Close();

}

catch(Exception e)

{

Console.WriteLine("Exception: {0}", e.ToString());

}

}

}

'ByteCode > C#' 카테고리의 다른 글

TCP Socket  (0) 2010.03.18
TCP/IP Socket with C#  (0) 2010.03.18
데이터 전송  (0) 2010.03.18
파일 송수신  (0) 2010.03.18
DataList에 그림 출력  (0) 2010.03.18
  • 데이터를 전송하기 위해서는 데이터의 길이를 먼저 알아내야 한다.
  • 데이터를 보낼때는 아래와 같은 순서로 이루어 진다.
  • 1) 데이터를 바이트 배열로 바꾸기
  • 2) 바이트의 길이를 알아내기
  • 3) 길이를 다시 바이트 배열로 바꾸기.

Snap1.png

  • 데이터를 수신 받기 위해서는 데이터의 길이를 먼저 알아야 한다.
  • 데이터를 받을때 아래와 같은 순서로 한다.

    • 1) 데이터의 크기를 받는다.
    • 2) 그 크기만큼 데이터를 받는다.
    • 3) 데이터를 원하는 데이터로 바꾼다.

Snap9.png

'ByteCode > C#' 카테고리의 다른 글

TCP/IP Socket with C#  (0) 2010.03.18
Stream, Dgram 설명  (0) 2010.03.18
파일 송수신  (0) 2010.03.18
DataList에 그림 출력  (0) 2010.03.18
Control.ControlCollection  (1) 2010.03.18

Snap1.png

'ByteCode > C#' 카테고리의 다른 글

Stream, Dgram 설명  (0) 2010.03.18
데이터 전송  (0) 2010.03.18
DataList에 그림 출력  (0) 2010.03.18
Control.ControlCollection  (1) 2010.03.18
Multi Delegate  (0) 2010.03.18

<ItemTemplate> 추가 후 <asp:Image> 컨트롤 추가

Snap2.png


DataList 데이터 바인딩

Snap3.png


DataList에 ItemDataBound 이벤트 추가

Snap4.png


이벤트 함수 구현

Snap1.png


'ByteCode > C#' 카테고리의 다른 글

데이터 전송  (0) 2010.03.18
파일 송수신  (0) 2010.03.18
Control.ControlCollection  (1) 2010.03.18
Multi Delegate  (0) 2010.03.18
Delegate(대리자)  (0) 2010.03.18

Snap1.png

왼쪽 그림 처럼 여러개의 버튼이 있을때 한 함수에서 이벤트를 전부 사용할 수 있다.

Control.ControlCollection 클래스는 모든 컨트롤이 상속을 받는base class 이므로

모든 클래스의 인스턴스를 대입하는 것이 가능하다.

이 클래스의 인스턴스를 만든 후 this.Controls 를 통해 이 폼의 모든 컨트롤의 인스턴스를 대입하고 foreach를 이용 원하는 Control 을 찾아 낼 수 있다. Snap3.png

Snap2.png원하는 Control 을 찾을 때는 옆의Tag를 조사하여 찾는다고 한다.

'ByteCode > C#' 카테고리의 다른 글

파일 송수신  (0) 2010.03.18
DataList에 그림 출력  (0) 2010.03.18
Multi Delegate  (0) 2010.03.18
Delegate(대리자)  (0) 2010.03.18
Get/Set Property  (1) 2010.03.18
  • Multi Delegate의 구현

    • Multi Delegate를 구현하는 방법은 += 를 이용해서 Delegate를 여러개 추가해 주기만 하면 된다. 호출 하는 방법은 일반 Delegate와 같으며, Delegate를 호출하면 등록된 모든 Delegate가 순서대로 호출된다.
  • 하나의 Delegate에 다른 Delegate를 추가, 삭제하는 방법.

    • 추가하려는 함수를 담고 있는 객체를 += 연산자를 사용해서 등록.
    • 추가한 함수를 제거할 때는 -= 연산자를 사용해서 제거.
    • 멀티 Delegate를 사용할 때 함수는 반드시 void를 반환해야 함.

Snap9.png

'ByteCode > C#' 카테고리의 다른 글

DataList에 그림 출력  (0) 2010.03.18
Control.ControlCollection  (1) 2010.03.18
Delegate(대리자)  (0) 2010.03.18
Get/Set Property  (1) 2010.03.18
Exception  (0) 2010.03.18
  • Delegate(대리자)란

    • 함수를 보다 효율적으로 사용하기 위해서 특정 함수 자체를 캡슐화하는 기능을 갖고 있다.
  • Delegate의 해석

    • 함수의 포인터를 편리하게 사용하는 방법을 제공.
    • Safe Type Method Pointer
    • Method의 Pointer를 C#에서는 Delegate라는 형식을 빌어 사용할 수 있게 해준다.
    • 함수를 Delegate라는 것에게 관리하게 하고 함수의 반환형과 매개변수 등의 안정성을 보장받는다.

Snap9.png



  • Delegate를 위한 함수

    • Delegate는 함수에 대한 대리자이다. 그렇기 때문에 일반 함수든 스태틱 함수든 상관없이 함수의 형만 정확하다면 Delegate로 해당 함수를 호출 할 수 있다.

Snap9(1).png


'ByteCode > C#' 카테고리의 다른 글

Control.ControlCollection  (1) 2010.03.18
Multi Delegate  (0) 2010.03.18
Get/Set Property  (1) 2010.03.18
Exception  (0) 2010.03.18
Attribute  (1) 2010.03.18

Snap3.png

'ByteCode > C#' 카테고리의 다른 글

Multi Delegate  (0) 2010.03.18
Delegate(대리자)  (0) 2010.03.18
Exception  (0) 2010.03.18
Attribute  (1) 2010.03.18
Event  (1) 2010.03.18

  Exception(1).pngException2(1).png

'ByteCode > C#' 카테고리의 다른 글

Delegate(대리자)  (0) 2010.03.18
Get/Set Property  (1) 2010.03.18
Attribute  (1) 2010.03.18
Event  (1) 2010.03.18
Invoke 개념 이해하기  (0) 2010.03.18
  • Dllimport Attribute

Dllimport는 윈도우 api를 사용할 때 주로 사용된다.

[DllImport("user32.dll")]

public static extern int MessageBox(int hWnd, string lpText, string lpCaption, int uType);

'ByteCode > C#' 카테고리의 다른 글

Get/Set Property  (1) 2010.03.18
Exception  (0) 2010.03.18
Event  (1) 2010.03.18
Invoke 개념 이해하기  (0) 2010.03.18
파일 관리  (0) 2010.03.18

C# 이벤트를 만들어 사용하려면 다음 단계를 따라야 합니다.

1) 델리게이트를 만들거나 지정합니다.

2) 다음을 포함하는 클래스를 만듭니다.

  • 델리게이트에서 만든 이벤트
  • event 키워드를 사용하여 선언된 델리게이트의 인스턴스가 있는지 확인하는 메서드
  • 이벤트를 호출하는 메서드


3) 매서드를 이벤트에 연결하는 클래스를 하나 이상 정의합니다.

  • += 및 -=연산자를 사용하여 하나 이상의 메서드를 기본 클래스의 이벤트에 연결
  • 이벤트에 연결되는 메서드의 정의


4) 다음과 같이 이벤트를 사용합니다.

  • 이벤트 선언을 포함하는 클래스 객체를 작성
  • 사용자가 정의한 생성자를 사용하여 이벤트 정의가 포함된 클래스 개체 작성.

'ByteCode > C#' 카테고리의 다른 글

Exception  (0) 2010.03.18
Attribute  (1) 2010.03.18
Invoke 개념 이해하기  (0) 2010.03.18
파일 관리  (0) 2010.03.18
디렉토리 관리  (0) 2010.03.18

+ Recent posts