CATEGORY

분류 전체보기 (73)
세상사는이야기 (27)
회사이야기 (7)
친구들이야기 (6)
공부이야기 (33)
개인적인이야기 (0)

RECENT ARTICLE

RECENT COMMENT

ARCHIVE

LINK



  1. 2008.06.02
    효율적으로 MSDN을 보는 방법
  2. 2008.06.02
    스승의날 행사_20080517
  3. 2008.05.29
    요즘 이러고 있다 -_-;;
  4. 2008.05.29
    나의 첫번째 회사 Tellord
  5. 2008.05.29
    두번째 회사 IPOP
  6. 2008.05.26
    fork 설명 2
  7. 2008.05.22
    MD5란?
  8. 2008.05.21
    Nagle 알고리즘_2
  9. 2008.05.21
    Nagle 알고리즘이란?
  10. 2008.05.21
    Quota란?
신입 개발자를 위한 조언
효율적으로 MSDN을 보는 방법
신영진 codewiz@gmail.com http://www.jiniya.net

윈도우 개발자를 위한 가장 기초적인, 동시에 가장 방대한 레퍼런스가 있다면 바로 MSDN일 것이다. 상당수의 고급 개발자들은 MSDN만 주어진다면 거의 모든 정보를 다 얻을 수 있다고 말하기도 한다. 하지만 아직도 초보 개발자들은 MSDN은 설치해두었지만 그 속에서 정보를 얻고 있지는 못하다. 게시판에 올린 질문에 냉소적으로 올라오는 MSDN을 참고하라는 말에 상처를 받기도 한다. 왜냐하면 정작 본인은 MSDN을 보았으나 정보를 얻지 못했기 때문이다. 이 글에서는 이러한 MSDN을 효율적으로 보는 방법에 대해서 다룰 것이다. 각 함수에 대한 정보를 보고 이해하는 방법에서부터 방대한 MSDN에서 자신이 원하는 정보를 찾기 위한 방법까지 언급할 것이다. 물론 이 과정에서 기본적인 영어 독해 실력은 필수사항이다.

MSDN에서 얻을 수 있는 가장 기초적인 정보는 개별 윈도우 API의 사용방법이다. 여러분이 OpenProcess의 정보를 얻고 싶다면 MSDN을 켜고 색인에서 OpenProcess를 입력하면 된다. 하지만 고민은 이 과정부터 시작된다. 검색된 OpenProcess가 너무 많기 때문이다. 일반적으로 PC에 설치되는 윈도우 운영체제에서 사용되는 OpenProcess 정보를 보고 싶다면 옆에 base라고 붙은 것을 클릭하면 된다.

이렇게 정보를 찾아 왔다면 MSDN은 여러분에게 OpenProcess에 대한 모든 정보를 보여줄 것이다. MSDN의 함수 설명은 총 여섯 개의 카테고리로 이루어진다. 인자 정보(Parameters), 리턴 값(Return Values), 주의 사항(Remarks), 예제 코드(Example Code), 요구 사항(Requirements), 관련 함수(See Also)가 그것이다.  

인자 정보에서 여러분이 이해해야 할 가장 큰 정보는 각 인자의 종류다. 종류는 크게 입력(in), 출력(out), 입출력(in, out)으로 나뉜다. 입력 정보의 대표적인 형태는 OpenProcess의 첫 번째 인자와 같은 것이다. OpenProcess의 첫 번째 인자는 열고자하는 프로세스 핸들의 권한을 설정하는 값으로 설명에 있는 process access rights라고 된 부분을 클릭해서 나오는 정보를 조합해서 넘기면 된다. 출력 정보의 대표적인 형태는 GetWindowText 함수에서 찾을 수 있다. GetWindowText의 두 번째 인자는 윈도우 캡션명을 저장할 문자열 포인터다. 이 공간은 출력용 포인터로 세 번째 인자인(nMaxCount)를 저장할 수 있을 만큼의 공간을 가진 버퍼를 넘겨야 한다. 끝으로 입출력 정보의 대표적인 형태는 GetVersionEx 함수에서 찾을 수 있다. GetVersionEx 함수의 유일한 인자인 lpVersionInfo는 넘기기 전에 dwOSVersionInfoSize에 구조체 크기를 지정해 주어야 한다. 이 후 함수를 호출하면 GetVersionEx 함수는 윈도우 버전 정보를 lpVersionInfo에 담아준다.

