본문 바로가기
코스웨어/10년 시스템제어

[시스템 제어]5월 18일 6번 김 신 호

by 알 수 없는 사용자 2010. 5. 19.
728x90
반응형
                C++

리눅스 명령어

su - 아이디              $ 로 바꿔줌
su                         아이디 현재설정유지 하면서 $로 바꿔줌
ctrl + D                   $ 상태에서 # 으로 바꿔준다

usr/include             pcab 헤더  있는곳
usr/inlcude/linux     if_ether.h  ,  ethernet.h  있는곳


1. 개요


Ethernet Protocol Type 이란 이더넷 패킷내의 데이터부분에서 캡슐화된 데이터가 어느 프로토콜에 해당하는지를 나타내고자,  13~14번째 바이트에 이를 표시하는 영역을 말한다.


2. 이더넷 프레임의 통상적인 형식 : IEEE 802.3 또는 DIX 2.0


- Preamble(10101...) 및 SFD(10101011) : 10101......10101011
- D A : Destination Address, S A : Source Address    ☞  MAC 주소
- Len/Type : 0x 600 이상이면 Type (DIX 2.0), 이하이면 Length (802.3) 로 해석
         . Length : 길이(3~1500 바이트)를 나타냄           ☞  MTU
         . Type   : Data에 담겨있는 상위 프로토콜          ☞  Ethertype


 - Type의 대표적인 값들 (0x600 이상의 값 만이 가능함)

     0600h                Xerox XNS IDP
    0800h            IP
     0805                  X.25
     0806h            ARP
     0835h                RARP
     6003h                DEC DECnet Phase Ⅳ
     8137h                Novell Netware IPX
     8191h                NetBIOS
     8847h                MPLS 
     8863h                PPPoE Discovery Stage
     8864h                PPPoE PPP Session Stage


4. 각 프레임의 형태



5. 참고사항

   ㅇ 위 프레임들 간의 주요한 차이는,
      MAC 부계층 바로 상위계층인 LLC 부계층 관련 부분(3 바이트)의 포함 여부에 있
      다.  (DIX Ethernet frame : 미포함, IEEE 802.3 frame : 포함)

  ㅇ 각 바이트별 비트들의 송신 순서
     - 이더넷 프레임의 각 바이트의 비트들은 FCS를 제외하고, 모두 LSB 부터 송신된다.


이더넷 프로토콜 타입에 대한 정보가 패킷내에 존재한다. 이것은 아래의 그림과 같은 모습의 구조를 띄고 있다.

위의 소스를 실제로 돌려봤을 때 다음과 같은 화면을 볼 수 있다. (리눅스에서 구동한 것이다.)


위의 프레임 구조에서 봤듯이 붉은 본홍색으로 표시된 부분은 도착지의 MAC address이며,
녹색으로 표시된 부분은 출발지의 MAC address이다.
 이를 ifconfig 명령어로 확인해보면 출발지의 값이 다음과 같이 동일하다는 것을 알 수 있다.


도착지 다음의 2바이트는 이더넷 타입을 나타내는 0x0800은 IP를 뜻한다.

소스는 다음과 같다.

#include <stdio.h>
#include <pcap/pcap.h>

char errbuf[PCAP_ERRBUF_SIZE];
void HexaView(const void *,int );
#pragma pack(1)

#pragma pack 이란?!

/*
실제 데이타와 구조체 사이즈를 비교해 보면 구조체 사이즈가 크다.
음 언급했듯이 운영체재의 환경에 따라 packing 되어 있는 크기가 있기 때문이었다. 만약 운영체재에서 packing 된 값이 4 Byte 라고 한다면, char 자료형도 1 Byte가 아닌 4 Byte를 잡고 들어간다. 3 Byte 만큼이 더 커진 것이다. 물론 int 자료형이면, 4 Byte 값이 들어가겠지만, 특정 자료형이 5 Byte 면. 우선 4 Byte 크기를 잡고 나머지 1 Byte 를 잡아주기 위해서 4 Byte 다시 잡아준다.
그래서 5 Byte 자료형은 8 Byte 만큼의 크기를 갖게 되는 것이다.
이런 문제를 막아주기 위해서 #pragma pack(push, 1) 또는 #pragma pack(1) 를 사용하면 운영체재에서 packing 되어진 값이 아닌 1 Byte 씩 자르기 때문에 char  자료형은 4 Byte 가 아닌 1 Byte 가 되고, 5 Byte 형 자료형도 8 Byte 가 아닌 5 Byte 가 된다.
*/


