Below is a quick tutorial on how to nest a child dialog inside another using MFC (useful when, say, implementing your own tab-strip-like control). Disclaimer: caveat emptor — this method may be flawed, but it works for me.

  1. Using the resource editor, create the parent dialog. As the child dialog will be a child window, be sure to set Control Parent to True.

  2. Optional: Create and insert a placeholder control of the desired dimensions for your nested child dialog. I typically use a CStatic with a border and caption for reference. Assign it a resource id that isn’t IDC_STATIC and generate a control member variable because you will need it later.

    Here is a picture of a sample parent dialog with a placeholder control:

    Nested dialogs parent dialog

    If you do not use a placeholder control, you will have to set the child window position manually.

  3. Using the resource editor, create a dialog to act as the child. Make sure that it is no larger than your placeholder control or it will be truncated (unless you handle resizing). Set Style to Child, Control to True, and Border to None. TheControl setting is particularly important for a smooth user experience —Raymond Chen describes what it does in What is the DS_CONTROL style for?

    Here is a picture of a sample child dialog:

    Nested dialogs child dialog
  4. Assuming that you named the placeholder control member variablem_staticPlaceholder, insert the following code snippet into the parent dialog’sOnInitDialog() function:

    // Get the static placeholder client rectangle, which we will use
    // to size the child dialog.
    CRect rct;
    m_staticPlaceholder.GetWindowRect(&rct); // In screen coordinates
    ScreenToClient(&rct);
    m_staticPlaceholder.ShowWindow(SW_HIDE);
    
    CDialog* pchild = new CChildDialog;
    // Call Create() explicitly to ensure the HWND is created.
    pchild->Create(CChildDialog::IDD, this);
    
    // Set the window position to be where the placeholder was.
    pchild->SetWindowPos
        (
        NULL,
        rct.left,
        rct.top,
        rct.Width(),
        rct.Height(),
        SWP_SHOWWINDOW
        );
    

    You may want to examine SetWindowPos()’s flags to see if there is a more appropriate combination of flags for your usage scenario.

Here is a picture of the result where the child dialog is properly nested inside the parent:

Nested dialogs combined dialog

Using this method, even keyboard navigation works correctly!


Posted by 두장
제  목 : 여러 서버의 load를 터미널에서 실시간 모니터링
작성자 : 좋은진호(truefeel, http://coffeenix.net/ )
작성일 : 2008.2.13(수)~15(금)

'리눅스 터미널(CLI모드)에서 보는 실시간 시계' ( http://coffeenix.net/bbs/viewtopic.php?t=2836 )에 대해 소개한 적이 있다. 이 시계 스크립트는 터미널의 오른쪽 상단에 실시간으로 시간을 표시한다. 

[ 터미널에서 시계 ] (1초단위로 시간이 바뀌면서 표시된다.)


1. 한화면 실시간 load 모니터링 개요

시계 스크립트를 응용하여, 여러 서버의 load를 한화면에서 볼 수 있도록 구현하였다. 스크립트는 다음과 같은 역할을 한다.

1) tput 명령과 ANSI코드를 이용하여 원하는 위치에 load를 표시한다.
2) 1~9초간격으로 새로운 데이터를 표시한다.
3) '로그 모니터링시 특정 문자를 highlight하기' ( http://coffeenix.net/board_view.php?bd_code=1562 , 글 좋은진호)에서 소개한 방법을 이용하여 load별로 다른 색을 표시한다.

   -------   --------
   load       색깔
   -------   --------
   0.0       하얀색
   0.1~0.39  녹  색
   0.4~0.79  파란색
   0.8~이상  빨간색
   -------   --------

4) 숫자 1~9까지 누르면 시간 간격을 변경할 수 있다. (단, foreground로 실행시)
5) q를 누르면 종료한다. (단, foreground 실행시)

참고로 서버는 10여대 정도만 샘플로 표시하였으며, 이미지상의 서버명은 실제 사용하지 않는 임의의 서버명이다.

[ load 모니터링 샘플 화면 ]


2. 미리 준비되어 있어야할 사항

통합 로그 서버와 각 서버에서 load를 보내주도록 처리해야 한다. 구축 방법에 대해서는 간략히 얘기하고, 시간이 될 때 추가 문서를 통해 설명하겠다.

1) 각 서버에서는 logger를 활용하여 서버의 load를 syslogd로 보내준다. 

  
 
   LOAD="`uptime|awk -F': '{print $2}'`"
   logger -p 로그의레빌 -t LOAD "호스트명 -> 현재시간 load $LOAD"
  
 


   syslogd 는 load부분에 대한 로그를 통합로그로 보내지도록 설정해야 한다. 이 때 서버의 load는 5~10초 간격, 또는 더 긴 간격으로 체크하여 syslogd로 보내주면 된다.

2) 통합 로그 서버에서는 각 서버의 syslog 결과를 받을 수 있도록 설정한다. 통합서버는 FreeBSD를 권장하지만, 리눅스 서버를 사용할 경우 syslog-ng를 통해서 로그 서버 구축한다. 각 서버에서 오는 load정보는 서버별로 별도 파일에 저장하도록 하는 것이 중요하다. 예를 들어 cnx10.log, cnx22.log, cnx25.log, ... 처럼. 통합로그 서버의 서버별 로그 파일에는 다음과 같이 형태로 로그가 저장된다.

 
Jan  6 00:00:04 192.168.123.140 LOAD: cnx10 -> 00:00:04 load 0.07, 0.03, 0.00
 


FreeBSD에서 실행할 때는 다음 2가지 사항을 체크해야 한다.
FreeBSD의 tput은 cursor 이동을 지원하지 않으므로 OpenBSD의 소스(ftp://ftp.openbsd.org/pub/OpenBSD/src/usr.bin/tput )를 가져다가 사용해야 한다. 또한 스크립트에서 사용한 read 옵션 -n, -s는 bash에 의존적으로 동작한다. /usr/ports/shells/bash ports 디렉토리에서 설치한다.

3. load 모니터링 스크립트

load_mon.sh 내려받기
 
#!/bin/bash
#
# system load를 실시간으로 모니터링
#
# by 좋은진호(truefeel, http://coffeenix.net/ )
# 2008.2.12~

# foreground로 실행할 때는 0으로, background로 할 때는 1로
fg=0

# 데이터를 실시간으로 보여줄 간격 (초단위)
sleep=2

# 오른쪽에서 몇번째 칸에 표시할 것인지 설정
cols=22

#
LOGDIR="/var/log/load"
TPUT="/usr/bin/tput"

# color
szColBk="^[[;30m";      szColBk1="^[[1;30m"     # black
szColRe="^[[;31m";      szColRe1="^[[1;31m"     # red
szColGr="^[[;32m";      szColGr1="^[[1;32m"     # green
szColYe="^[[;33m";      szColYe1="^[[1;33m"     # yellow
szColBl="^[[;34m";      szColBl1="^[[1;34m"     # blue
szColPu="^[[;35m";      szColPu1="^[[1;35m"     # magenta(purple)
szColCy="^[[;36m";      szColCy1="^[[1;36m"     # cyan
szColGy="^[[;37m";      szColWh="^[[1;37m"      # white
szInverse="^[[7m"
szInvOff="^[[27m"
szNormal="^[[;m"

#
szColLev1=$szColYe
szColLev2=$szColBl
szColLev3=$szColRe1

# ------------------------------------------------
#
keyinput () {
        stty -icanon
        read -t $sleep -n 1 -s time
        stty icanon

        case $time in
                [1-9])
                        sleep=$time
                        C=$((`$TPUT cols` - $cols))
                        $TPUT cup $row $C
                        echo "${szInverse} Delay time : $time sec   $szNormal"
                        ;;
                [qQ])
                        echo -n  "^[[u"
                        exit 0
                        ;;
        esac
}

# ------------------------------------------------
# 실시간 처리 시작
# ------------------------------------------------
# foreground면 화면 clear
if [ $fg -eq 0 ]; then
        clear
fi

cd $LOGDIR

while :
do

        # ------------------------------------------------
        # 결과값 추출
        # ------------------------------------------------
        cmd_local=`uptime | awk -F': ' '{print $2}'|awk -F', ' '{print $1 "|" $2 "|" $3 " "}'`
        cmd=`tail -1 *.log | grep : | awk '{print $6 "|" $10 "|" $11 "|" $12 " "}'`
        result="LOC_|$cmd_local $cmd"

        # highlight
        result_color=`echo "$result" \
        | sed \
                -e "s/,//g" \
                -e "s/\(0\.0\)/${szColGy}\\1/g" \
                -e "s/\(0\.[1-3]\)/${szColGr}\\1/g" \
                -e "s/\(0\.[4-7]\)/${szColBl1}\\1/g" \
                -e "s/\(0\.[8-9]\)/${szColLev3}\\1/g"  \
                -e "s/\([1-9]\.\)/${szColLev3}\\1/g"`

        # ------------------------------------------------
        # cursor 위치 저장
        echo -n "^[[s"

        $TPUT el         # cleans from position to end of line

        # ------------------------------------------------
        # 결과값을 출력
        # ------------------------------------------------
        col_width=`$TPUT cols`                  # column 길이

        #지정한 cols보다 좁으면 종료
        if [ $col_width -lt $cols ]; then
                echo "터미널의 폭이 너무 좁습니다."
                exit
        fi

        C=$(($col_width - $cols))               # data를 표시할 column 위치 계산
        row=0
        $TPUT civis                             # cursor 숨김
        for line in $result_color
        do
                $TPUT cup $row $C               # cursor 이동
                row=`expr $row + 1 `            # row 증가
                echo -n "$szColYe$szInverse$line$szNormal"
        done
        $TPUT cnorm                             # cursor 다시 표시

        # ------------------------------------------------
        if [ $fg -eq 0 ]; then
                keyinput
        else
                 # cursor 위치를 원래대로
                echo -n  "^[[u"

                sleep $sleep
        fi
done
 


foreground로 스크립트를 실행할 것이면 fg=0으로 하고, background로 실행할 때는 1로 해줘야 스크립트의 기능을 제대로 사용할 수 있다. sleep=2 는 실시간으로 조회할 데이터를 몇 초 간격으로 볼 것인가를 지정한다.

LOGDIR= : 서버 load가 저장되어 있는 로그 파일의 경로
TPUT=   : tput 명령의 경로. 기본 경로는 /usr/bin/tput

상단 부분의 'szCol' 로 시작하는 변수는 색깔을 정의한 ANSI 코드이다. ^[ 문자는 ESC키를 의미한다. 쉘에서 입력할 때 Ctrl+V를 누른 후 ESC키를 누르면 입력할 수 있다.

4. 스크립트 부분별 이해

 
keyinput () {
        stty -icanon
        read -t $sleep -n 1 -s time
        stty icanon

        case $time in
                [1-9])
                        sleep=$time
                        C=$((`$TPUT cols` - $cols))
                        $TPUT cup $row $C
                        echo "${szInverse} Delay time : $time sec   $szNormal"
                        ;;
                [qQ])
                        echo -n  "^[[u"
                        exit 0
                        ;;
        esac
}
 


keyinput() 함수는 foreground로 실행할 때 키입력을 받아들이는 부분이다.
read 의 -t 옵션은 입력 대기 시간이다. -t 5라면 5초동안 입력 대기를 하게 되는데, 결국 sleep 5 를 한 것과 같은 효과를 볼 수 있다. -n 1 은 1자만 입력 받는 것이고, -s는 입력한 키를 화면에 출력하지 말라는 뜻이다. 키 입력이 생기면 바로 그 다음줄이 실행되며, 입력되지 않더라도 대기시간이 지나면 넘어가게 된다. 결국 keyinput()함수는 프로그램의 실행에 방해를 주지 않으면서 원하는 키입력을 받아들이는 역할을 하게 된다.
1~9까지 입력(즉, 1~9초에 해당)하면 delay time을 변경하고, 화면 변경됐음을 보여준다. q를 누르면, 적당한 곳으로 커서를 옮기고 종료한다.

 
cmd_local=`uptime | awk -F': ' '{print $2}'|awk -F', ' '{print $1 "|" $2 "|" $3 " "}'`
cmd=`tail -1 *.log | grep : | awk '{print $6 "|" $10 "|" $11 "|" $12 " "}'`
 