리턴 값에서 인지해야 할 가장 중요한 두 가지 정보는 성공한 경우의 리턴 값과 실패한 경우의 리턴 값이다. 또한 실패한 경우에 추가적으로 실패한 원인을 찾을 수 있는 방법에 대해서도 알아두어야 한다. 대부분의 윈도우 API의 경우 GetVersionEx 함수와 같이 성공한 경우에 0이 아닌 값을, 실패한 경우에 0을 반환한다. 또한 실패한 경우에는 추가적인 실패 원인을 GetLastError를 통해서 조회할 수 있다. 종종 GetCurrentProcess와 같이 절대 실패하지 않는 함수들도 있다. 동시에 실패하지만 MSDN에는 실패에 대한 언급이 없는 GetWindowThreadProcessId와 같은 함수도 있다. GetWindowThreadPorcessId 함수는 잘못된 윈도우 핸들이 전달되면 실패하며, 실패여부는 GetLastError를 통해서 알 수 있다.

끝으로 각 함수에 첨부되어 있는 요구 사항 표를 살펴보는 방법에 대해서 알아보자. 요구 사항 표에는 각 함수를 호출할 수 있는 운영체제가 나와 있다. 여기서는 여러분의 제품이 지원하는 운영체제의 하한선이 존재하는 가만 확인하면 된다. Windows 98을 지원해야 하는 제품이라면 VerifyVersion 함수를 정적으로 사용하는 것은 피해야 한다. 이 함수는 Windows 2000 이상부터 사용가능하기 때문이다. 굳이 이 함수를 사용해야 한다면 GetProcAddress로 동적으로 함수 주소를 구해서 사용하는 방법을 택해야 한다.

이제 한 함수의 정보를 알아내는 방법에 대해서 살펴보았다. 하지만 망망대해 같은 MSDN을 탐색하는데에는 이런 방법으로는 한계가 있다. 좀더 효과적으로 다양한 정보를 한번에 살펴볼 수 있는 방법이 필요한 것이다. 이런 방법 중에 하나가 마법과 같은 버튼인 목차 동기화(Sync Contents) 버튼에 있다. OpenProcess 설명 부분에서 이 버튼을 눌러 보자. 그러면 OpenPorcess 설명이 있는 목차로 이동하게 된다. 여기서 여러 분들은 세 가지 중요한 사항을 인지해야 한다. 하나는 OpenProcess가 있는 목차의 위치다. 두 번째는 OpenProcess와 같은 단계에있는 다른 함수들에 대한 정보다. 마지막 정보는 OpenProcess 목차 부위에 있는 기술 문서(Technical Article)이다.
And
01234567891011


2008년 5월 17일 1차 식사후
청주대학교 이공대 구관 과사무실 앞에서...
And
0
And
0

http://www.tellord.com
And
And
 

우선 예재 프로그램을 대충 만들어 보겠습니다.

각 section은 어떤 특정한 일을 하는 부분이고, pid, pid2는 미리 선언했다고 가정합시다.


// section A


pid = fork();

if (pid != 0) {

    // section B

}

else {

    // section C

    pid2 = fork();

    if (pid2 != 0) {

        // section D

    }

    else {

        // section E

    }

    // section F

}


section G



자.. 이제 이 프로그램을 컴파일해서 실행파일을 만들구요...

실행 파일을 실행 시키면 우선 첫 프로세스가 뜨겠죠? 이놈을 P1이라고 부릅시다.

P1은 프로그램이 짜여진대로 section A를 실행하고 pid = fork()문을 만납니다.

그리고 fork()를 실행하지요... 그러면 새로운 프로세스가 만들어지는데 P2라고 부릅시다.


P2는 P1의 환경을 그대로 가져옵니다. 즉, 지금 프로그램이 어디까지 실행되었는가라는

정보까지 그대로 가져오지요.. 그래서 P1도 P2도 모두 fork())이후의 pid = (fork()의 return 값)

pid에 대입하는 부분부터 실행합니다.

자.. 문제는 P1은 fork로부터 P2의 프로세스 ID를 받습니다.

새로 프로세스가 만들어졌으니 당연히 프로세스 ID가 있겠죠?

P2는 자기가 새로 만들어진 놈이므로 그냥 0을 return 받습니다.

따라서 똑같은 부분부터 시작은 하되.... fork()의 return값은 다른 놈을 가지고 P1, P2가 실행됩니다.