struct ether_header
{
   unsigned char ether_dhost[6];  /* destination eth addr */
   //u_int8_t => 1바이트 ,[ETH_ALEN]=6 그러므로 1*6=총 6바이트

   unsigned char ether_shost[6];  /* source ether addr    */
   //u_int8_t => 1바이트 ,[ETH_ALEN]=6 그러므로 1*6=총 6바이트

   unsigned short ether_type;             /* packet type ID field */
   //u_int16_t => 총 2바이트
 };

int main()
{
    char *nicName;
    pcap_t *stpHandle;
    const u_char *ucData;
    struct pcap_pkthdr stInfo;
    //패킷을 건져 올리 때의 시간 같은 정보를 StInfo로 넘겨준다.
    struct ether_header *stpEth;

    nicName=pcap_lookupdev(errbuf);    

// char
* pcap_lookupdev(char * errbuf);
// pcap_lookupdev : 장치를 찾아 장치명알아낸다
// 현재 연결된 네트워크 장비를 찾아 해당 장비의 장비명을 리턴하며 인자로 에러를 처리할 버퍼의
// 주소를 넘긴 다. 위 함수를 통해 얻은 장치명은 pcap_open_live 함수를 통해서 장치로부터 오는
// 패킷을 캡쳐할수 있다


    printf("%s\n",nicName);
   
    if(0==nicName)
    {
        printf("[%s] 네트워크 디바이스를 찾을수가 없습니다",errbuf);
        return 0;
    }
   
    stpHandle=pcap_open_live(nicName, 1500,1,0, errbuf);

   // pcap_t * pcap_open_live(char * device,int snaplen,int promisc,int to_ms, char * ebuf);
 // 장치읽기위해 열 때 사용하는 함수,
// 열린 장치는 
pcap_close()함수를 이용해서 반드시 닫아 주어야 한다..
// 첫 번째 인자는 읽어올 장치의 장치명이며 pcap_lookupdev함수를 통해 얻은 값을 넣어준다.
// 두 번째 인자는 읽어들일 패킷의 최대 크기
// 세 번째 인자는 패킷을 읽어들일 방식을 설정하는 값이며 1로 설정하게되면
// 조건없이 모든 패킷을 읽어들인다.
// 네 번째 인자는 패킷이 오기 까지의 대기시간을 나타내고 0으로 주면 패킷을 올때까지 무기한 기다린다.
// 마
지막 인자는 에러를 처리할 버퍼의 주소이다 

    if(0==stpHandle)
    {
        printf("[%s] 네트워크 디바이스를 열 수가 없습니다",errbuf);
        return 0;
    }

    ucData=pcap_next(stpHandle,&stInfo);

    // 열린 장치로부터 패킷을 읽어 들일 때 사용하는 함수는 다음과 같다.
    //  패킷을 건져 올린다.
    //  패킷 시작점의 주소가 UcData로 넘겨준다.
   // 
pcap_next 함수는 pcap_open_live 함수를 통해 리턴된 장치ID인 p를 넘겨 캡쳐한
  // 패킷의 기본정보를 h 에 담아주고 해당 패킷의 데이터를 리턴하게된다.
  // 열린 장치로 부터 패킷이 오길 기다리다 패킷이 도착하면 캡쳐한다.
  // (대기 시간및 캡처 방식은 장치를 열대 설정)
  // u_char * pcap_next(pcap_t * p,struct pcap_pkthdr
* h) 

    HexaView(ucData,stInfo.len);
    stpEth=(ether_header*)ucData;

    printf("Destination: %02X %02X %02X %02X %02X %02X \n",stpEth->ether_dhost[0],stpEth->ether_dhost[1],stpEth->ether_dhost[2],stpEth->ether_dhost[3],stpEth->ether_dhost[4],stpEth->ether_dhost[5]);
 
    printf("Source: %02X %02X %02X %02X %02X %02X \n",stpEth->ether_shost[0],stpEth->ether_shost[1],stpEth->ether_shost[2],stpEth->ether_shost[3],stpEth->ether_shost[4],stpEth->ether_shost[5]);
  
    char *j;
    j=(char*)&stpEth->ether_type;   // 하나하나의 주소를 찍기 위해서 포인터 j 선언 하였다
    printf("Protocol: %02X %02X\n",*j,*(j+1));   // 08  00  찍힘!
    pcap_close(stpHandle);
    return 0;
}