원하는 데이터 값을 가져오는 부분이다.
$cmd_local : 스크립트를 실행중인 서버의 load가 저장된다. '0.03|0.01|0.00'
$cmd       : load가 저장된 각 서버별 로그파일의 맨 마지막 줄(가장 최근 load)를 읽어서 변수에 저장한다.
    'cnx10|1.00,|1.00,|0.95 cnx22|0.39,|0.38,|0.35 cnx25|0.31,|0.24,|0.18 ... 생략...'
    '서버명|1분load|5분load|15분load' 형태이며, 서버간의 구분은 반드시 1개 이상의 공백으로 해야 한다.

 
        C=$(($col_width  - $cols))              # data를 표시할 column 위치 계산
        row=0
   $TPUT civis            # cursor 숨김
        for line in $result_color
        do
                $TPUT cup $row $C               # cursor 이동
                row=`expr $row + 1 `            # row 증가
                echo -n "$szColYe$szInverse$line$szNormal"
        done
   $TPUT cnorm            # cursor 다시 표시
 


data를 표시할 위치를 오른쪽 상단, 오른쪽에서 $cols 번째칸으로 한다. 그런 후 서버마다 한줄에 한칸씩 보여준다. 화면에 표시될 때 커서는 안보이게 했다가(civis), 데이터가 다 뿌려지면 다시 보이도록 했다(cnorm).

다음은 실제 모니터링하는 화면이다. 3개의 화면을 연속으로 캡쳐한 것이다. 3초 간격, 3초 간격, 그리고 숫자 '5'를 누른 후 5초간격으로 보여주겠다는 화면이다.



highlight 처리 부분에 대한 설명은 참고문서로 대신한다. 그리고, 재미난 시계 스크립트를 소개한 'Sergio Gonzalez Duran'씨에게 감사드린다.

5. 참고자료

  * CLI Magic: Use ANSI escape sequences to display a clock in your terminal 
    http://www.linux.com/feature/124918
  * 로그 모니터링시 특정 문자를 highlight하기 (글 좋은진호, 2008.1)
    http://coffeenix.net/board_view.php?bd_code=1562 
  * bash 맨페이지 중에 'read' 부분
  * tput: Portable Terminal Control
    http://www.gnu.org/software/termutils/manual/termutils-2.0/html_chapter/tput_1.html


Posted by 두장

string.h 함수 정리 (형식/기능)

 

 

함수명

형식 / 기능

strlen()

unsigned strlen( const char *str )

str 문자열 길이를 반환

strcat()

char *strcat( char *str1, const char *str2 )

str1의 문자열에 str2 문자열을 연결

strncat()

char *strncat( char *str1, const char *str2, unsigned c )

str1의 문자열에 str2 문자열의 선두 c개의 문자를 연결

strcmp()

char *strcmp( char *str1, const char * str2 )

str1의 문자열과 str2 서로 부호 없는 비교,
str1>str2
이면 양수값 반환 / str1<str2 이면 음수값 반환 / str1=str2 이면 0을 반환

strncpm()

char *strncpm( char *str1, const char *str2, unsigned c )

str1 문자열의 선두 c개의 문자와 str2 문자열을 비교

strcpy()

char *strcpy( char *str1, const char *str2 )

str1의 문자열에 str2 문자열을 복사, str1의 값을 반환함.

strncpy()

char *strncpy( char *str1, const char *str2, unsigned c )

str1의 문자열에 str2 문자열의 선두 c개의 문자를 복사

strstr()

char *strstr( const char *str1, const char *str2 )

문자열 str2가 문자열 str1에서 처음 일치하는 위치를 알려준다. 만약 문자열이 발견 되면 str1에 있는 그 문 자열의 포인터를 반환한다. 그 외에는 NULL 포인터를 반환한다.

strerror()

char *strerror( int num )

오류번호 num을 받아 해당하는 오류 메시지를 반환

strpbrk()

char *strpbrk( char *str1, const char *str2 )

지정한 str1의 문자열에서 str2의 문자열에 포함된 어떤 문자를 찾고 위치 포인터를 반환

strrchr()

char *strrchr( const char *str, int c )

문자열 str에서 c가 마지막으로 나타나는 위치를 알려준다. c가 발견되면 c의 포인터 를 반환한다. 그 외에는 NULL포인터를 반환한다.

strcspn()

char *strcspn( char *str, const char *str2 )

str1의 문자열에서 str2의 문자열에 포함된 문자가 첫 번째 나타날 때 까지의 문자수

strspn()

char *strspn( char *str1, const char str2 )

str1의 문자열에서 str2의 문자열에 포함되지 않은 문자가 첫 번째 나타날 때까지의 문자수

strtok()

char *strtok( char *str1, const char *str2 )

일련의 strtok 호출은 문자열 str1을 문자열 str2가 가지고 있는 문자로 구분되는 '토큰'으로 나눈다. 첫 번째 호출은 첫 번째 인수인 str1을 사용하여 두 번째 호출부터는 NULL을 첫 번째 인수로 사용한다. 매 호출마다 현재 토큰의 포인터를 반환한다. 더 이상 토큰이 없으면 NULL을 반환한다 .

strupr()

char *strupr( char *str )

지정한 str의 문자열 중 소문자를 대문자로 변환

 

 

또 다른 글 =============================================================================================

 

stpcpy

원형 : char *stpcpy( char *dest, char *src );

헤더 : string.h

기능 : 문자열 src를 문자배열 dest로 복사한다. dest 의 길이가 src 보다 작은 경우 dest 뒤의 인접 데이터가 파괴된다.

리턴 : dest + strlen(src)의 번지를 리턴

 

 strcat

원형 : char *strcat( char *dest, const char *src );

헤더 : string.h

기능 : 문자열끼리 연결한다. dest의 널문자 위치에 src가 붙는다. dest의 길이가 ( dest 문자열 + src 문자열 ) 길이보다 작을 경우 인접 데이터가 파괴된다.

리턴 : dest의 번지가 리턴

 

 strchr

원형 : char *strchr( const *src, int c );

헤더 : string.h

기능 : 문자열 배열 src 내에 문자 c가 있는지 검사하고 있을 경우 문자 c가 있는 번지를 리턴. 널문자도 문자로 취급하기 때문에 널문자를 넣으면 첫번째 널문자의 번지를 리턴한다.

리턴 : 문자열 src내에서 발견된 문자 c의 포인터. 발견되지 않을 경우 NULL 리턴

 

 strcmp

원형 : int strcmp( const char *src1, const char *src2 );

헤더 : string.h

기능 : 두 개의 문자열을 대소 비교함. 이 함수를 사용하여 두 개의 문자열이 같은 문자열인지 아닌지를 비교할 수 있다. 같을 경우 0, 다를 경우 양수나 음수의 값을 리턴.

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strcmpi

원형 : int strcmpi( const char *src1, const char *src2 );

헤더 : string.h

기능 : 두 개의 문자열을 대소 비교함. 하지만 대소문자를 구분하지 않는다. 이 함수를 사용하여 두 개의 문자열이 같은 문자열인지 아닌지를 비교할 수 있다. 같을 경우 0, 다를 경우 양수나 음수의 값을 리턴.

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strcoll

원형 : int strcoll( char *src1, char *src2 );

헤더 : string.h

기능 : setlocale 함수에 의해 지정된 비교방식에 따라 두 개의 문자열을 비교

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strcpy

원형 : char *strcpy( char *dest, const char *src );

헤더 : string.h

기능 : 문자열 src를 문자배열 dest로 복사한다. dest 의 길이가 src 보다 작은 경우 dest 뒤의 인접 데이터가 파괴된다.

리턴 : dest의 번지가 리턴

 

 strcspn

원형 : size_t strcspn( const char *src1, const char *src2 );

헤더 : string.h

기능 : 문자열 src1 중에 문자열 src2에 들어 있지 않은 문자들이 연속해 있는 길이를 구한다. 문자열 s2에 없는 문자들로 구성되어 있는 문자열 s1 내의 세그먼트를 찾아내고 그 세그먼트의 길이를 리턴.

예를 들어 src1 = "123456" 이고 src2 = "0486" 이라면 src1 내에서 src2 의 문자인 4가 나오기 전까지의 길이인 3을 리턴한다.

리턴 : 찾아낸 세그먼트의 길이만약 0을 리턴한다면 세그먼트가 발견되지 않은 것이다.

 

 strdup

원형 : char *strdup( const char *src );

헤더 : string.h

기능 : 새로운 메모리를 할당하고 문자열 src를 복사한 후 그 포인터를 리턴한다. 종료 시 반드시 복제된 문자열은 메모리를 해제해 주어야 한다.

리턴 : 복제된 문자열의 포인터를 리턴. 메모리 할당에 실패한 경우 NULL을 리턴.

 

 _strerror

원형 : char *_strerror( const char *src );

헤더 : string.h, stdio.h

기능 : 사용자가 정의하는 에러 메시지를 만든다. src NULL일 경우 최근 발생한 에러 메시지만으로 구성된 문자열을 만들고 src NULL이 아닌 경우 에러메시지 형식의 문자열을 만든다.

만약 src "babo" 이면 babo : 최근 에러 메시지 같은 형식으로 문자열을 만든다.

리턴 : 만들어진 에러 문자열의 포인터를 리턴한다.

 

 strerror

원형 : char *strerror( int errnum );

헤더 : stdio.h

기능 : errnum에 해당하는 에러메시지 문자열을 만든다. 에러메시지 문자열은 모두 \n으로 끝나므로 개행 문자를 첨가해 줄 필요는 없다.( 에러 메시지는 이미 정의되어 있으므로 궁금하면 출력시켜보자)

리턴 : 에러메시지 문자열의 포인터

 

 stricmp

원형 : int stricmp( const char *src1, const char *src2 );

헤더 : string.h

기능 : 두 개의 문자열을 대소 비교함. 하지만 대소문자를 구분하지 않는다. 이 함수를 사용하여 두 개의 문자열이 같은 문자열인지 아닌지를 비교할 수 있다. 같을 경우 0, 다를 경우 양수나 음수의 값을 리턴이 함수를 매크로로 정의해 둔 함수가 strcmpi 이다.

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strlen

원형 : size_t strlen( const char *src );

헤더 : string.h

기능 : 문자열 src 의 길이를 계산한다. 널문자는 길이에 포함되지 않고 널문자 앞에 까지 문자 개수를 리턴한다.

리턴 : 문자열의 길이

 

 strlwr

원형 : char *strlwr(char *src);

헤더 : string.h

기능 : 문자열 src 내의 대문자(A~Z)를 소문자(a~z)로 변경한다. 영문자 외의 다른 문자는 변경하지 않는다.

리턴 : 인수로 주어진 src를 그대로 리턴

 

 strncat

원형 : char *strncat( char *dest, const char *src, size_t maxlen );

헤더 : string.h

기능 : dest 의 널문자에 src의 문자열을 붙이는데 maxlen 길이 만큼만 붙인다.

리턴 : dest의 번지를 리턴

 

 strncmp

원형 : int strncmp( const char *src1, const char *src2, size_t maxlen );

헤더 : string.h

기능 : 두 개의 문자열을 대소 비교한다. 비교시 대소문자를 구분한다. 하지만 문자열 전체를 비교하는 것이 아니라 maxlen 길이 만큼만 비교한다.

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strncmpi

원형 : int strncmpi( const char *src1, const char *src2, size_t maxlen );

헤더 : string.h

기능 : 두 개의 문자열을 대소 비교한다. 비교시 대소문자를 구분하지 않는다하지만 문자열 전체를 비교하는 것이 아니라 maxlen 길이 만큼만 비교한다.

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strncpy

원형 : char *strncpy( char *dest, char *src, size_t maxlen );

헤더 : string.h

기능 : 문자열을 정해진 길이만큼 복사한다. 길이만큼만 복사하기 때문에 dest의 뒤에 널문자가 붙지 않는다.

리턴 : dest의 번지를 리턴

 

 strnicmp

원형 : int strnicmp( const char *src1, const char *src2, size_t maxlen );

헤더 : string.h

기능 : 두 개의 문자열을 대소 비교한다. 비교시 대소문자를 구분하지 않는다하지만 문자열 전체를 비교하는 것이 아니라 maxlen 길이 만큼만 비교한다. 이 함수의 매크로 버젼이 strncmpi 이다.