이 때, 우리는 주로 P1을 부모, P2를 자식이라고 설명합니다.


바로 다음 if문에 의해서

P1은 section B를 실행하게 되고 P2는 section C를 실행하게 됩니다. 

return 받은 pid가 다르니까 if의 조건이 달라지죠?

P1은 section B를 실행한 후에 당연히 section G를 실행하고 끝납니다.

P2는 section C를 실행하고 다시 fork()를 만납니다.

fork를 실행하면 아시다시피 fork를 호출한 프로세스와 똑같은 프로세스가 하나 더

만들어 집니다.

즉 P2와 똑같은 놈 P3가 만들어지고 fork()로 부터 return을

P2는 P3의 프로세스 ID를 받고

P3는 자신이 fork되었으니 0을 받습니다.

그리고는 똑같은 위치인 pid2 = (fork의 return값) 을 실행합니다.

이때는 P2가 부모이고 P3가 자식이죠?

P2는 section D, F, G를 차례로 수행하고 끝날테구요..

P3는 section E,F,G를 수행하고 끝납니다.


여기서 주의할 점은 각 프로세스가 어느 놈이 먼저 수행될지는 아무도 모른다는 것이고,

이를 위해서 동기화 방법들이 있는 것입니다.


원본 위치 <http://kin.naver.com/detail/detail.php?d1id=1&dir_id=10203&eid=n8OK2wWtO3/UXmPooNhPW2sdQgvDEWQz&qb=Zm9yaw==&pid=fvpKRloQsClssaVBrfdsss--408388&sid=SDpMUhYpOkgAAFsjn@k>

And

위키백과 ― 우리 모두의 백과사전.

암호학에서 MD5(Message-Digest algorithm 5)는 128비트 해시를 제공하는 암호화 해시 함수이다. RFC 1321로 지정되어 있으며 수많은 프로그램과 파일의 무결성 검사에 사용된다.

MD5는 1991년로널드 라이베스트가 예전에 쓰이던 MD4를 대체하기 위해 고안했다. 1996년에는 MD5의 설계상 결함이 발견되었다. 매우 치명적인 결함은 아니었지만, 암호학자들은 SHA-1 같은 다른 알고리즘을 사용할 것을 권장하기 시작했다. 2004년에는 더욱 심한 암호화 결함[1]이 발견되었고 2006년에는 노트북 컴퓨터 한 대의 계산 능력으로 1분 내에 해시 충돌을 찾을 정도로 빠른 알고리즘이 발표[2]되기도 하였다. 사람들은 MD5 알고리즘을 보안 관련 용도로 쓰는 것을 그다지 권장하지 않는다.

〈〈〉〉== 알고리즘 ==

그림 1. 단일 MD5 연산 - MD5는 이러한 연산 64개로 이루어진다. 16개의 연산을 그룹화한 4 라운드로 묶인다. F는 비선형 함수이다; 한 개의 펑션이 각 라운드에 각각 사용된다. Mi는 입력 메시지의 32-비트 블록을 말한다.

s는 s칸 만큼의 레프트 로테이션을 말한다; s는 각 연산 후 값이 변한다. 은 모듈로 232 덧셈을 말한다.

MD5는 임의의 길이의 메시지(variable-length message)를 입력받아, 128비트 짜리 고정 길이의 출력값을 낸다. 입력 메시지는 512 비트 블록들로 쪼개진다; 메시지를 우선 패딩하어 512로 나누어 떨어질 수 있는 길이가 되게 한다. 패딩은 다음과 같이 한다: 우선 첫 단일 비트, 1을 메시지 끝부분에 추가한다. 512의 배수의 길이보다 64 비트가 적은 곳까지 0으로 채운다. 나머지 64 비트는 최초의(오리지널) 메시지의 길이를 나타내는 64 비트 정수(integer)값으로 채워진다.

메인 MD5 알고리즘은 A,B,C,D라고 이름이 붙은 32 비트 워드 네 개로 이루어진 하나의 128 비트 스테이트(state)에 대해 동작한다. A,B,C,D는 소정의 상수값으로 초기화된다. 메인 MD5 알고리즘은 각각의 512 비트 짜리 입력 메시지 블록에 대해 차례로 동작한다. 각 512 비트 입력 메시지 블록을 처리하고 나면 128 비트 스테이트(state)의 값이 변하게 된다.