#pragma pack(4)

실행 화면이다 . 실행하고 인터넷을 켜게 되면 다음과 같이 나온다



 C++에서의 문자열과 +오퍼랜드의 재정의





   인라인 함수와 함수포인터 예제 




                 A P I 

컨트롤

컨트롤 : 사용자와의 인터페이스를 이루는 도구이고 하나의 윈도우 라고 한다. 곧 입출력 도구를 뜻한다.

표준 컨트롤 : 버튼, 에디트 ,리스트 박스, 콤보 박스, 스크롤 바, 스태틱 



①  버 튼

LRESULT OnCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
 CreateWindow(TEXT("button"),TEXT("Clik_Me"),WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,20,20,100,25,hWnd,(HMENU)0,g_hInst,NULL);

 // WS_CHILD | WS_VISIBLE -> 버튼은 child이고 화면에 출력하겠다 => 공통적으로 들어 가는 옵션
 // BS_PUSHBUTTON -> 푸시 버튼
 // 20,20,100,25 ->윈도우의 위치와 크기  => 좌상단 (20,20)에 위치 하며 폭은 100, 높이는 25 픽셀이다.
 //  hWnd ->컨트롤의 부모 윈도우 지정 => 메인 윈도우의 핸들(hWnd)
 // (HMENU)0 -> 윈도우에서 사용할 메뉴의 핸들
 // g_hInst -> 윈도우를 만드는 인스턴스 핸들
 // NULL -> 사용자 정의 데이터 => CHILD 컨트롤을 만들 때에는 이 인수를 사용하지 않는다.

 CreateWindow(TEXT("button"),TEXT("Me Two"),WS_CHILD | WS_VISIBLE | S_PUSHBUTTON,20,50,100,25,hWnd,(HMENU)1,g_hInst,NULL);
 CreateWindow(TEXT("button"),TEXT("Exit"),WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,20,80,100,25,hWnd,
(HMENU)2,g_hInst,NULL);
 
 return 0;
}
LRESULT OnCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
         switch(LOWORD(wParam))
          {

  case 0:
          MessageBox(hWnd,TEXT("First Button Clicked"),TEXT("Button"),MB_OK);
          break;
  case 1:
         MessageBox(hWnd,TEXT("Second Button Clicked"),TEXT("Button"),MB_OK);
         break;
  case 2:
         DestroyWindow(hWnd);
         break;
         // 윈도우를 종료시킨다
 }

 return 0;
}
LRESULT OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
      return 0;
}
LRESULT OnPaint(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
       HDC hdc;
       PAINTSTRUCT ps;
       hdc=BeginPaint(hWnd, &ps);
       EndPaint(hWnd,&ps);
       return 0;
}
LRESULT OnDestroy(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
       PostQuitMessage(0);
       return 0;
}

실 행 화 면 이 다.



② 체 크 박 스

푸쉬버튼은 사용자로부터 명령을 받아들이기 위해 사용하는데 비해 체크박스는 참, 거짓의

진위적인 선택을 입력받을 때 주로 사용된다.

옵션의 개수에 따라 두 가지 상태로 나뉜다.

BS_CHECKBOX  :  두 가지 상태를 가진다.  (선택 /  비선택)
BS_3STATE : 세 가지 상태를 가진다.   (선택 / 비선택 / Greayed[알수 없음])

동작 방법에 따라 두가지로 나뉜다.

자동 체크 박스 : 스스로 체크 상태를 바꾼다
                       상태를 조사하기만 하면 될 경우 사용

수동 체크 박스 : 선택 / 비선택 상태를 부모 윈도우가 직접 바꾸어야 한다.
                       체크 박스의 상태가 변경될 때마다 어떤 처리를해야 하고 체크 조건이 복잡한 경우 사용

체크 박스 소스는 다음과 같다

#include "MsgProc.h"