리턴 : src1 < src2  인 경우 음수 리턴

         src1 = src2  인 경우 0 리턴

         src1 > src2  인 경우 양수 리턴

 

 strset

원형 : char *strset( char *src, int c );

헤더 : string.h

기능 : 문자열을 특정 문자로 채운다. 문자열 중 널문자가 발견될 때가지 문자 c 로 채운다.

리턴 : src의 번지를 리턴

 

 strpbrk

원형 : char *strpbrk( const char *src1, const char *src2 );

헤더 : string.h

기능 : 문자열 src1 내에 문자열 src2에 있는 문자 중의 하나라도 있는지 검사하고 있을 경우 그 포인터를 리턴.

리턴 : 문자열 src1 내에 문자열 src2에 있는 문자 중 하나가 발견된 포인터를 리턴. 없을 경우 널을 리턴

 

 strrchr

원형 : char *strrchr( const cjar *src, int c );

헤더 : string.h

기능 : 문자 배열 src내에 문자 c가 있는지 검사하고 있을 경우 문자 c가 있는 번지를 리턴한다. 하지만 앞에서 부터 검사하는 것이 아니라 뒤에서 부터 검사를 진행한다.

리턴 : 문자열 src에서 발견된 문자 c의 포인터를 리턴. 발견되지 않을 경우 널을 리턴.

 

 strrev

원형 : char *strrev( char *src );

헤더 : string.h

기능 : 문자열의 순서를 바꾼다. 즉 제일 앞에 있는 문자가 제일 뒤로 가고 제일 뒤의 문자가 제일 처음으로 옮겨진다. 널문자는 이동 없음.

리턴 : 역순으로 바꾼 문자열의 src번지

 

 strspn

원형 : size_t strspn( const char *src1, const char *src2 );

헤더 : string.h

기능 : 문자열 src1 중에서 문자열 src2에 있는 문자들이 연속해 있는 길이를 구한다.

예를 들어 src1 = "12345678" 이고 src2 = "143290" 이라면 src1에서 src2의 문자들을 찾아보면 1234가 있다. 이 문자열의 길이 4를 리턴한다.

리턴 : 찾아낸 세그먼트의 길이를 리턴. 만약 0을 리턴하면 세그먼트를 찾지 못한 것이다.

 

 strstr

원형 : char *strstr( const char *src1, const char *src2 );

헤더 : string.h

기능 : 문자열 src1내에서 문자열 src2가 포함되어 있는지 검사하고 있다면 src2와 같은 문자열이 있는 부분을 리턴한다.

리턴 : 부분문자열의 선두 번지. 없다면 널을 리턴

 

 strtod

원형 : double strtod( const char *src1, char **endptr );

헤더 : stdlib.h

기능 : 문자열을 double 형 부동 소수점으로 바꾼다. 문자열은 다음과 같은 구조로 이루어져야 한다.

[공백,][부호][숫자][소수점][e]  -> ex) -5.64e+5, -3.6924

순서를 어기거나 불필요한 문자가 중간에 있을 경우는 변환이 중지.

endptr 인수는 변환이 중지될 경우 중지된 문자를 가리키므로 에러 검색에 사용

리턴 : 변환된 double 형 실수를 리턴. overflow 발생시 HUGE_VAL을 리턴

 

 strtok

원형 : char *strtok( char *src1, char *src2 );

헤더 : string.h

기능 : 문자열에서 token을 찾아낸다. ( token 이란 특정한 구분자로 분리되는 문장 구성 요소이다. 구분자가

"/"라 할때 다음 문자열은 1994 Feb 20의 세 개의 token 으로 분리된다. "1994/Feb/20" )

문자열 src1 token을 찾아낼 문자열이며 src2 token 구분자가 들어있는 문자열이다. token 구분자는 여러개가 복수 개 지정될 수 있으며 token 구분자는 strtok 호출 시 마다 바뀔 수 있다.

리턴 : 찾아낸 token의 포인터를 리턴. token이 더 이상 없을 경우 널 리턴.

( 이해가 안가는 분은 winapi에서 예제를 참고)

 

strtol

원형 : long strtol( const char *src1, char **endptr, int radix );

헤더 : stdlib.h

기능 : 문자열을 long 형 정수로 변환한다.문자열 src1은 다음과 같은 구조로 이루어져야 한다.

[공백, ][부호][숫자]

만약 이 순서를 어기거나 불필요한 문자가 문자열 내에 있을 경우 변환은 중지되고 중지된 위치가 endptr에 설정된다. endptr은 에러 검색에 사용하면 용이. 그리고 radix은 문자열을 해석할 진법을 지정할 때 사용되는데 범위는 2~36 까지 이고 그 진법에서 사용되는 문자만 인식

리턴 : 변환된 long 형 정수를 리턴. 변환이 불가능할 경우 0을 리턴

 

strtoul

원형 : unsigned long strtoul(const char *src1, char **endptr, int radix );

헤더 : string.h

기능 : 문자열을 부호없는 long 형 정수로 바꾼다. 사용법은 strtol 과 동일.

리턴 : 변환된 unsigned long 형 정수를 리턴. 변환이 불가능할 경우 0을 리턴

 

strupr

원형 : char *strupr( char *src );

헤더 : string.h

기능 : 문자열 src내의 소문자 (a~z)를 대문자( A~Z)로 변환한다. 영문자 외의 다른 문자는 변경하지 않는다.

리턴 : src의 번지를 리턴

출처&참조 : www.winapi.co.kr

 

Posted by 두장
에디트박스와 리스트 컨트롤의 내용이 꽉 찰경우에 자동으로 스크롤을 내려줄 때
다음과 같이 구현합니다.

1. EditBox Control
CEdit m_edit;
m_edit.LineScroll(m_edit.GetLineCount());
2. List Control
CListCtrl m_list;
m_list.EnsureVisible(m_list.GetItemCount()-1, FALSE);

Posted by 두장

  만약 우리가 프로그래밍을 해서 C 프로그램을 만들었다고 하자. 우리는 대부분 Visual Studio 를 이용하거나, GCC 를 통해 컴파일 할 것이다. 하지만 이는 모두 그 컴파일러를 다운받아서 사용해야 한다는 단점이 있는데 인터넷 상에서 컴파일 해 실행할 수 있는 사이트가 있다.
  바로 codepad.org 이다. 이 사이트는  C , C++ , D , Haskell , Lua , OCaml , PHP , Perl, Python, Ruby , Scheme, Tcl 과 같은 언어들에 대한 무료 컴파일러/인터프리터 를 제공해준다. 인터넷에 올려진 무료 컴파일러/인터프리터가 쉽게 제작되는 것은 아니다. 왜냐하면 이 컴파일러/인터프리터는 무한 while 문 이라던지, 스스로를 파괴하는 명령문들로 부터 철저하게 대비를 해야만 사이트가 유지될 수 있기 때문이다. 또한 보안을 위해서cin 이나 scanf 와 같은 사용자로 부터 입력을 받아들이는 함수들도 봉쇄되고 있다. 
  따라서 긴 코딩을 하기에는 별로 적합하지 않다. 그렇지만 짧은 프로그램이나 잠시 테스트 할 것이 있는 것 등을 하기 위해서는 이용하기 적합한 것 같다. 하지만 궁금한 것이 하나 있는데, C 의 포인터를 이요할 때, 그 포인터가 가리키는 메모리는 어느 메모리를 가리키는 것일까? 사용자의 컴퓨터의 메모리? 또는 codepad.org 의 서버 컴퓨터 메모리인지. 참 궁금할 따름이다. 
Posted by 두장
2008. 10. 31. 16:03

 

11.1 표준 입·출력 함수

표준 입·출력 함수는 자료의 기록, 판독에 대하여 다음과 같이 4가지 방법을 사용한다.

① 키보드로부터 자료를 읽어서 화면에 자료를 나타내는 방법으로 한 번에 한문자만을기록, 판독하는 방법

(예: getchar(), getc(), getch(),putchar(), putc(), putch())

② 키보드에서 문자열을 읽어서 화면에 문자열을 나타내주는 방법

(예: gets(), puts())

③ 문자, 문자열, 부동 소수점, 정수 등을 혼합하여 형식화된 자료를 기록하거나 판독하는 방법

(예: fscanf(), fprintf())

④ 레코드 또는 블록 형식을 이용하여 자료의 기록 및 판독을 행하는 방법 등이 있다.이중 2가지 방법은 이미 배운바 있으나 정리하면서     간략히 설명하고 3,4번째 방법에대해 자세히 기술한다.

단일 문자 입·출력

■ 입 력

키보드로부터 1문자를 입력하는 형식은 다음과 같다.

 

getchar()

getch()

getc(화일 포인터)

 

getchar(), getch(), getc() 함수의 사용 방법은 동일하나 getch() 함수는 화면에 문자가 나타나지 않으며 getc() 함수는 인수로서 읽고 쓸 화일의 이름을 꼭 밝혀 주어야 한다.

■ 출 력

1 문자를 화면에 출력하는 형식은 다음과 같다.

 

putchar()

putch()

putc(문자, 화일 포인터)

 

putchar(), putch(), putc() 함수의 사용 방법은 동일하나, putchar(), putch() 함수는 화면에서 출력만으로 사용하며 putc() 함수는 화일 포인터에 문자를 저장할 수 있다.

 

 [예제 11-1] putchar() 함수 사용 방법

 #include <stdio.h>

void main()

     {

         char ch;

         while((ch = getchar()) != '\r')

         putchar(ch);

     }

 TurboC example

TurboC example

 

 

[예제 11-2] putch() 함수 사용 방법  

#include <stdio.h>

void main()

    {

        char ch;

        while((ch = getch()) != '\r')

        putch(ch);

    }

TurboC example 

 

 

[예제 11-3] getc(), putc() 함수 사용 방법  

 #include <stdio.h>

void main()

     {

          char ch;

          while((ch = getc(stdin)) != '\r')

          putc(ch,stdout);

     }

TurboC example

TurboC example 

 

 

문자열의 입·출력

문자열의 입·출력에 대한 형식은 다음과 같다.

 

gets(문자열)

puts(문자열)

 

gets() 함수는 표준 입력 장치(스트림 입력 장치라고도 함)으로부터 문자열을 입력으로 받아들여 문자열에 대한 포인터를 반환하는 함수이다 이때 주의할 점은 문자열 버퍼의 끝에 NULL('\0')이 자동적으로 부가되어 저장되므로 입력의 문자 수보다 적어도 하나 이상의 저장공간이 확보되어야 한다. puts() 함수는 표준 출력 장치로 문자열을 보내는 함수이다. 이 함수는 printf()의 제어지시를 이용하여 문자열을 간단히 출력할 수 있으므로 잘 사용하지 않는다.

 

[예제 11-4]  

#include <stdio.h>

void main()

     {

          char string[80];

          printf("Input a string:");

          gets(string);

          puts(string);

     }  

Input a string:This is sample string

This is sample string 

 

 

11.2 화일의 개방과 종결

본 절에서는 보조 기억장치를 이용한 화일의 기록, 판독에 대한 초기 과정, 화일의 개방과 종결에 대해 기술한다.

화일의 개방

화일은 보조 기억장치에서 읽어오거나 보조 기억장치로 기억시키기 위해서는 화일을 개방하여야 한다. 화일을 개방하기 위해서는 화일이름을 읽을 것인지 기억 시킬것인지를 운영체제에 정보를 제공해 주어야 한다. 운영 체제는 보조 기억장치(주로 디스크 장치 이용)에서 정보를 읽을 것인지 또는 기억할 것인지에 대한 정보를 포인터로써 돌려주게 된다. 따라서 개방되는 화일은 구조체를 가지게 된다.

화일 구조체는 자료 버퍼의 현재 크기와 위치 등의 화일에 관한 정보를 포함하며 반드시 #include <stdio.h> 할 필요가 있다.

프로그램에서 화일 구조체에 대한 포인터형의 변수 선언과 화일을 개방하는 문장은 다음과 같다.

예)#include <stdio.h>

FILE *fp;

fp=fopen("kim.dat","w");

여기서 *fp는 포인터 화일 변수이며 fopen() 함수는 fp변수에 저장된 화일 구조체에 대한 포인터를 돌려준다. 개방 화일은 "kim.dat"이며 화일에 자료를 기록하라는 의미가 "w"이다.