하나의 메시지 블록을 처리하는 것은 4 단계로 나뉜다. 한 단계를 "라운드"(round)라고 부른다; 각 라운드는 비선형 함수 F, 모듈라 덧셈, 레프트 로테이션(left rotation)에 기반한 16개의 동일 연산(similar operations)으로 이루어져 있다. 오른쪽 "그림 1"은 한 라운드에서 이루어지는 한 연산(operation)을 묘사하고 있다.

함수 F에는 4가지가 있다; 각 라운드마다 각각 다른 F가 쓰인다:

는 각각 XOR, 논리곱, 논리합 그리고 NOT 연산을 의미한다.

[편집] 슈도코드

MD5 알고리즘의 슈도코드는 다음과 같다:

//Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
var int[64] r, k

//r specifies the per-round shift amounts
r[ 0..15] := {7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22} 
r[16..31] := {5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20}
r[32..47] := {4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23}
r[48..63] := {6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21}

//Use binary integer part of the sines of integers as constants:
for i from 0 to 63
    k[i] := floor(abs(sin(i + 1)) × (2 pow 32))

//Initialize variables:
var int h0 := 0x67452301
var int h1 := 0xEFCDAB89
var int h2 := 0x98BADCFE
var int h3 := 0x10325476

//Pre-processing:
append "1" bit to message
append "0" bits until message length in bits ≡ 448 (mod 512)
append bit (bit, not byte) length of unpadded message as 64-bit little-endian integer to message

//Process the message in successive 512-bit chunks:
for each 512-bit chunk of message
    break chunk into sixteen 32-bit little-endian words w[i], 0 ≤ i ≤ 15

    //Initialize hash value for this chunk:
    var int a := h0
    var int b := h1
    var int c := h2
    var int d := h3

    //Main loop:
    for i from 0 to 63
        if 0 ≤ i ≤ 15 then
            f := (b and c) or ((not b) and d)
            g := i
        else if 16 ≤ i ≤ 31
            f := (d and b) or ((not d) and c)
            g := (5×i + 1) mod 16
        else if 32 ≤ i ≤ 47
            f := b xor c xor d
            g := (3×i + 5) mod 16
        else if 48 ≤ i ≤ 63
            f := c xor (b or (not d))
            g := (7×i) mod 16
 
        temp := d
        d := c
        c := b
        b := b + leftrotate((a + f + k[i] + w[g]) , r[i])
        a := temp

    //Add this chunk's hash to result so far:
    h0 := h0 + a
    h1 := h1 + b 
    h2 := h2 + c
    h3 := h3 + d

var int digest := h0 append h1 append h2 append h3 //(expressed as little-endian)
  //leftrotate function definition
  leftrotate (x, c) 
      return (x << c) or (x >> (32-c)); 


주석: RFC 1321에 나온 공식 말고 다음과 같은 공식이 쓰일 수 있다. 다음과 같은 공식을 쓰면 퍼포먼스가 향상될 수 있다. (어셈블리 언어가 사용될 때 유용하다 - 다른 언어가 쓰일 경우에는 대개 컴파일러가 위의 코드를 최적화 해준다.):

(0  ≤ i ≤ 15): f := d xor (b and (c xor d))
(16 ≤ i ≤ 31): f := c xor (d and (b xor c))
And
Nagle 알고리즘


- 작은 data를 tcp layer차원에서 모으고 있다가 ACK에 같이 실려서 보낸다.
- 이 알고리즘은 ACK가 빠르게오면 올수록 packet을 빨리 보낼 수가 있기 때문에
LAN에 적합하다.



이것은 TCP의 동작 메카니즘에서 발생하는 문제이다. TCP에서 interactive data flow인 경우에 하나의 TCP 연결 속에서 클라이언트와 서버 사이에 서로 주고받고 하는 패킷 교환이 일어나게 된다. 이때 1 바이트의 데이타와 20 바이트의 헤더로 구성되는 매우 작은 TCP 패킷들로서 상호간 동작이 연속적으로 일어난다면 트래픽의 혼잡을 가중시킬 수 있다.

이러한 문제를 해결하기 위한 방법이 Nagle 알고리즘이라 하는 것이다. 이미 전송한 패킷이 있을 때 이 패킷에 대한 수신 성공을 알리는 ack 패킷이 도착하기 전까지는 다른 패킷을 전송하지 않고 버퍼에 대기시키도록 한다. 이렇게 기다리는 동안에 몇 개의 패킷이 전송을 위해 대기하게 될 수 있고, ack가 도착했을 때 이들 전송 대기 패킷들을 하나의 세그먼트로 묶어서 전달하도록 할 수 있다.