HDC hdc;
PAINTSTRUCT ps;
static HWND c1,c2,c3,c4;
static BOOL bEllipse = FALSE;

LRESULT OnCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)
{

 c1=CreateWindow(TEXT("button"),TEXT("Draw Ellipse?"),WS_CHILD | WS_VISIBLE | BS_CHECKBOX,20,20,160,25,hWnd,(HMENU)0,g_hInst,NULL);
 c2=CreateWindow(TEXT("button"),TEXT("Good Bye Message?"),WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,20,50,160,25,hWnd,(HMENU)1,g_hInst,NULL);
 c3=CreateWindow(TEXT("button"),TEXT("3State"),WS_CHILD | WS_VISIBLE | BS_3STATE,20,80,160,25,hWnd,(HMENU)2,g_hInst,NULL);
 c4=CreateWindow(TEXT("button"),TEXT("Auto 3State"),WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,20,110,160,25,hWnd,(HMENU)3,g_hInst,NULL);

            return 0;
}
LRESULT OnCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)
{

 switch(LOWORD(wParam))
 {

 case 0:

  if(SendMessage(c1,BM_GETCHECK,0,0)==BST_UNCHECKED)
 //  BM_GETCHECK(함수 실행 함으로써 현재 체크 상태를 알려달라고 한다),
//   0(wParam),0(lParam)
// 그 체크 상태가 체크가안되어 있을때


  {
   SendMessage(c1,BM_SETCHECK,BST_CHECKED,0);
   // wParam에 BST_CHECKED 를 넣어 보낸다.
   // 즉 체크 해달라고 명령한다.

   bEllipse = TRUE;
   // 원을 그리위한 조건식 선언

  }

  else
  {

   SendMessage(c1,BM_SETCHECK,BST_UNCHECKED,0);
   // 이 조건식에 들어 왔다는건 지금 현재 체크박스가 체크가 되어 있기 때문에
   // 체크 박스에 wParam에 BST_UNCHECKED 넣어 주어 체크를 풀게 명령한다.
   
   bEllipse = FALSE;
   // 사각형을 그리위한 조건식 선언

}

  InvalidateRect(hWnd,NULL,TRUE);
  //WM_PAINT 함수 발생

  break;

 case 2:

  if(SendMessage(c3,BM_GETCHECK,0,0)==BST_UNCHECKED)
  {
         SendMessage(c3,BM_SETCHECK,BST_CHECKED,0);
  }
  // 3STATE 값이 체크가 안되어 있을 때
  // 부모윈도우는 BM_GETCHECK 함수를 이용하여 체크 상태를 질문하고
  //  BM_SETCHECK 함수를 이용하여 체크 상태로 변경하라고 명령한다.

  else if(SendMessage(c3,BM_GETCHECK,0,0)==BST_INDETERMINATE)
  {
         SendMessage(c3,BM_SETCHECK,BST_UNCHECKED,0);
  }
       // 3STATE 값이 체크가 Grayed 값을 가질때
      // 체크를 풀라고 명령한다.
  else
  {
          SendMessage(c3,BM_SETCHECK,BST_INDETERMINATE,0);
  }
         // 그렇지 않을 때의 값은 현재 체크가 되어 있는 상태이므로
         // Grayed 값으로 변경 하라고 명령한다.
  break;
 }

 return 0;

}
LRESULT OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
      return 0;
}
LRESULT OnPaint(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
      hdc=BeginPaint(hWnd, &ps);
       if(bEllipse == TRUE)
       {
             Ellipse(hdc,200,100,400,200);
        }
        else
        {
              Rectangle(hdc,200,100,400,200);
         }
       EndPaint(hWnd,&ps);
       return 0;

}
LRESULT OnDestroy(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
       if(SendMessage(c2,BM_GETCHECK,0,0)==BST_CHECKED)
       {
              MessageBox(hWnd,TEXT("Good Bye"),TEXT("Check"),MB_OK);
       }

 // c2 는 오토 체크 박스 이다.
 // 오토 체크 박스에 체크가 되어 있을시 마지막에 마칠 때 메시지 박스를 열어
 //  Good Bye를 출력하고 OK 버튼을 눌렀을 때 종료한다.

       PostQuitMessage(0);
       return 0;
}

실 행 화 면 은 다 음 과 같 다.


728x90