<stdio.h> 화일에 미리 정의되어 개방되는 스트림은 다음과 같다.

 

이 름

장 치

모 드

stdin

stdout

stderr

stdaux

stdprn

표준 입력 장치(키보드)

표준 출력 장치(화면)

표준 에러 장치(화면)

표준 보조 장치(직렬 포트)

표준 출력 장치(병렬 프린터)

텍스트 모드

텍스트 모드

텍스트 모드

2 진 모드

2 진 모드

 

FILE 구조체에 대한 포인터형의 변수와 화일의 개방함수 fopen()에 대해 생각해 보자. fopen() 함수의 목적은 입·출력 동작을 하기 위해 화일을 개방하는데 사용되며 형식은 다음과 같다.

 

FILE *fopen(화일명, 접근 모드)

 

여기서 접근 모드는 개방하고자 하는 화일의 모드를 결정하는 문자열을 말하며 다음과 같은 사용 모드를 제공하고 있다.

 

분 류

접근 모드

접근 내용

읽 기

r

읽기 전용으로 기존의 화일을 개방

쓰 기

w

a

쓰기 전용으로 새로운 화일을 생성

추가로 쓰기 위해 화일을 개방

갱 신

r+

w+

a+

갱신을 위해 기존의 화일을 개방

갱신을 위해 새로운 화일을 생성

갱신을 위해 화일의 끝에 개방

2진 모드

"rb", "wb", "ab"

"r+b" 또는 "rb+"

"r+a" 또는 "ra+"

2진 화일에 대해 r,w,a 기능 수행

2진 화일에 대해 r+ 기능 수행

2진 화일에 대해 a+ 기능 수행

 

화일 닫기 화일을 개방하여 그 화일에 대한 기록과 판독이 끝나면 그 화일을 닫아야만 한다. 화일을 닫는 형식은 다음과 같다.

 

fclose(화일 포인터)

11.3 화일 입·출력 함수

이 절에서는 화일의 기록과 판독에 따른 입·출력 형식에 대해 기술한다.

문자 단위 화일 입·출력 함수

일단 화일을 개방하면 디스크에 기록시키거나 디스크에서 화일의 내용을 읽어올 수가 있다. 문자 단위 화일 입·출력 형식은 다음과 같다.

 

fgetc(화일 포인터)

fputc(문자, 화일 포인터)

 

 

[예제 11-5] fputc() 함수를 이용하여 화일에 출력하는 프로그램  

 #include <stdio.h>

void main()

     {

          FILE *fp;

          char ch;

          fp=fopen("kim.dat","w");

          while((ch=getch()) != '\r') {

               putch(ch);

               fputc(ch,fp);

          }

          fclose(fp);

     }

"kim.dat"화일에는 키보드를 통해서 입력된 문자가 저장된다. 

 

 

[예제 11-6] fgetc() 함수를 이용하여 화일에 있는 내용을 화면에 출력하는 프로그램  

#include <stdio.h>

void main(void)

     {

          FILE *fp;

          char string[] = "This is a test";

          char ch;

          if((fp=fopen("kim.dat", "r")) == NULL) {

               printf("\n File not found");

               exit(-1);

          }

          do

          {

               ch = fgetc(fp);

               putch(ch);

          } while (ch != EOF);

          fclose(fp);

     }

"kim.dat" 화일에 있는 내용이 화면에 출력된다.

만약 "kim.dat"라는 화일이 없으면

"File not found" 라는 메시지가 출력된다.

  

 

  문자열의 화일 입·출력 함수

화일에서 문자열을 판독하거나 화일 문자열을 기록하는 형식은 다음과 같다.

 

fgets(문자열, 최대 길이, 화일 포인터)

fputs(문자열, 최대 길이 화일 포인터)

 

fgets() 함수는 화일 포인터로부터 입력행을 읽어 문자 배열에 저장하고 현재 위치로부터 한 레코드 또는 (최대 길이-1)개의 문자가 읽혀지면 개행문자를 만나면 끝낸다. 마지막 문자가 정상적으로 읽혀지면 NULL('\n')을 추가시키며 화일의 끝이거나 에러이면 NULL을 반환한다.

fputs() 함수는 화일 포인터가 지시하는 화일에 문자열을 기록하라는 것을 의미하며 정상이면 0을 화일의 끝이거나 에러이면 EOF(-1)을 반환한다.

 

[예제 11-7] fgets(), fputs() 함수 사용 방법  

#include <stdio.h>

void main()

     {

          FILE *fp,*fp1;

          char string[30];

          fp=fopen("kim1.dat","w");

          fp1=fopen("kim.dat","r");

          while(fgets(string,30,fp1) != NULL)

          fputs(string,fp);

          fclose(fp);

          fclose(fp1);

}

c:>type kim.dat

Jim Botton, sportscaster and author of Ball Four, on

the reception to his book : "Pete rose would screen at

me from dugout because I resealed too much. Now he's

posing in magazine ads in his underwear.

   

 

 

"kim1.dat" 화일에는 "kim.dat"화일에 있는 내용과 동일하다.

형식화된 화일 입·출력 함수

지금가지 문자와 텍스트를 화일에 기록하거나 판독하는 것을 다루었다. 여기서는 수치 자료를 다루기 위해서 형식화된 입·출력 함수에 대해 설명한다. 형식화된 입·출력 함수에 대한 다음과 같다.

 

fscanf(화일 포인터, 제어문자열, 인수)

fprintf(화일 포인터, 제어문자열, 인수)

 

fscanf() 함수fprinf() 함수는 화일 포인터를 제외하고는 scanf() 함수와 fprintf() 함수와 동일하다. fscanf() 함수는 화일로 부터 지정된 형태로 읽어들여 뒤에 오는 인수에 대입하고 화일의 끝이거나 에러가 발생하면 EOF를 반환하고 그렇지 않을 경우에는 입력된 항목의 수 를 반환한다.

fprintf() 함수는 지정된 형태를 화일에 출력하고 화일에 쓰여진 문자의 수를 반환하고 에러가 생길 경우에는 음수(-)의 값을 반환한다.

 

[예제 11-8] 성적을 저장하는 프로그램  

#include <stdio.h>

void main()

     {

          FILE *fp;

          char name[20];

          int number;

          int kor;

          int eng;

          int math;

          int total;

          int i=0;

          fp=fopen("grade.dat","w");

          do {

               printf("Enter name, number, Kor, Eng, Math : ");

               scanf("%s %d %d %d %d",name, &number, &kor, &eng,                          &math);

               total=kor+eng+math;

               fprintf(fp,"\n%s %d %d %d %d %d",name, number, kor, eng,

                         math, total);

               i++;

          } while(i <4);

          fclose(fp);

     }

Enter name, number, Kor, Eng, Math : kim 1 57 87 45

Enter name, number, Kor, Eng, Math : kim1 2 67 45 76

Enter name, number, Kor, Eng, Math : kim2 3 76 45 95

Enter name, number, Kor, Eng, Math : kim3 4 67 45 87

c:>type grade.dat

kim 1 57 87 45 189

kim1 2 67 45 76 188

kim2 3 76 45 95 216

kim3 4 67 45 87 199 

 

 

[예제 11-9] 성적이 있는 화일을 읽어서 화면에 출력하는 프로그램  

 #include <stdio.h>

void main()

     {

          FILE *fp;

          char filename[15];

          char name[20];

          int number;

          int kor;

          int eng;

          int math;

          int total;

          printf("Enter name of a file to open foe WRITING : ");

          gets(filename);

          if((fp=fopen(filename,"r")) == NULL) {

               printf("\n File not found");

               exit(-1);

          }

          printf("\n Name Number KOR ENG MATH TOTAL");

          do {

               fscanf(fp,"%s %d %d %d %d %d",name, &number, &kor,

                         &eng, &math, \&total);

               printf("\n %-10s%3d %3d %3d %3d %3d", name, number, kor,                          eng, math,total);

          } while(!feof(fp));

          fclose(fp);

     }

Enter name of a file to open foe WRITING : grade.dat

Name Number KOR ENG MATH TOTAL

kim 1 57 87 45 189

kim1 2 67 45 76 188

kim2 3 76 45 67 216

kim3 4 67 45 87 199 

 

 만일 "grade.dat"라는 화일이 없으면 "File not found"라는 메시지가 출력된다.

레코드 단위의 화일 입·출력 함수

형식화된 화일 입·출력 함수는 각 숫자가 문자로서 저장되기 때문에 디스크의 공간을 많이 차지하게 된다.

또한 배열이나 구조체 같은 복잡한 자료 형을 읽거나 기록할 때 직접적인 방법이 없다.

배열을 한 번에 배열 요소 하나를 저장하기 때문에 비 효율적이며 구조체는 여러 부분으로 나누어서 저장해야 한다.

이러한 문제점을 해결하는 것이 레코드 단위의 입·출력이다. 레코드 단위의 입·출력은 수치를 정수형은 2바이트,

실수형은(부동 소수점형)은 4바이트를 2진 형식으로 쓰기 때문에 메모리를 효율적으로 이용할 수가 있다.

한꺼번에 많은 자료를 취급할 수가 있으며 배열, 구조체, 배열의 구조체, 그리고 다른 자료 구조를 단일 문장으로 사용할 수가 있다.

형식은 다음과 같다.

 

fwrite(문자열, 크기, 항목수, 화일 포인터)

fread(문자열, 크기, 항목수, 화일 포인터)

 

fwrite() 함수는 지정된 갯수 만큼의 자료를 화일에 저장하며 fread() 함수는 주어진 화일 로부터 지정된 갯수만큼의 자료를 읽어서 문자열에 저장한다.

 

[예제 11-10] fwrite() 함수를 이용한 프로그램  

#include <stdio.h>

void main()

     {

          struct {

               char name[20];

               int number;

               float height;

          } man;

          FILE *fp;

          float dummy=0.0;

          if((fp=fopen("kim.dat","wb")) == NULL) {

               printf("\n File not found");

               exit(-1);

          }

          do {

               printf("\n Enter name : ");

               gets(man.name);

               printf(" Enter number : ");

               scanf("%d",&man.number);

               printf(" Enter height : ");

               scanf("%f",&man.height);

               fflush(stdin);

               fwrite(&man, sizeof(man),1,fp);

               printf("Add another man(y/n) ?");

          } while(getch() == 'y');

          fclose(fp);

     }

Enter name : kim1

Enter number : 1

Enter height : 34.83

Add another man(y/n) ?

Enter name : kim2

Enter number : 2

Enter height : 67.56

Add another man(y/n) ? y

Enter name : kim3

Enter number : 3

Enter height : 84.54

Add another man(y/n) ? n 

 

 

[예제 11-11] fread() 함수을 이용한프로그램  

#include <stdio.h>

#include <stdlib.h>

void main()

     {

          struct {

               char name[20];

               int number;

               float height;

          } man;

          FILE *fp;

          fp=fopen("kim.dat","rb");

          while(1) {

               fread(&man, sizeof(man), 1, fp);

               if(feof(fp)) {

                    fclose(fp);

                    exit(-1);

               }

               printf("\n Name : %s", man.name);

               printf("\n Numer : %d", man.number);

               printf("\n Height : %4.2f",man.height);

           };

     }

Name : kim1

Number : 1

height : 34.83

Name : kim2

Number :2

height : 67.56

Name : kim3

Number : 3

height : 84.54  

 

 여기서 feof() 함수는 화일의 끝을 검사하는 함수이며 화일 포인터가 가리키고 있는 화일이 모두다 판독되면 ZERO(0)가 아닌 값을 반환하고 그렇지 않으면 0을 반환한다.

exit(n) 함수는 프로그램의 실행중 중도에 끝내고 싶을 때 이용되는 함수이며 n은 0이 아니어야 프로그램의 수행을 종료하는 함수이다.

화일 포인터의 제어 함수

이제가지의 순차화일에 비해 다소 조작 방법이 복잡하지만 어디서든지 읽고 쓰기 가능한 방식은 "랜덤화일처리"라고 하며, 랜덤화일처리에서 어느 부분을 읽을 것인지를 지정할 수 있는데 이를 수행하는 함수가 fseek() 이다.

fseek() 함수는 화일의 위치를 자유로이 지정하는 함수로서 다음과 같은 형식을 갖는다.

 