이러한 메카니즘은 파이프라인 동작에서 문제를 일으킬 수 있다. 왜냐하면 파이프라인을 통해 연속적으로 요구 메시지가 전달되어야 하는데 Nagle 알고리즘에 의해 즉시 전송되지 못하고 잠깐 대기해야 하는 문제가 생기기 때문이다. 이의 해결책은 Nagle 알고리즘을 사용하지 않는 것으로 TCP 동작을 설정하고 패킷 전송을 하면 된다.



TCP_NODELAY는 Nagle 버퍼링 알고리즘을 중지시킬 특별한 목적으로 사용된다. 이것은 전송은 작은 단위로 자주 이루어 지지만 즉각적인 응답은 필요 없는 어플리케이션에서만 사용 되어야 한다.(마우스 움직임 같은)

사용자 삽입 이미지
And

네트웍에서 Nagle 알고리즘은 "가능하면 조금씩 여러번 보내지말고 한번에 많이 보내라(Effective TCP)" 라는 원칙을 기반으로 만들어진 알고리즘입니다. 

WinSock 의경우 기본으로 Navle 알고리즘이 적용이 되어있습니다. 하지만 몇몇 네트웍 관련 프로그램에서는 네트웍 의 전송량이나 부하보다는 빠른 응답속도를 더 중요시 여기는 상황이 있습니다. 그러한때에는 TCP_NODELAY  라는 옵션을 사용하여 Nagle 알고리즘을 제거 할 수 있습니다.

해당 코드를 적용하는 방법은

int nValue = 1;

setsockopt( TCP_NODELAY, &nValue, sizeof(int), IPPROTO_TCP );

의 코드를 사용합니다.

아래는 100Byte 의 패킷을 5번에 걸처서 보내고 에코로 받은 결과입니다.

Nagle 알고리즘 적용 (default) : 100~150ms

Nagle 알고리즘 해제              : 1~3 ms

하지만 해당 옵션의 사용은 네트웍 부하를 극대화 시켜주면서 서버의 전체적인 성능을

무척감소하기때문에 꼭 필요한경우에만 매우 주의를 해서 사용해야 합니다.

추가로 "Effective TCP Programming" 역시 추천도서입니다. ^^

네트웍 프로그램을 향상하는 44가지 팁이라고 하는데 저의 경우

15개정도의 팁만이 쓸모가 있더군요.

출처 : Tong - Mothrah님의 TCP Communication통

And

[디스크 Quota]

다중 사용자를 환경으로 하는 Linux 환경에서 특정 사용자가 시스템의 모든 디스크를 독점하여 사용하게 된다면 큰일이다.


한 사용자에 의해서 독점되는 시스템 자원으로 인해서 다른 사용자는 하고자 하는 작업을 할 수가 없게 된다.

특히, 웹 호스팅을 하는 업체와 같은 경우에는 사용자에게 일정한 디스크 용량만을 사용할 수 있게 하는 기능이 필수적이라고 할 수 있다.

웹 호스팅을 하는 서버의 경우 보통 적게는 100명 많게는 200명의 사용자가 홈페이지를 운영하고 있기 때문에 제한된 자원을 모든 사용자가 사용할 수 있도록 해주어야 한다.

이러한 요구 사항을 충족하기 위해서 사용하는 기능이 디스크 Quota 기능이다. 쿼터 기능을 사용해서 관리자는 사용자마다 일정한 디스크 용량만을 사용할 수 있도록 할 수 있기 때문에 효율적으로 하드 디스크 공간을 사용할 수 있다.
그러면 Quota 기능을 어떻게 설정하고 사용하는지에 대해서 알아보도록 하자.


[ TIP : ]

Window NT 4.0의 경우에는 이 Quota 기능이 없어서 사실상 웹 호스팅을 하거나 많은 사람에게 디스크를 사용하게 한다는 것은 거의 불가능한 일이었다.
필자의 경우는 여러 사람에게 디스크 공간을 한정되게 주기 위해서 파티션을 나누어서 제공한 적이 있다.

그러나 윈도우 2000부터는 쿼터 기능이 지원되기 때문에 요즈음 윈도우 2000과 ASP를 사용해서 웹 호스팅을 하는 업체가 부쩍 늘고 있다.

[출처] 리눅스 공부 - 디스크 Quota|작성자 길당

And