fssek(화일 포인터, 변위, 기준 점)

 

화일 포인터의 화일 위치를 기준점을 기준으로 하여 변위 바이트만큼 이동하여 정상시는 0, 오류시는 0 이외의 값을 반환한다.

이때 기준점의 위치 설정에 따라 3가지로 나누며 이에 대한 상수 및 의미는 표 11-3과 같다.

 

상 수

실 제 값

의 미

SEEK_SET

SEEK_CUR

SEEK_END

0

1

2

화일의 처음

현재 화일 포인터의 위치

화일끝 검출 위치

 

한 편 fseek() 이외의 랜덤 처리계 함수 및 기능은 표 11-4와 같은 종류가 있다.

 

함수명

기 능

fflush

fgetpos

fsetpos

ftell

rewind

버퍼에 넣으려는 전체의 문자를 화일에 씀

화일 위치의 정보를 읽음

화일 포인터의 위치 설정

현제의 화일 위치 파악

화일의 위치를 선두로 이동

 

 

[예제 11-12] fseek() 함수를 사용한 프로그램  

#include <stdio.h>

#include <stdlib.h>

void main()

     {

          struct {

               char name[20];

               int number;

               float height;

          } man;

          FILE *fp;

          int rec_no;

          long int offset;

          fp=fopen("kim.dat","rb");

          printf("Enter record number : ");

          scanf("%d",&rec_no);

          offset=(rec_no-1) * sizeof(man);

          if(fseek(fp,offset,SEEK_SET)) {

               printf("\n Can't move pointer there.");

               exit(-1);

          }

          fread(&man, sizeof(man), 1, fp);

          printf("\n Name : %s", man.name);

          printf("\n Numer : %d", man.number);

          printf("\n height : %f",man.height);

          fclose(fp);

      }

Enter record number : 2

Name : kim2

Numer : 2

height : 67.55998 

 

 

11.4 메모리 할당

지금까지 다루어온 자료의 저장 방법은 표준 변수들을 사용하여 기억 장소를 미리 확보하여 확보된 영역에서의 자료의 저장 방법을 다루었다.

예를 들어 배열 선언에서 100개의 원소를 취하는 배열을 확보하고 5개의 원소만을 취한다면 95개의 원소는 빈 공간으로 남아 기억 공간이 낭비가 된다.

이 절에서는 자료의 크기가 동적으로 변할때 메모리의 확대가 가능한 메모리 할당 에 대하여 기술한다. c언어에서는 malloc() 함수를 제공하여 처리하고 있다. malloc() 함수의 사용 형식은 다음과 같다.

 

malloc(arg)

 

여기서 arg는 메모리의 바이트를 표시하는 양의 정수이며 새로운 메모리의 블럭 시작점에 대한 포인터를 반환한다.

 

[예제 11-12] malloc() 함수를 이용한 프로그램  

#include <string.h>

#include <stdio.h>

void main()

     {

          char temp_string;

          temp_string=(cahr *) malloc(100);

          strcpy(temp_string,"Hello Kang");

          printf("Enter string : ");

          fgets(temp_string,100,stdin);

          printf("Your input string is %s",temp_string);

     }

Hello Kang

Enter string : Good morning !

Your input string is Good morning !

 

 

다음 표 11.5는 표준 입·출력 함수에 대하여 총괄적인 의미를 보인 것이다.

 

함 수 명

형 식

의 미

getc(fp)

getc(fp)

FILE *fp;

fp가 가르키는 화일로부터 한 문자 입력

putc(c,fp)

putc(c,fp)

int c;

FILE *fp;

fp가 가르키는 화일로 한 문자 출력

fgetc(fp)

fgetc(c)

int c;

fp가 가르키는 화일로부터 한 문자 입력

fputc(c,fp)

fputc(c,fp)

int c;

FILE *fp;

fp가 가르키는 화일로 한 문자 출력

fgtes(s,n,fp)

fgtes(s,n,fp)

char *s;

int n;

FILE *fp;

화일 fp에 최대 n바이트의 문자열 s를 입력

fputs(s,fp)

fputs(s,fp)

char *s;

FILE *fp;

화일 fp에 문자열 s를 출력

fprintf(fp,format,인수)

fprints(fp,format,인수)

FILE *fp;

char *format;

화일 fp에 지정된 형태 format에 따라 출력

fscanf(fp,format,인수)

fscanf(fp,format,인수)

FILE *fp;

char *format;

화일 fp에서 지정된 형태 format에 따라 입력

fread(s,n,item,fp)

fread(s,n,item,fp)

char *s;

int n;

int item;

FILE *fp;

화일 fp에서 지정된 갯수 만큼의 데이타를 읽어 문자 열 s에 입력

 

 

연 습 문 제

 

[문제 11-1] 화일을 읽어서 대문자는 소문자로 소문자는 대문자로 변환하는 프로그램  

#include <stdio.h>

void main()

     {

          int ch;

          FILE *fp, *fp;

          char filename1[13], filename2[13];

          printf("\n Input filename : ");

          gets(filename1);

          fp=fopen(filename1,"r");

          printf(" Output filename : ");

          gets(filename2);

          fp1=fopen(filename2,"w");

          while((ch=fgetc(fp)) != EOF) {

               if(ch >= 'A' &&ch <='Z')

                    fputc(ch + 32, fp1);

               else if(ch >= 'a' &&ch <='z')

                    fputc(ch-32,fp1);

               else

                    fputc(ch,fp1);

          }

     }

Input filename : in_letter.dat

Output filename : out_letter.dat

c:>type in_letter.dat

Jim Botton, sportscaster and author of Ball Four, on

the reception to his book : "Pete rose would screan at

me from dugout because I recealed too much. Now he's

posing in magazine ads in his underwear.

c:>type out_letter.dat

jIM bOTTON, SPORTSCASTER AND AUTHOR OF bALL fOUR, ON

THE RECEPTION TO HIS BOOK : "pETE ROSE WOULD SCREAN AT

ME FROM DUGOUT BECAUSE i RECEALED TOO MUCH. nOW HE'S

POSING IN MAGAZINE ADS IN HIS UNDERWEAR.

 

 

 

[학습 11-1]  

#include <stdio.h>

void main()

     {

          int ch;

          int i=0;

          char string[100];

          printf("\n Input string : ");

          gets(string);

          do {

               ch=string[i];

               if(ch >= 'A' &&ch <='Z')

                    putchar(ch + 32);

               else if(ch >= 'a' &&ch <='z')

                    putchar(ch-32);

               else

                    putchar(ch);

               i++;

           } while(string[i] != '\0');

     }

Input String : This is Sample Text

tHIS IS sAMPLE tEXT  

 

 

[문제 11-2] 레코드 단위 입·출력 함수를 이용하여 봉급을 계산하는 프로그램  

#include <stdio.h>

#include <string.h>

struct{

     char depart[4];

     char name[20];

     int day;

     float pay;

}work_pay;

void main()

     {

          char numstr[20], flag;

          float money=30000;

          FILE *fp;

          if((fp=fopen("work_pay.rec","ab"))==NULL)

          fp=fopen("work_pay.rec","wb");

          do{

               printf("\nEnter department : ");

               gets(work_pay.depart);

               printf("Enter name : ");

               gets(work_pay.name);

               printf("Enter How much day : ");

               gets(numstr);

               work_pay.day=atoi(numstr);

               work_pay.pay=money * (float)work_pay.day;

               printf("\nPayment per day : %f",money);

               printf("\nTotal Payment:%f",work_pay.pay);

               fwrite(&work_pay,sizeof(work_pay),1,fp);

               printf("\n\nContinue (Y/N)...");

               flag=getche();

          }while(flag != 'N' &&flag != 'n');

          fclose(fp);

     }

Enter department : 3

Enter name : Kang jae sik

Enter how much day : 34

 

Payment per day : 30000.00000

Total Payment : 1020000.00000

Continue (Y/N)...

결과는 "work_pay.rec"라는 화일에 2진 정보로 저장된다.

 

 

[문제 11-3] 화일에 있는 문자의 수를 출력  

 #include <stdio.h>

#include <string.h>

void main(int argc, char *argv[])

     {

          FILE *fp;

          char string[81];

          char filename[13];

          int count=0;

          strcpy(filename,argv[1]);

          if(argc != 2) {

               printf("\n Input filename : ");

               gets(filename);

          }

          if((fp=fopen(filename,"r")) == NULL) {

               printf("\n File not found");

               exit(-1);

          }

          while(getc(fp) != EOF)

          count++;

          printf("\n File <%s >contains %d characters",filename,count);

          fclose(fp);

     }

 Input file name : exam.dat

File <exam.dat >contains 444 characters

 

 

[문제 11-4] 임의의 화일을 읽어서 행을 두 배로 확장하는 프로그램  

#include <stdio.h>

#include <string.h>

void main(int argc, char *argv[])

     {

          FILE *in_fp, *out_fp;

          char in_filename[13], out_filename[13];

          strcpy(in_filename,argv[1]);

          strcpy(out_filename,argv[2]);

          if(argc <3) {

               printf("\n Input filename : ");

               gets(in_filename);

               printf(" Output filename : ");

               gets(out_filename);

          }

          in_fp=fopen(in_filename,"r");

          out_fp=fopen(out_filename,"w");

          double_space(in_fp, out_fp);

          fclose(in_fp);

          fclose(out_fp);

     }

double_space(in_p, out_p)

FILE *in_p, *out_p;

     {

          int c;

          while((c=getc(in_p)) != EOF) {

               putc(c,out_p);

               if(c == '\n')

                    putc('\n',out_p);

          }

     }

 Input filename : in.dat

Output filename : out.dat

c:>type in.dat

This is

a

sample

file

c:>type out.dat

This is

a

sample

file 

 

 

[학습 11-2] 화일의 개행문자를 무시하여 화일의 내용을 한 줄로 길게 늘리는 프로그램  

#include <stdio.h>

#include <string.h>

void main(int argc, char *argv[])

     {

          FILE *in_fp, *out_fp;

          char in_filename[13], out_filename[13];

          strcpy(in_filename,argv[1]);

          strcpy(out_filename,argv[2]);

          if(argc <3) {

               printf("\n Input filename : ");

               gets(in_filename);

               printf(" Output filename : ");

               gets(out_filename);

          }

          in_fp=fopen(in_filename,"r");

          out_fp=fopen(out_filename,"w");

          double_space(in_fp, out_fp);

          fclose(in_fp);

          fclose(out_fp);

     }

double_space(in_p, out_p)

FILE *in_p, *out_p;

     {

          int c;

          while((c=getc(in_p)) != EOF) {

               if(c == '\n')

                    putc(' ',out_p);

               else

                    putc(c,out_p);

          }

     }

Input filename : in.dat

Output filename : out.dat

c:>type in.dat

This is

a

sample

file

c:>type out.dat

This is a sample file  

 

 

[문제 11-5] 화일에 'A'부터 'Z'까지의 문자를 저장하고 해당 위치에 있는 문자를 출력  

 #include <stdio.h>

void main()

     {

          FILE *fp;

          int ch;

          int num;

          char filename[13];

          printf("\n Input file name : ");

          gets(filename);

          fp=fopen(filename,"w");

          for(ch='A'; ch<='Z'; ch++)

          putc(ch, fp);

          fclose(fp);

          if((fp=fopen(filename,"r")) == NULL) {

               printf("\n File not found");

               exit(-1);

          }

          printf(" Record Number = ");

          scanf("%d",&num);

          if(fseek(fp,num-1,0) != 0) {

               perror("Can't move pointer there.");

               exit(-1);

          }

          ch=getc(fp);

          printf("\n Record Number : %d character = %c",num,ch);

          fclose(fp);

     }

 Input file name : in.dat

Record number : 5

Record number : 5 character = e

c:>type in.dat

ABCDEFGHIJKLMNOPQRSTUVWXYZ

 

 

[문제 11-6] 화일을 복사하는 프로그램  

#include <stdio.h>

#include <string.h>

void main(int argc, char *argv[])

     {

          FILE *in_fp, *out_fp;

          char in_filename[13], out_filename[13];

          char ch;

          strcpy(in_filename, argv[1]);

          strcpy(out_filename, argv[2]);

          if(argc <3) {

               printf("\n Input file name : ");

               gets(in_filename);

               printf(" Output file name : ");

               gets(out_filename);

          }

          if((in_fp=fopen(in_filename,"r")) == NULL) {

               printf("\n %s file not found");

               exit(-1);

          }

          out_fp=fopen(out_filename,"w");

          while((ch=getc(in_fp)) != EOF)

          putc(ch, out_fp);

          fclose(in_fp);

          fclose(out_fp);

     }

Input file name : letter.dat

Output file name : letter.bak

c:>type letter.dat

Jim Botton, sportscaster and author of Ball Four, on

the reception to his book : "Pete rose would screan at

me from dugout because I recealed too much. Now he's

posing in magazine ads in his underwear.

c:>type letter.bak

Jim Botton, sportscaster and author of Ball Four, on

the reception to his book : "Pete rose would screan at

me from dugout because I recealed too much. Now he's

posing in magazine ads in his underwear.

  

 

 

[학습 11-3] 두 개의 화일을 합병하는 프로그램  

 #include <stdio.h>

#include <string.h>

#define MAX_LINE 80

void main(int argc, char *argv[])

     {

          FILE *in_fp[2], *out_fp;

          int i;

          char ch;

          char temp[MAX_LINE];

          char *in_filename[2],

          out_filename[13];

          strcpy(in_filename[0],argv[1]);

          strcpy(in_filename[1],argv[2]);

          if(argc <3) {

               for(i=0; i<2; i++) {

                    printf("Input %d-st file name : ",i+1);

                    scanf("%s",in_filename[i]);

               }

          }

          for(i=0; i<=1; i++)

          if((in_fp[i]=fopen(in_filename[i],"r")) == NULL) {

               printf("\n %s file not found",in_filename[i]);

               exit(-1);

          }

          printf("\nMerge file name : ");

          scanf("%s",out_filename);

          out_fp=fopen(out_filename,"w");

          for(i=0; i<2; i++) {

               while((ch=getc(in_fp[i])) != EOF)

               putc(ch,out_fp);

          }

          fclose(in_fp[0]);

          fclose(in_fp[1]);

          fclose(out_fp);

     }

Input 1-st file name : in1.dat

Input 2-st file nsme : in2.dat

Merge file name : out.dat

c:>type in1.dat

Jim Botton, sportscaster and author of Ball Four, on

the reception to his book : "Pete rose would screan at

c:>type in2.dat

me from dugout because I recealed too much. Now he's

posing in magazine ads in his underwear.

c:>type out.dat

Jim Botton, sportscaster and author of Ball Four, on

the reception to his book : "Pete rose would screan at

me from dugout because I recealed too much. Now he's

posing in magazine ads in his underwear. 

 

 

[문제 11-7] 화일을 dump하는 프로그램  

#include <stdio.h>

#include <string.h>

void main(int argc, char *argv[])

     {

          FILE *fp;

          int i;

          char ch;

          char buffer[17];

          char filename[13];

          strcpy(filename,argv[1]);

          if(argc <2) {

               printf("\nInput file name : ");

               scanf("%s",filename);

          }

          if((fp=fopen(filename,"r")) == NULL) {

               printf("\n %d file not found",filename);

               exit(-1);

          }

          do {

               for(i=0; i<16; i++) {

                    ch=getc(fp);

                    if(ch == EOF)

                         exit(1);

                    if(ch <31)

                         ch='.';

                    buffer[i]=ch;

                    printf("%3X",ch);

               }

               buffer[i]='\0';

               printf(" %s",buffer);

               putchar('\n');

          } while(1);

          fclose(fp);

     }

Input file name : letter.dat

20 20 20 4A 69 6D 20 42 6F 74 74 6F 6E 2C 20 73 Jim Botton, s

70 6F 72 74 73 63 61 73 74 65 72 20 61 6E 64 20 portscaster and

61 75 74 68 6F 72 20 6F 66 20 42 61 6C 6C 20 46 author of Ball F

6F 75 72 2C 20 6F 6E 2E 20 74 68 65 20 72 65 63 our, on. the rec

65 70 74 69 6F 6E 20 74 6F 20 68 69 73 20 62 6F eption to his bo

6F 6B 20 3A 20 22 50 65 74 65 20 72 6F 73 65 20 ok : "Pete rose

77 6F 75 6C 64 20 73 63 72 65 61 6E 20 61 74 2E would screan at.

20 6D 65 20 66 72 6F 6D 20 64 75 67 6F 75 74 20 me from dugout

62 65 63 61 75 73 65 20 20 49 20 72 65 63 65 61 because I recea

6C 65 64 20 74 6F 6F 20 6D 75 63 68 2E 20 4E 6F led too much. No

77 20 68 65 27 73 2E 20 70 6F 73 69 6E 67 20 69 w he's. posing i

6E 20 6D 61 67 61 7A 69 6E 65 20 61 64 73 20 69 n magazine ads i

6E 20 68 69 73 20 75 6E 64 65 72 77 65 61 72 2E n his underwear.

2E 2E  

 

 

[문제 11-8] sin함수를 화일에 출력하는 프로그램  

#include <stdio.h>

#include <math.h>

void main()

     {

          FILE *fp;

          char filename[13];

          int num,i;

          float x;

          printf("\nOutput file name : ");

          scanf("%s",filename);

          fp=fopen(filename,"w");

          num=16;

          fprintf(fp,"%d",num);

          for(i=0; i<num; i++) {

               x=sin(2*M_PI/num*i);

               fprintf(fp,"\n%f",x);

          }

     }

Output file name : sin.dat

16

0.000000

0.382683

0.707107

0.923880

1.000000

0.923880

0.707107

0.382683

0.000000

-0.382683

-0.707107

-0.923880

-1.000000

-0.923880

-0.707107

-0.382683  

 

 

[학습 11-4] 위에서 구한 화일을 그래프 형식으로 출력하기  

 #include <stdio.h>

#include <math.h>

#define MAX 100

void main()

     {

          int n;

          float x[MAX];

          file_io(&n,x);

          disp(n,x);

          sgraph(n,x);

     }

disp(int num,float array[])

     {

          int i;

          for(i=0; i<num; i++)

          printf("%d\t%f\n",i,array[i]);

     }

sgraph(int num, float array[])

     {

          int i,j,k=39;

          float fmax=0;

          for(i=0; i<num; i++) {

               if(fabs(array[i]>fmax))

               fmax=fabs(array[i]);

          }

          for(i=0; i<num; i++)

               array[i]/=fmax;

          printf("-1");string(k-2,' ');

          printf("0");string(k-2,' ');

          printf("+1\n");printf("+"); string(k-1,'-');

          printf("+"); string(k-1,'-');

          printf("+\n");

          for(i=0; i<num; i++) {

               j=array[i]*k + 0.5 + k;

               if(j>k) {string(k,' ');printf("+");

               string(j-k-1,'-');printf("*\n");

          }

          if(k==j) {

               string(k,' ');

               printf("*\n");

 

          }

          if(j<k) {

               string(j,' ');printf("*");

               string(k-j-1,'-');printf("+\n");

          }

     }

string(int x,char y)

     {

          if(x >0)

          while(x--)

          putchar(y);

     }

file_io(int *num,float array[])

     {

          FILE *fp;

          int i;

          char filename[13];

          printf("\nInput file name : ");

          scanf("%s",filename);

          if((fp=fopen(filename,"r")) == NULL) {

               printf("\n %s file not found",filename);

               exit(-1);

          }

          fscanf(fp,"%d",num);

          for(i=0; i<*num; i++)

          fscanf(fp,"%f",&array[i]);

     }

 Input file name : sin.dat

00.000000

10.382683

20.707107

30.923880

41.000000

50.923880

60.707107

70.382683

80.000000

9-0.382683

10-0.707107

11-0.923880

12-1.000000

13-0.923880

14-0.707107

15-0.382683

-1 0

+1

+--------------------------------------+--------------------------------------+

*

+--------------*

+---------------------------*

+-----------------------------------*

+--------------------------------------*

+-----------------------------------*

+---------------------------*

+--------------*

*

*--------------+

*---------------------------+

*-----------------------------------+

*--------------------------------------+

*-----------------------------------+

*---------------------------+

*--------------+

표 11.5 표준 입․출력 함수표 11.4 랜덤 처리계 함수표 11.3 기준점의 위치표 11.2 화일 접근 모드표 11.1 <stdio.h>화일의 개방 스트림

Posted by 두장

시스템 관리자들은 정기적으로 로그 파일을 체크하고 관리해야 합니다. 
리눅스에는 보안과 시스템 등에 관련된 다양한 로그 파일들이 존재하며, 주로 /var/log 디렉토리에 싸이게 됩니다. 

dmesg 
Linux가 시작될 때 나타나는 메시지들을 기록한 파일로 터미널에서 dmesg 명령을 입력하면 보여지는 내용과 동일합니다. 
주로 시스템의 구동과 종료시에 문제점이 발생하는 경우 그 원인을 체크해 볼 수 있는 중요한 파일입니다. 
/var/log/messages 를 확인해도 비슷한 내용을 볼 수 있다.

messages 
다양한 서버의 데몬이나 xinetd와 관련된 서비스를 사용할 때 기록되는 로그파일로 데몬에 문제가 발생할 경우 체크합니다. 

secure 
시스템에 로그인하거나 인증을 요하는 작업을 한 경우 기록되는 파일로 보안상 매우 중요한 로그입니다. 

lastlog 
각 사용자가 마지막으로 로그인한 날짜를 기록하고 있습니다. lastlog 명령어를 사용하여 확인할 수 있습니다. 

wtmp 
시스템에 접속한 모든 사용자의 로그를 기록하는 파일로 last, 명령어로 확인 할 수 있습니다. 

xferlog 
FTP 서비스의 엑세스를 기록하는 로그입니다. 

로그 파일의 관리에 소홀하면, 로그 파일이 계속 커져 시스템 FULL 과 같은 장애가 발생하고 
디스크에도 심각한 문제를 일으킬 수 있으므로, logrotate와 같은 프로그램으로 자동으로 로그파일을 순환시켜야 합니다.
Posted by 두장
 
  • 1. IP 주소 막기


  • 이제 Iptables를 사용하기 위한 기본적인 설정에 대해서 알아보자. Iptables는 Kernel 2.4.x 기반의 리눅스 설치시에 기본으로 설치되어있고 /sbin 디렉토리 아래에 있다. 그리고 iptables와 ipchains는 동시에 사용할 수 없으므로 우선 ipchains의 모듈을 내려줘야 한다. 

    아래의 그림처럼 lsmod를 해보고 만약 ipchains 모듈이 올라와 있다면 rmmod ipchains 명령으로 모듈을 내려줘야 iptables 사용이 가능하다. 


    이제 Iptables에 대해서 본격적으로 알아보도록 하자. 

    기본적으로 Iptables에는 세가지 chain이 있고 모든 패킷은 이 세가지 chain중 하나를 통과하게 된다. 이 세가지 chain은 INPUT, OUTPUT, FORWARD chain인데 우선 여러분의 컴퓨터로 들어가는 모든 패킷은 INPUT chain을 통과한다. 그리고 여러분의 컴퓨터에서 나가는 모든 패킷은 OUTPUT chain을 통과한다. 그리고 하나의 네트워크에서 다른 곳으로 보내는 모든 패킷은 FORWARD chain을 통과한다.


    Iptables가 작동하는 방식은 이들 각각의 INPUT, OUTPUT, FORWARD chain에 당신이 어떠한 rule을 세우는 지에 따라 달라진다. 
    예를 들어 당신이 HTML 페이지를 요청하기 위해 www.yahoo.com에 패킷을 보낸다면 이 패킷은 우선 당신 컴퓨터의 OUTPUT chain을 통과하게 된다. 
    그러면 kernel에서 OUTPUT chain의 rule을 확인하고 rule과 match가 되는지 확인을 하게된다. rule중에서 최초로 match되는 것에 의해 당신이 보낸 패킷의 운명이 결정되는 것이다. 
    만약 어떤 rule과도 match되지 않는다면 전체 chain의 정책이 ACCEPT냐 DROP이냐에 따라 패킷의 운명이 결정될 것이다. 그러고 나서 Yahoo! 에서 응답하는 패킷은 당신의 INPUT chain을 통과하게 될 것이다. 

    IP 주소 막기 

    이제 기초적인 개념에 대해서 알아봤으니 실제로 사용해 보도록 하겠다. 

    Iptable을 사용할 때에는 기억해야 할 많은 옵션들이 있으므로 man 페이지(man iptables)를 잘 활용하는 것이 중요하다. 이제 특정 IP를 조종하는 법에 대해서 알아보자. 우선 당신이 200.200.200.1 이라는 IP로부터 오는 모든 패킷을 막고 싶어한다고 가정하자. 우선 -s 옵션이 사용되는데 여기에서 source IP나 DNS name을 지칭할 수 있다. 그러므로 다음과 같이 함으로써 이 IP를 지칭할 수 있다. 


    ./iptables -s 200.200.200.1 


    하지만 위처럼만 명령을 내리면 kernel은 위의 주소에서 오는 패킷을 어떻게 처리해야 할 지를 알 수가 없다. 그러므로 -j 옵션으로 그 패킷을 어떻게 처리해야 하는지 결정해야 한다. 일반적으로 3가지 옵션이 있는데 ACCEPT, DENY, DROP이다. 

    ACCEPT는 대충 예상할 수 있듯이 패킷을 허용하는 옵션이다. DENY 옵션은 컴퓨터가 연결을 허용하지 않는다고 메시지를 돌려 보내는 옵션이다. 그리고 DROP 옵션은 패킷을 완전히 무시해 버린다. 만약 우리가 이 IP에 대해 확실히 의심이 간다면 우리는 DENY 대신에 DROP을 사용해야 할 것이다. 
    그러므로 결과적으론 다음과같이 옵션을 주면 된다. 


    ./iptables -s 200.200.200.1 -j DROP 


    하지만 이 명령만으로는 아직 컴퓨터가 명령을 이해할 수가 없다. 우리는 한가지를 더 추가해야 되는데 바로 어떤 chain의 rule로 적용시킬지 결정해야 하는 것이다. 
    여러분은 -A 옵션을 사용해서 이를 결정할 수 있다. 즉 아까 위에서 본 INPUT, OUTPUT, FORWARD 옵션 중에서 하나를 선택해야 하는 것이다. 이 옵션을 줌으로써 당신이 선택한 chain의 맨 아래부분에 새로운 rule이 추가될 것이다. 
    따라서 우리는 우리에게 들어오는 패킷을 차단하고 싶으므로 INPUT 옵션을 주면 되는 것이다. 그러므로 전체 명령은 다음과 같다. 


    ./iptables -A INPUT -s 200.200.200.1 -j DROP 


    이 한 줄의 명령으로 200.200.200.1로부터 오는 모든 패킷을 무시할 수 있다. 옵션의 순서는 바뀌어도 상관이 없다. 즉 -j DROP이 -s 200.200.200.1 보다 앞에 가도 상관이 없다. 만약 그 반대로 200.200.200.1로 패킷이 못가도록 하려면 INPUT 대신에 OUTPUT을, -s 대신에 -d(destination) 옵션을 주면된다.

     
     
  • 2. Service 차단하기


  • 만약 우리가 해당 컴퓨터로부터 telnet 요청만 무시하고싶다면 어떻게 해야 하는가? 이것도 그다지 어렵지 않다. 일단 큰 범주로 나누어 봤을 때 적어도 3가지의 프로토콜 - TCP, UDP, ICMP - 가 있다. 다른 대부분의 서비스와 마찬가지로 telnet은 TCP 프로토콜로 작동한다. -p 옵션으로 우리는 프로토콜을 결정할 수 있다. 하지만 TCP라고만 옵션을 줘서는 컴퓨터가 인식하지를 못한다. telnet은 TCP프로토콜로 작동하는 특정 서비스에 불과하기 때문이다. 우선 우리가 프로토콜을 TCP로 설정한 다음에는 --destination-port 옵션으로 해당하는 port를 설정해 줘야한다. 
    우선 telnet의 포트번호는 23번이다. 포트번호 대신에 telnet이라 써도 상관없다. 
    여기서 source port 와 destination port를 혼동하면 안된다. 즉 클라이언트는 어떤 포트로도 작동할 수 있는 반면에 서버는 23번 포트로 작동하기 때문이다. 즉 특정 서비스를 차단하기 위해서는 -destination-port를 이용하면 되고, 그 반대는 -source-port를 이용하면 된다. 이제 이들 옵션을 합쳐서 아래와 같이 명령을 주면 된다. 

    ./iptables –A INPUT –s 200.200.200.1 –p tcp --destination-port telnet –j DROP 


    그리고 IP의 영역을 선택하고 싶다면 200.200.200.0/24 와 같이 설정하면 된다. 이것은 200.200.200.* 에 해당하는 모든 IP를 선택하는 것과 같다. 

    선택적인 차단 

    이제 좀더 심화된 내용에 대해서 알아보자. 우선 여러분의 컴퓨터가 local area network(LAN)에 있고, Internet에 접속 가능하다고 가정한다. 알다시피 LAN은 eth0으로 Internet 연결은 ppp0으로 구분할 수 있다. 이제 다시 다음과 같이 가정해 보자. 우리는 telnet 서비스를 LAN상의 컴퓨터에게는 서비스하고 보안상 Internet상에서는 접근하지 못하도록 하고 싶다. 이것 역시 쉽게 구성할 수 있다. 우리는 input interface에 대해서는 -i 옵션을 output interface에 대해서는 -o 옵션을 사용할 수 있다. 즉 다음처럼 명령을 주면 된다. 

    ./iptables –A INPUT –p tcp --destination-port telnet –i ppp0 –j DROP 


    이렇게 함으로써 우리는 LAN상의 사용자는 telnet을 사용하고 그밖에 Internet상의 사용자는 telnet 을 사용하지 못하도록 할 수 있다. 

    Rule 순서에 관하여 
    이제 다음 단계로 들어가기에 앞서서 rule을 조종하는 다른 방법에 대해서 간단히 알아보자. 
    Iptables의 chain에서는 먼저 등록 된 rule이 효력을 발생하기때문에 등록을 하는 순서가 중요하다. 모든 것을 거부하는 설정이 먼저오게 되면 그 이후에 포트를 열어주는 설정이 와도 효과가 없다. 그러므로 허용하는 정책이 먼저오고 나서 거부하는 정책이 와야한다. 

    –A 옵션을 줌으로써 우리는 새로운 규칙을 chain의 맨 아래에 추가하게 된다. 즉 chain상의 상위 rule이 먼저 작동하기 때문에, 만일 새로 추가하는 rule을 먼저 작동시키기 위해서는 -I 옵션을 줌으로써 새로운 rule을 원하는 위치에 놓을 수 있다. 예를 들어 INPUT chain의 가장 위에 어떤 rule을 놓고 싶다면 “-I INPUT 1” 이라 명령하면 된다. 그리고 다른 위치로 놓고 싶다면 1을 다른 숫자로 바꿔주면 된다. 

    그리고 이미 위치된 rule을 다른 위치로 바꾸고 싶다면 -R 옵션을 주면 된다. -I 옵션을 주는 것과 마찬가지로 사용할 수 있는데 다만 -I옵션을 사용해서 1의 위치에 놓으면 다른 rule들이 밑으로 한칸씩 내려가는 반면 -R옵션을 사용해서 1의 위치에 놓으면 그 위치의 rule은 삭제된다. 

    그리고 끝으로 rule을 삭제하고 싶다면 -D옵션과 숫자를 사용하면 되고, -L 옵션을 사용하면 작성된 모든 rule의 목록을 보여주고, -F 옵션을 주면 해당 chain의 모든 rule을 삭제한다. 그리고 만약 chain을 명시하지 않았다면 모든 것을 flush할 것이다.

     
     
  • 3. SYN Packets


  • 좀더 심화된 내용에 대해서 알아보자. 우선 패킷들은 특정 프로토콜을 사용한다. 그리고 프로토콜이 TCP라면 역시 특정 port를 사용한다. 그러므로 여러분 컴퓨터의 모든 포트를 막음으로써 보안을 할 수 있을 것이다. 
    하지만 당신이 다른 컴퓨터에 패킷을 보내면 그 컴퓨터는 당신에게 다시 응답을 해야한다. 그러므로 만약 당신에게 들어오는 모든 포트를 막아버린다면 당신에게 응답하는 패킷도 결국 못 들어오므로 connection을 하는 의미가 없을 것이다. 

    하지만 다른 방법이 있다. 두 컴퓨터가 TCP connection으로 패킷을 주고 받는다면 그 connection은 우선 초기화가 되어야 한다. 

    이것은 바로 SYN packet이 담당한다. SYN packet은 단순히 다른 컴퓨터에게 주고 받을 준비가 되었다는 것만 알려주는 초기화 기능만을 한다. 이제 서비스를 요청하는 컴퓨터는 우선적으로 SYN packet을 보낸다는 것을 알게 되었다. 그러므로 들어오는 SYN packet만 막기만 하면 다른 컴퓨터가 당신 컴퓨터의 서비스를 이용하지 못하게 할 수 있고, 하지만 당신은 그들과 통신할 수 있는 것이다. 

    즉 이와 같이 하면 당신이 먼저 패킷을 보내서 요청이 들어오는 것이 아니면 모두 무시해 버리게 된다. 
    이 옵션을 사용하기 위해서는 선택한 프로토콜 뒤에 --syn이라고 명령을 넣으면 된다. 이제 인터넷으로부터 오는 모든 연결을 막기위해서는 다음과 같이 rule을 정하면 된다. 

    ./iptables –A INPUT –i ppp0 –p tcp --syn –j DROP 


    당신이 만약 웹 서비스를 운영하는 것이 아니라면 이것은 유용한 rule이 될 것이다. 

    만약 당신이 웹서비스를 위해 하나의 포트(예를들어 80번-HTTP)만 열어두고 싶다면 역시 한가지 방법이 있다. 
    바로 “!” 마크를 사용하면 되는데 많은 프로그래밍 언어에서처럼 “!”은 “not”을 의미한다. 

    예를들어 80번 포트만 제외하고 모든 SYN packet들을 막고싶다면 다음과 같이 하면 된다. 


    ./iptables –A INPUT –i ppp0 –p tcp --syn --destination-port ! 80 –j DROP 


    다소 복잡한듯해도 간단한 rule이다. 

    Chain 정책 

    마지막으로 한가지 남은 것이 있다. 이것은 chain의 정책을 바꾸는 것으로 INPUT과 OUTPUT chain은 디폴트로 ACCEPT로 정해져 있고, FORWARD chain은 DENY로 정해져 있다. 
    만약 당신의 컴퓨터를 라우터로 사용하려면 당신은 FORWARD chain의 정책을 ACCEPT로 설정하고 싶을 것이다. 

    이럴때 어떻게 해야하는가? 이것은 매우 간단하다. -P 옵션을 사용하면 된다. 즉 FORWARD chain을 ACCEPT로 정하기 위해선 다음과 같이 명령을 내리면 된다. 


    ./iptables -P FORWARD ACCEPT 

     
  • 4. iptables, 스크립트로 만들어 사용하기


  • 이번에는 iptable 명령어를 편리하게 스크립트로 만들어서 사용해 보자 
    일단 iptables라는 파일을 다음처럼 작성해 보자. 파일의 위치는 /etc/sysconfig/ 아래에 두도록 하겠다. 



    --begin script-- 
    #!/bin/sh 

    # 우선 모든 Rule을 정리한다. 

    /sbin/iptables -F 

    # 다음으로 각각에 대한 정책을 세운다. 

    /sbin/iptables -P INPUT DROP 
    /sbin/iptables -P OUTPUT ACCEPT 
    /sbin/iptables -P FORWARD DROP 

    # localhost에서의 traffic을 받아들인다. 

    /sbin/iptables -A INPUT -i lo -j ACCEPT 

    # 확립된 연결에 대한 Packet을 받아들인다. 

    /sbin/iptables -A INPUT -i eth0 -p tcp ! --syn -j ACCEPT 

    # DNS 응답을 받아들인다. 

    /sbin/iptables -A INPUT -i eth0 -p tcp --source-port 53 -j ACCEPT 
    /sbin/iptables -A INPUT -i eth0 -p udp --source-port 53 -j ACCEPT 

    # 인증 연결을 거부한다(그렇지 않을 경우 메일서버가 오랫동안 타임아웃 상태가 될 것이다.) 
    /sbin/iptables -A INPUT -i eth0 -p tcp --destination-port 113 -j REJECT 

    # echo나 목적지에 도착 못하거나 시간 초과된 icmp packet들을 받아들인다. 

    /sbin/iptables -A INPUT -i eth0 -p icmp --icmp-type 0 -j ACCEPT 
    /sbin/iptables -A INPUT -i eth0 -p icmp --icmp-type 3 -j ACCEPT 
    /sbin/iptables -A INPUT -i eth0 -p icmp --icmp-type 11 -j ACCEPT 

    --end script— 



    위의 스크립트는 하나의 예에 불과하고 기타 ssh나 ftp, samba등을 이용하기 위한 설정사항을 직접 작성해야 한다. 
    파일 작성이 끝났으면 파일에 실행권한을 줘야한다. 보안상 root만 실행할 수 있도록 권한을 변경한 후 위의 스크립트를 실행하면 된다. 

    확인을 하려면 /sbin/iptables –L 이라고 하면 방금 실행시킨 스크립트가 나올 것이다. 

    그리고 부팅시마다 실행을 시키려면 /etc/rc.d/rc.local 파일 맨 아래 부분에 다음처럼 넣으면 된다. 

    if [ -f /etc/sysconfig/iptables ]; then 
    /etc/sysconfig/iptables 
    fi 

    이번 시간에는 Iptables의 기초만을 알아보았다. 여기 있는 정보를 통해서 당신은 기본적인 firewall을 설정할 수 있을 것이다. 하지만 아직 많은 것들이 남아있다. 더 많은 옵션에 대해서 알아보기 위해서 man 페이지를 활용하기 바라고 Iptables에 관련된 심화된 문서들을 참고하기 바란다.

    Reference Site 

    http://kldp.org/Translations/html/Packet_Filtering-KLDP/Packet_Filtering-KLDP-7.html
    http://linux.com/enhance/newsitem.phtml?sid=125&aid=12431
    http://chongnux.klug.or.kr/board/read.php?table=tip1&no=326
    http://linux.co.kr/tips/se.html?keyword=iptables
     
     
    출처:
    Posted by 두장
    nat는 snat와 dnat로 나뉘어 진다.
     
    snat는 출발지 주소를 변한하며 인터넷 공유기가 대표적이다
    아래 그림이 집에서 공유기를 사용해서 ip포워딩을 하는 예이다.
     
    대표적인 명령으로는
    iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -J SNAT --to 211.240.47.128
     
    위의 명령은 pc1~pc3이 192.168.10.0/24 네트워크 주소를 쓰고 공유기의 ip주소가 211.240.47.128일때 내부 pc가 dns에 패킷을 보내도록 하기 위해서 사설 아이피 주소를 공인 아이피 주소로 바꾸어주는 것이다.
     
     
     
    dnat는 도착지 주소를 변환한다.
    아래의 그림이 dnat의 대표격이다..
     
    방화벽에서 들어오는 패킷을 분석해서 내부의 어느 컴퓨터에 패킷을 전달할지를 결정한다.
    대표적으로 사용하는 명령어는
     
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.131 -p tcp --dprot 22 -J DNAT --to 192.168.10.1:22
     
    위 명령은 pc1이 ssh서비스를 하고 있다고 가정하고 방화벽으로 들어오는 목적지 패킷이 22번인 것을 pc1에 보낸것이다.
     
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.131 -p tcp --dprot 80 -J DNAT --to 192.168.10.2:80
     
    위 명령은 pc2가 웹 서비스를 하고 있다고 가정하고 방화벽에서 pc2로 포워딩 하는 것이다.
     
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.131 -p tcp --dprot 21 -J DNAT --to 192.168.10.3:21
     
    위 명령은 pc3가 ftp 서비스를 한다고 가정하고 방화벽에서 pc3로 포워딩 하는 것이다.


     
    인터넷 공유기 설정하기
     
    리눅스로 인터넷 공유기를 만드는 예를 보기로하자
    우선 vmware로 리눅스 시스템 2개를 운영하고 네트워크 영역은 192.168.1.0이며 vmware에서 192.168.1.254가 인테넷을 공유하는 ip주소라고 하자.
     
    다음 그림을 보면서 설명하겠다.

     
     
     
    우선 컴퓨터 A는 랜카드가 2개이다. 그런데 실제 물리적 랜카드가 1개 모자르므로 가상 랜카드를
    만들었다.
     
    이 명령은 #ifconfig 192.168.1.4 eth0:0 up으로 만들 수 있다.
     
    만약에 가상의 랜카드를 사용하지 않고 실제의 랜카드를 사용한다면 eth0:0의 케이트 웨이 주소가
    eth0의 아이피 주소 192.168.1.2가 되어야한다.
     
    컴퓨터 A의 eth0의 게이트웨이는 192.168.1.254인테 이것은 실제로 인터넷을 나갈 수 있는 랜카드의 주소이다.
     
    컴퓨터 B는 기본 게이트웨이로 컴퓨터 A의 eth0:0의 아이피 주소이다.
    왜냐하면 컴퓨터 B가 패킷을 보낼때 외부로 나가기 위해서 사용하는 문이 eth0:0이기 때문이다.
     
    즉 컴퓨터 B에서 데이터를 보내면 컴퓨터 A의 eth0:0을 지나서 eth0을 지나 외부로 나가게 하기 위함이다. 그러나 eth0:0이 실제 랜카드가 아니라 가상의 랜카드이므로 eth0:0에서 eth0으로 패킷이 가도록 게이트웨이를 192.168.1.2로 지정할 수가 없다.
     
    위에 처럼 해놓고 각각의 컴퓨터에서 192.168.1.2~4까지 그리고 254까지 ping을 하면은 핑은 해당 목적지까지 도착한다는 것을 알 수 있다.
     
    그러나 ping www.daum.net를 하면은 www.daum.net의 아이피 주소가 나타나지 않는다는 것을 알 수 있다. 외부에까지 접근을 하기 위해서는
    컴퓨터 A에서
     
    #echo "1" > /proc/sys/net/ipv4/ip_forward
     
    를 해준다.
     
    이것을 해주는 이유는 컴퓨터 B에서 보면은 컴퓨터 A는 자신의 패킷을 외부에 전달해주는 게이트웨이 역할을 한다. 그러므로 컴퓨터 A는 eth0:0에서 받은 패킷을 외부에 전달해줘야 하기 때문에 게이트웨이 역할을 하기 위해서 위와 같은 명령을 하다.
     
    그러나 위의 명령은 휘발성이다. 즉 재부팅을 하고 나면은 아무런 쓸모가 없다.
    영구적으로 하기 위해서는
     
    /etc/sysconfig/network 파일에서
     
    FORWARD_IPV4=YES
     
    로 바꾸어주기를 바란다.
     
     
    iptable명령과 옵션들
     
    iptables -t nat -L  방화벽 정책 확인
    iptables -t nat -F  방화벽 정책 초기화
    iptables -t nat -L --line 방화벽 정책에 줄번호 부여
    iptables -t nat -D POSTROUTING 번호
                             PREROUTING 번호    방화벽 정책 지우기
     
    iptables를 이용한 여러가지 예.
     
     

     
     
     두대의 컴퓨터가 있고 한쪽은 사설아이피와 공인 아이피, 그리고 나머지 하나는 사설 아이피를 쓴다. 오른쪽 컴퓨터가 외부로 나갈때는 공인 아이피로 바꾸어주고 외부에서 내부로 SSH서비스를 요청할때는 왼쪽 컴퓨터에서 오른쪽 컴퓨터로 포워딩한다.
    오른쪽 컴퓨터는 SSH서비스를 실행중이다라고 가정한다.
     
    왼쪽 컴퓨터에서 다음과 같이 설정한다.
     
    iptables -t nat -A POSTROUTING -s 192.168.101.2 -o eth0 -J SNAT --to 211.240.47.139
     
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.139 -p tcp --dport 22 -J DNAT --to 192.168.101.2:22
     
     
     
     

     
     
    위의 예제는 3대의 컴퓨터가 있고 내부에 웹서버와 ssh서버를 돌리고 왼쪽 컴퓨터에서 방화벽 역할을 하는 내용이다.
     
    우선 웹서버 컴퓨터에서
    ifconfig eth0 192.168.101.2
    route add default gw 192.168.101.1
     
    ssh컴퓨터에서
    ifconfig eth0 192.168.101.3
    route add default gw 192.168.101.1
     
    맨 왼쪽 컴퓨터에서는
    iptables -t nat POSTROUTING -s 192.168.101.2 -o eth0 -J SNAT --to 211.240.47.139
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.139 -p tcp --dport 80 -J DNAT 192.168.101.2:80
     
    위는 웹서버에 대하여 한 정책이다. 여기에서 웹서버는 snat, dnat 둘다를 적용시킨 이유는 웹서버는 클라이언트의 요청을 받고 또한 응답을 해야하기 때문이다.
     
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.139 -p tcp --dport 22 -J DNAT 192.168.101.3:22
     
    위의 내용은 ssh서버에 접속할 수 있도록 한 정책이다.
     
     
     

     
     
    *방화벽에서 해야할 내용
    ifconfig eth0:0 192.168.102.1 up
    ifconfig eth0:1 192.168.103.1 up
    ifconfig eth0 211.240.47.138 netmask 255.255.255.128 up
    route add default gw 211.240.47.129
     
    iptables -t nat -A POSTROUTING -s 192.168.102.0/24 -o eth0 -J SNAT --to 211.240.47.138
    iptables -t nat -A POSTROUTING -s 192.168.103.0/24 -o eth0 -J SNAT --to 211.240.37.138
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.138 -p tcp --dport 21 -J DNAT --to 192.168.102.3:21
    iptables -t nat -A PREROUTING -i eth0 -d 211.240.47.138 -p tcp --dport 80 -J DNAT --to 192.168.102.2:80
     
    *아파치 서버에서 해야할 일
    ifconfig eth0 192.168.102.2 up
    route add default gw 192.168.102.1
     
    *ftp 서버에서 해야할 일
    ifconfig eth0 192.168.103.2 up
    route add default gw 192.168.103.1
     
     
    Posted by 두장

    Thread 사용시 UpdateData(false); 는 실행 중에 Debug Assertion Failed라는

    에러는 발생시킨다.

    예를 들면,

    MyThread( CMyDlg *p )
    {
    p->UpdateData(BOOL);
    }
    위와 같은 방법은 않된다.

     

    가능한 방법1.

    GetDlgItem()->SetWindowText(CString); 방법을 사용해서 특정 아이템만

    업데이트를 하는 것이다. 이때, SetWindowText()의 인자 값으로는 CString만 온다는 것에 주의.

    예제.

      int cnt = 100;

      CString num;
      num.Format("%d",cnt);

      Pointers->GetDlgItem(IDC_STATIC_RESULT)->SetWindowText(num);

     


    그러나 콘트롤 하나 하나 직접 처리하는게 번거로워
    UpdateData()로 일괄처리하고 싶으시다면..

    유저메시지를 하나 만들어서 윈도로 쏘세요.. PostMessage( UM_UPDATE) 따위로
    ..
    그래서 그 윈도가 스스로 UpdateData를 실행하도록 하셔야 합니다
    .

    예를 들면
    ..
    #define UM_UPDATE WM_USER

    BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
        ON_MESSAGE( UM_UPDATE, OnUpdateData)
    END_MESSAGE_MAP()

    LRESULT CMyDlg::OnUpdateData( WPARAM wParam, LPARAM lParam)
    {
        UpdateData( FALSE);

        return 0;
    }

    위와 같이 해 놓고.. 필요할때..스레드 상에서 다음과 같이 호출하면 되겠지요
    .

    pDlg->PostMessage( UM_UPDATE);

    pDlg
    CMyDlg의 포인터입니다. CMyDlg가 매인 윈도우라면

    AfxGetApp()->m_pMainWnd
    으로 얻을 수 있으며,
    아니라면 스레드의 파라메터로 넘겨받아 쓰면 되죠
    .

    참고로 MFC가 모든 스레드 환경에서 완전하게 작동하진 않습니다
    .
    스레드로 뭔가를 할 때는 꼭 염두에 두셔야 해요.. -_-;

     

    Posted by 두장
    이전버튼 1 2 3 4 5 이전버튼