24
Chapter 1 기초

온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

  • Upload
    others

  • View
    16

  • Download
    1

Embed Size (px)

Citation preview

Page 1: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

Chapte r 1

기초

Page 2: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

1 1Cha pter 1 기초

1. 모듈화란

왜 모듈화를 하는가?

모든것을한프로젝트에담아클래스로분리하는것도나쁜방법은아닙니다. 하지만요즘

게임 개발 프로젝트는 그 범위가 커져서 혼자서 모든 것을 개발할 수는 없습니다. 그래서

서버프로그램을엔진모듈, 게임로직모듈, 관리모듈로크게나누어보았습니다. 첫번째,

엔진모듈은주로네트워크통신, 암호화, 메모리관리등의역할을수행하고두번째, 게임

로직모듈은 게임에따라서내용은 달라지겠지만실제게임의 진행을담당하게됩니다. 마

지막으로, 관리모듈은게임을서비스를하면서생길수있는상황에대해서쉽고편리하게

대처하기 위해서 만드는 모듈입니다.

이렇게 3가지로 모듈을 구분해서 관리하면 어떤 장점이 생길까요?

첫번째, 코드의재활용이높아집니다. 어떤게임을만들더라도엔진모듈, 관리모듈은

거의변화가없기때문에재활용을계속할수있습니다. 즉, 새로운게임프로젝트를진

행할때이런게임에서개발해놓은엔진, 관리모듈을재활용할수있다면게임로직에

만 주력하여 개발을 진행하면 됩니다.

두번째, 코드의공유성이높아집니다. 대부분의클라이언트개발자들은네트워크프로

그래밍에대해서는잘모르는경우가많습니다. 그래서서버프로그래머가네트워크모

듈을 따로만들어 주어야하는 경우가많은데, 만약 엔진모듈로 통신모듈이 분리되어

있다면 그 모듈을 제공해 서버와 통신하는 코드를 쉽게 작성할 수 있습니다.

세번째, 코드의관리가편리합니다. 사소한정의나내용을수정할때모듈화가잘되어

있다면간단히그모듈만을수정하면되지만, 만약반대의경우라면검색으로일일이수

정할 부분을 찾아 작업을 해야 합니다.

필자는이러한경우항상모듈화를하고있고, 위의 3가지중엔진모듈과관리모듈은프로

젝트를거치면서점차적으로업그레이드되어새로운프로젝트를진행할때많은도움이되

고 있습니다.

Page 3: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍12

만드는 방법은?

그럼 모듈화에는 어떠한방법이 있을까요? LIB, DLL, COM과같은 모듈화 방법이많이

있지만 여기서는 LIB를 사용해서 모듈화를 하도록 하겠습니다. 지금 이 시점에서 DLL,

COM, LIB의각각의장·단점을들어 LIB가더좋다는주장은별로필요없을것같습니

다. 각자프로젝트에맞는방법으로모듈화를하는것이좋습니다. LIB 파일을만드는방법

은 간단합니다.

[그림 1.1] 프로젝트 생성 화면

위의 그림처럼 프로젝트 파일을 생성하게 됩니다.

Page 4: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

13Cha pter 1 기초

[그림 1.2] LIB 파일 옵션 선택 화면

생성한 후 LIB 파일(정적 라이브러리)로선택만 하면됩니다. 미리 컴파일된헤더 옵션은

개인의취향에따라선택하면되고여기서는필자가사용하는것으로진행하겠습니다. 위의

과정을 거치면 LIB 파일이 하나 만들어지게 되는데, 앞으로 여기에 기본적인 엔진, 관리

모듈을 작업해 보겠습니다.

2. 함수포인터(Delegate)

앞에서모듈화에대해언급을하면서 LIB 파일을생성하는프로젝트를제작해보았습니다.

그럼이 LIB 안에위에서언급한엔진, 관리모듈들을넣어야하겠지만우선서버프로그래

밍에서필수적으로 필요한기초지식에 대해서이야기해나가도록 하겠습니다. 그 첫번째

가 함수 포인터(Delegate)입니다. 일반적으로 모듈화에 대한 기초지식을 많이 가지고 계

신 분들은 필자보다도 더 잘 아시겠지만, 모듈화를 하다보면 어떠한 작업이 일어났을 때

그결과를특정시점에서받고싶은경우가생깁니다. 쉽게생각하면, 윈도우즈프로그래밍

의이벤트와같은역할을하는것이라고생각하면됩니다. 이런함수들은우리가 API로코

딩을하게될때많이보게되는데 Callback 함수들이그대표적인예입니다. 이렇게말로

설명하는 것보다 코드를 직접 보면서 설명하는 것이 이해하기에 더 좋을 것 같습니다.

Page 5: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍14

일단 A라는 프로그래머가 다음과 같은 함수를 만듭니다.

voi d De l egat eSampl e (voi d (*f p) ( i nt ) , i nt dat a){

pr i nt f ( "# De l egat eSampl e f uct i on #\ n" ) ;f p (dat a / 10 , dat a / 100) ;

}

그리고B라는프로그래머는위의함수를이용하기위해서다음과같은코드를작성하게됩니다.

voi d Ca l l back (i nt r e s ul t 1 , i nt r e s ul t 2){

pr i nt f ( "# r e sul t 1 : %d , r e s ul t 2 : %d" , r e s ul t 1 , r e sul t 2) ;}

voi d ma i n (voi d){

De l egat eSampl e (Cal l bac k , 500) ;

}

B라는 프로그래머는 A라는 프로그래머가 만든 dat a를 10으로 나눈 값과 100으로 나눈

값을결과물로반환해주는함수 Delegat eSample를이용해서그결과를리턴값이나파라

미터가아닌함수로받습니다. 이렇게사용할수있는것이함수포인터입니다. 더욱상세한

설명이필요하다면 C/ C+ + 관련서적을참고하기바랍니다. 지금당장보기에는모듈화에

별다른효과가없을것같지만, C+ +의상속을이용한 virtual과함께모듈화에서절대적

으로 필요한 기초적인 내용입니다.

#i nc l ude <s t di o . h>

voi d De l egat eSampl e (voi d (*f p) ( i nt , i nt ) / *함수 포인터선언*/ , i nt dat a ){

pr i nt f ( "# De l egat eSampl e f uct i on #\ n" ) ;f p (dat a / 10 , dat a / 100) ;

}

voi d Ca l l back (i nt r e s ul t 1 , i nt r e s ul t 2) / / 함수 포인터 Cal l back 함수{

pr i nt f ( "# r e sul t 1 : %d , r e s ul t 2 : %d" , r e s ul t 1 , r e sul t 2) ;}

voi d ma i n (voi d){

De l egat eSampl e (Cal l bac k , 500) ;}

Page 6: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

15Cha pter 1 기초

3. 윈도우즈(Windows)형의사용

왜 윈도우즈(W ind ow s )형을 사용하는가?

일반적으로 작업을 할 때 int , char 등의 ANSI 표준형을 사용합니다. 하지만 게임 서버

프로그래밍을할때많은 Windows API들을사용하게되는데, 이들은대부분윈도우즈형

으로 이루어져있습니다. 대부분 ANSI 표준형과 윈도우즈형은비슷하게 사용하지만 나중

에혹시라도생길수있는형변환에따른오류를줄이기위해서윈도우즈형을기본으로하

여 작업을 진행하는 것이 좋습니다. 다음은 앞으로 많이 사용하게 될 윈도우즈형과 ANSI

표준형의 비교 설명입니다.

[표 1.1] 윈도우즈형과 ANSI 표준형의 비교 및 설명

윈도우즈(Windows ) ANSI 설명

BOOL bool TRUE/FALSE 변수

BYTE signed char 8비트 변수

DWORD unsigned long 32비트 정수형 변수

DWORD_PTR unsigned long 32비트 정수형 포인터 변수

FLOAT float 32비트 실수형 변수

INT int 32비트 정수형 변수

INT32 int 32비트 정수형 변수

INT64 __int64 64비트 정수형 변수

CHAR char 8비트 변수

LPCSTR const char * 8비트 문자열 변수

LPCTSTR char* 또는 wchar* MultiByte, Unicode에 따라서 달라짐

VOID void

위의 표에서 설명된 형들이가장 많이 쓰는 변수입니다. 앞으로 보게 될 예제코드는 모두

위의 형에 맞추어 제작됩니다. 위의 형 설명을 보면 조금 특이한 것이 있는데, 바로

LPCTSTR입니다. 이것을풀어서쓰자면 CONST TCHAR*라고할수있는데, 이것에대

한 자세한 설명은 다음에 다시 하겠습니다(더 많은 윈도우즈형에 대해서 알고 싶다면

MSDN에서 Windows Data Types라는 섹션을 보면 됩니다) .

Page 7: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍16

사용 권장 함수

윈도우즈형이외에우리가많이쓰는메모리관련함수들역시윈도우즈함수로제공되는것

들이 많이 있습니다. 여기서는 앞으로 사용하게 될 대표적인 몇 가지를 설명해 보겠습니다.

[표 1.2 ] 윈도우즈 함수와 ANSI 함수의 비교 및 설명

윈도우즈(Windows ) ANS I 설명

FillMemory memset 정해진 크기의 메모리에 데이터를 채울 때 사용한다.

ZeroMemory memset 정해진 크기의 메모리를 0으로 초기화할 때 사용한다.

CopyMemory memcpy 정해진 크기의 메모리를 복사할 때 사용한다.

MoveMemory memmove 정해진 크기의 메모리를 이동할 때 사용한다.

[함수 원형]

VOI D Fi l l Memory(PVOI D Dest i nat i on, SIZE_T Lengt h, BYTE Fi l l )

PVOI D Dest i nat i on : 값을 채울 메모리입니다.SIZE_T Lengt h : 값을 채울 크기입니다.BYTE Fi l l : 채울 1바이트 값입니다.

VOI D Ze roMemory(PVOI D Dest i nat i on, SIZE_T Lengt h)

PVOI D Dest i ncat i on : 초기화할 메모리입니다.SIZE_T Lengt h : 초기화할 크기입니다.

VOI D CopyMemory(PVOI D Dest i nat i on, CONST VOI D* Source , SIZE_T Lengt h)

PVOI D Dest i nat i on : 복사를 해 넣을 메모리입니다.CONST VOI D* Source : 복사할 원본 메모리입니다.SIZE_T Lengt h : 복사할 크기입니다.

VOI D MoveMemory(PVOI D Dest i nat i on, CONST VOI D* Source , SIZE_T Lengt h)

PVOI D Dest i nat i on : 옮겨 넣을 메모리입니다.CONST VOI D* Source : 옮길 원본 메모리입니다.SIZE_T Lengt h : 옮길 크기입니다.

위의설명된 함수들을보면파라미터로 SIZE_T라는형을볼수 있는데, 32비트환경에서

는 크게 관계없지만 64비트로 넘어가고 있는 현재에는 중요한 형입니다. 보통 SIZE-T는

unsigned int로 선언되어있고, SIZE_T라는변수를 쓰는것은 메모리관련한 함수를쓸

때많이 볼수있습니다. 즉, SIZE_T는형으로사용된변수들은메모리 주소를나타낼때

Page 8: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

17Cha pter 1 기초

사용됩니다. 일반적인 32비트에서는 32비트만큼일것이고, 64비트에서는 64비트만큼일

것입니다. 만약 SIZE_T를무작정 32비트로 생각하고코딩을 하게 되면나중에 64비트로

코드를 바꿀 때 문제가 생길 수 있으니 주의해야 합니다.

TCHAR의 사용

일반적으로우리는ANSI 표준형인 CHAR형에익숙합니다. 이러한환경을 Mult iByte 환

경이라고 부르며 영문과 같이 한 문자가 8비트로 되어 있는 환경을 처리하기 좋은 형입니

다. 물론 한글을 CHAR형에서 사용하려면 몇 가지 편법을 이용해야 하지만 사용상의 큰

문제는없습니다. 하지만해외로 게임을수출했을때 문자열코드로인한 문제를최소화하

기 위해서문자열을 Unicode로처리하는 것이좋습니다. 하지만일부 Mult iByte 형태의

프로젝트도지원해야하는경우를대비하여나온것이 TCHAR입니다. TCHAR로선언된

변수는컴파일옵션에서어떤것을선택하느냐에따라 Mult iByte 형태와 Unicode 형태로

자동으로변환되어사용할수있게됩니다. 하지만이렇게편리하게사용할수있을것같은

TCHAR도 역시 주의하고, 신경을 써야 할 작업이 몇 가지 있습니다.

[그림 1.3] 컴파일 옵션에서 MultiByte, Unicode 변경하는 화면

Page 9: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍18

첫번째, TCHAR형의데이터를직접 CopyMemory 등의함수로핸들링할때는조심해야

합니다. sizeof(TCHAR)는 옵션에 따라서 그 사이즈가 틀려질 수 있으므로 다음과 같이

코드를 작성해 주어야 합니다.

TCHAR Sampl eDat a [64] ;Ze ro (Sampl eDat a , 64 * s i zeof (TCHAR) ) ;

만약 위의 코드에서 * sizeof(TCHAR)가 없다면 Mult iByte 환경에서는 크게 문제가 없

겠지만 Unicode 환경에서는사이즈에문제가생겨데이터에문제가생길수있습니다. 즉,

Mult iByte 환경에서는 정상적으로 메모리가 초기화되겠지만, Unicode 환경에서는 절반

만 초기화되는현상이발생하게 됩니다. 이것은 매우중요한문제이므로 꼭신경써서코드

를 작성하기 바랍니다.

두번째, 포인터연산을할때주의해야합니다. CHAR형은 1바이트이므로습관적으로포

인터 + 1, - 1 연산을 할 때 당연히 1바이트씩 움직인다고 생각합니다. 하지만 TCHAR의

Unicode일 경우는 + 1을하면 실제적으로 2바이트가움직입니다. 간단히예를 들어설명

하자면 다음과 같습니다.

TCHAR Sampl eDat a [64] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,0 } ;TCHAR *pPoi nt e r = Sampl eDat a + 6 ;

위와 같이 코드를 작성하게 되면 pPoint er는 Mult iByte이거나, Unicode이거나 무조건

값 7을 가리키게 됩니다. 즉, Unicode일 경우는 2바이트이므로 + 6을 하면 4라는 것은

잘못된 생각입니다. 포인터 연산을 할 때 + , - 는 앞의 변수의 형을 따라가게 됩니다. 첫

번째 사항과 두번째 사항이 워낙에버그가 많이 생길수 있는 중요한사항이다 보니 샘플

코드를 하나 더 보도록 하겠습니다.

#i nc l ude <t cha r . h>#i nc l ude <wi ndow. h>

voi d _t ma i n (voi d){

TCHAR Sampl eDat a [10] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,0 } ;

TCHAR *pPoi nt e r = Sampl eDat a + 6 ;

BYTE Dat a [64] = {0 , } ;

Page 10: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

19Cha pter 1 기초

CopyMemo r y ( Dat a , *pPoi nt e r , 2 * s i zeof (TCHAR) ) ;}

첫 번째에서 언급했던 것처럼 CopyMemory에서 * sizeof(TCHAR)를 하지 않는다면

Unicode 환경에서실제원하는길이만큼의복사가힘들게됩니다. 결론적으로위코드에서

Dat a 변수에는 7, 8의 값이 들어가게 되겠습니다.

세 번째, 기존에 사용하던 문자열 함수들을 변경해 주어야 합니다. 즉, 기존에 strcpy ,

st rcmp 등의 함수를 바꾸어 주어야 하는 것입니다. 대표적인 함수들은 다음과 같습니다.

[표 1.3] TCHAR 사용에 따른 문자열 함수

TCHAR CHAR 설명

_tcscpy strcpy 문자열을 복사할 때 사용합니다.

_tcsncpy strncpy 문자열을 정해진 길이만큼 복사합니다.

_tcscmp strcmp 문자열을 비교합니다.

_tprintf printf 화면에 문자열을 출력합니다.

_stprintf sprintf 정해진 버퍼에 정해진 형식의 문자열을 입력합니다.

_sntprintf snprintf 정해진 버퍼에 정해진 길이만큼 정해진 형식의 문자열을 입력합니다.

[함수 원형]

TCHAR* _t cscpy(TCHAR *st rDest i nat i on , CONST TCHAR *st rSource)

RETURN : st rDest i nat i on의 포인터

TCHAR *st rDest i nat i on : 문자열을 복사해 넣을 메모리TCHAR *st rSource : 원본 문자열

TCHAR* _t csncpy(TCHAR *st rDest i nat i on, CONST TCHAR *st rSource , SIZE_T count )

RETURN : st rDest i nat i on의 포인터

TCHAR *st rDest i nat i on : 문자열을 복사해 넣을 메모리

CONST TCHAR *st rSource : 원본 문자열SIZE_T count : 복사해 넣을 문자열의 길이

Page 11: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍2 0

I NT _t cscmp(CONST TCHAR *st ri ng1, CONST TCHAR *st ri ng2)

RETURN : 0일 경우 같고 0이 아닐 경우 같지 않은 문자열CONST TCHAR *st ri ng1 : 비교할 문자열 1CONST TCHAR *st ri ng2 : 비교할 문자열 2

I NT _t pri nt f (CONST TCHAR *f ormat , [a rgument ] )

RETURN : 출력된 문자열의 개수CONST TCHAR *f ormat : 포맷 문자열

I NT _st pri nt f (TCHAR *buf f e r , CONST TCHAR *f ormat , [a rgument ] )

RETURN : 출력된 문자열의 개수TCHAR *buf f e r : 문자열을 입력할 메모리CONST TCHAR *f ormat : 포맷 문자열

I NT_s nt pri nt f (TCHAR *buf f e r , SIZE_T count , CONST TCHAR *f ormat , [a rgument ] )

RETURN : 출력된 문자열의 개수TCHAR *buf f e r : 문자열을 입력할 메모리SIZE_T count : 입력할 문자열의 개수CONST TCHAR *f ormat : 포맷 문자열

네 번째, 사용하는 대부분의 문자열을 _T("")로 묶어주어야 합니다.

_t pr i nt f ( "TEST STRI NG\ n") ; / / 에러_t pr i nt f (_T( "TEST STRI NG\ n" ) ) ; / / 성공

_T("")는 해당 문자열을 옵션에 따라서 Mult iByte나 Unicode 형태로 변경시켜 줍니다.

위의 3가지를 주의한다면 Mult iByte 환경과 Unicode 환경 모두를 지원하는 서버 엔진,

관리모듈을제작할수있습니다. 다음부분에서는엔진모듈을만들면서꼭알아야할클래

스와 상속에 대하여 알아보도록 하겠습니다.

4. 클래스와상속

상속이란?

아마 C+ + 기초서를보면제일먼저다루면서가장많이나오는내용이상속일것입니다.

다중상속, public 상속, private 상속, friend 등상속에관련된내용만해도책의대부분

을 차지할정도입니다. 일단여기서는상속에 대한전반적인내용을 다루는것보다는앞으

Page 12: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

2 1Cha pter 1 기초

로제작할엔진모듈에서사용될부분들만언급하고넘어가도록하겠습니다. 상속은간단히

설명하자면 부모 클래스의 내용들을 물려받는다는 내용입니다. 그럼 상속을 왜 써야 할까

요? 여러가지 중요한이유가있겠지만앞으로제작될엔진에서 상속을쓰는가장큰이유

는첫번째로코드의재활용, 두번째로 virtual의사용, 세번째로기능별클래스분리입니

다. 이유에대한설명은앞으로진행하면서알아보도록하고, 일단상속을쉽게설명한코드

를 보면서 상속의 기초적인 지식을 알아보겠습니다.

cl a s s CUse r{pr i vat e :

TCHAR m_ s zUse r I D[64] ; / / 아이디TCHAR m_ s zPas swo r d [64] ; / / 암호

TCHAR m_ s zName [64] ; / / 실명TCHAR m_ s zAdd r e s s [64] ; / / 주소

USHORT m_usAge ; / / 나이

publ i c :/ / 생성자CUs e r (VOI D){

/ / 위의 TCHAR 설명에서 언급되었던 형태의 코드입니다./ / Ze r oMemo r y를 할 때 길이를 s i zeof (TCHAR) 로 곱해주었습니다.Ze roMemo ry (m_ s zUse r I D, s i zeof (TCHAR) * 64) ;Ze roMemo ry (m_ s zPas swo r d , s i zeof (TCHAR) * 64) ;Ze roMemo ry (m_ s zName , s i zeof (TCHAR) * 64) ;Ze roMemo ry (m_ s zAdd r e s s , s i zeof (TCHAR) * 64) ;

m_ usAge = 0 ;}/ / 소멸자~CUse r (VOI D) {}

/ / LPCTSTR은 CONST TCHAR*를 의미합니다.VOI D Set Use r I D( LPCTSTR szUs e r I D, LPCTSTR s zPas swo r d){

/ / 넘어오는 파라미터의 NULL 체크는 필수i f ( !s zUse r I D | | !s zPas swo r d)

r et ur n ;

/ / 일반 _t c s cpy를 사용하지 않고 _t c sncpy를 사용했습니다._t c s ncpy (m_ s zUse r I D, s zUse r I D, 64) ;_t c s ncpy (m_ s zPas swo r d , s zPas swo r d , 64) ;

}

VOI D Set Use r I nf o r mat i on ( LPCTSTR s zName , LPCTSTR szAddr e s s , USHORT usAge){

i f ( !s zName | | !s zAdd r e s s )r et ur n ;

Page 13: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍2 2

_t c s ncpy (m_ s zName , szName , 64) ;_t c s ncpy (m_ s zAdd r e s s , s zAdd r e s s , 64) ;

m_ usAge = usAge ;}

} ;

/ / 게임에서 사용하는 사용자 클래스cl a s s CGameUs e r : publ i c CUs e r{pr i vat e :

TCHAR m_ s zCha r act e r Name [64] ; / / 게임 캐릭터이름USHORT m_us Level ; / / 캐릭터 레벨

publ i c :VOI D Set GameI nf o r mat i on ( LPCTSTR szCha r act e r Name , USHORT us Leve l ){

i f ( !szCha r act e r Name)r et ur n ;

_t c s ncpy (m_ s zCha r act e r Name , s zCha r act e r Name , 64) ;

m_ us Leve l = us Level ;}

} ;

/ / 웹에서 사용하는 사용자 클래스cl a s s CWebUse r : publ i c CUse r{pr i vat e :

TCHAR m_ szBoa r dName [64] ; / / 게시판 필명

publ i c :VOI D Set WebI nf o rmat i on ( LPCTSTRs zBoa r dName){

i f ( !szBoa r dName)r et ur n ;

_t c s ncpy (m_ s zBoa r dName , s zBoa r dName , 64) ;}

} ;

위의 코드를 보면 부모 클래스가 되는 CUser라는 클래스와 그것을 각각 상속받은

CGameUser , CWebUser를 볼 수 있습니다. 만약 CUser라는 클래스가 없었다면

CGameUser , CWebUser는 공통적으로 CUser의 내용을 각각 포함해야 합니다. 즉, 첫

번째 이유로언급했던코드 재활용의예입니다. 또한기능적인측면에서 보자면사용자정

보를가지고있는 CUser 클래스를게임에서사용하는 CGameUser 클래스와웹에서사용

하는 CWebUser 클래스가 각각 기능별로상속받은 것입니다. 즉, 그클래스의 쓰임에 따

라서 기능별로분리가되었습니다. 이렇듯클래스의 상속을이용하면편리함을 얻을수있

Page 14: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

2 3Cha pter 1 기초

습니다. 그리고앞의코드를자세히살펴보면몇가지코드작성의노하우를발견할수있는

데, 첫번째파라미터 NULL 체크입니다. 잘못된포인터주소는프로그램을크래쉬시키는

가장큰 이유이므로항상서버 프로그래밍을할때는 파라미터를꼭체크하고 넘어가는버

릇을들이는것이좋습니다. 두번째는배열형변수의보호입니다. 일반적으로문자열복사

를 하려면 _tcscpy를사용하겠지만 파라미터로 넘어오는문자열의 길이가 실제들어갈 버

퍼의 길이보다 크게 온다면 문제가 될 수 있습니다. 그래서 _tcsncpy를 사용해서 읽어올

사이즈를지정하여포인터문제가생기지않게미리방지하는것입니다. 이러한 n이들어가

는 함수들은 거의 대부분의 문자열 함수에 존재합니다.

v irt ua l의 쓰임

앞에서 간단히 상속의 샘플 코드를 보았습니다. 이번에는 중요한 항목 두 번째로 꼽았던

virtual입니다. 한 가지 상황의 예를 들어서 설명해보겠습니다. A라는 프로그래머가

CUser 클래스를만들어놓았습니다. 그런데 CGameUser를만든 B라는프로그래머가그

클래스를쓰다 보니 SetUserID 함수를실행하는도중에 사용자아이디값을 설정하는코

드이후에 하고싶은작업이 생겼습니다. B라는 프로그래머가자신만을위해서 CUser 클

래스를 수정할수 없는 상황입니다. B프로그래머가 A 프로그래머에게 수정을요청하자 A

프로그래머는 virtual을 이용한 가상 함수하나를 넘겨주었습니다. B 프로그래머는 그 가

상 함수를 이용해서 문제를 해결했습니다. 다음은 그 내용의 코드입니다.

cl a s s CUse r{pr i vat e :

TCHAR m_ s zUse r I D[64] ; / / 아이디TCHAR m_ s zPas swo r d [64] ; / / 암호

TCHAR m_ s zName [64] ; / / 실명TCHAR m_ s zAdd r e s s [64] ; / / 주소

USHORT m_usAge ; / / 나이

/ / 가상 함수를 pr ot ect ed로 선언합니다.pr ot ect ed :

vi r t ual VOI D OnUpdat edUs e r I D(VOI D) = 0 ;

publ i c :/ / 생성자CUs e r (VOI D){

/ / 위의 TCHAR 설명에서 언급되었던 형태의 코드입니다.

Page 15: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍2 4

/ / Ze roMemo ry를 할 때 길이를 s i zeof (TCHAR) 로 곱해주었습니다.Ze roMemo ry (m_ s zUse r I D, s i zeof (TCHAR) * 64) ;Ze roMemo ry (m_ s zPas swo r d , s i zeof (TCHAR) * 64) ;Ze roMemo ry (m_ s zName , s i zeof (TCHAR) * 64) ;Ze roMemo ry (m_ s zAdd r e s s , s i z eof (TCHAR) * 64) ;

m_ usAge = 0 ;}/ / 소멸자~CUs e r (VOI D){

}

/ / LPCTSTR은 CONST TCHAR*를 의미합니다.VOI D Set Use r I D( LPCTSTR s zUse r I D, LPCTSTR s zPas swo r d){

/ / 넘어오는 파라미터의 NULL 체크는 필수i f ( !szUs e r I D | | !s zPas swo r d)

r et ur n ;

/ / 일반 _t c s cpy를 사용하지 않고 _t c sncpy를 사용했습니다._t c s ncpy (m_ s zUse r I D, szUs e r I D, 64) ;

/ / 여기서 가상 함수를 호출합니다.OnUpdat edUse r I D( ) ;

_t c s ncpy (m_ s zPas swo r d , sz Pa s swo r d , 64) ;}

VOI D Set Use r I nf o r mat i on ( LPCTSTR szName , LPCTSTR szAddr e s s , USHORT usAge){

i f ( !szName | | !s zAdd r e s s )r et ur n ;

_t c s ncpy (m_ s zName , szName , 64) ;_t c s ncpy (m_ s zAdd r e s s , s zAdd r e s s , 64) ;

m_ usAge = usAge ;}

} ;

/ / 게임에서 사용하는 사용자 클래스cl a s s CGameUs e r : publ i c CUs e r{pr i vat e :

TCHAR m_ s zCha r act e r Name [64] ; / / 게임 캐릭터 이름USHORT m_us Level ; / / 캐릭터레벨

publ i c :VOI D Set GameI nf o r mat i on ( LPCTSTR szCha r act e r Name , USHORT us Leve l ){

i f ( !szCha r act e r Name)r et ur n ;

_t c s ncpy (m_ s zCha r act e r Name , s zCha r act e r Name , 64) ;

Page 16: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

2 5Cha pter 1 기초

m_ us Leve l = us Level ;}

VOI D OnUpdat edUse r I D(VOI D){

/ / 여기서 B는 자신이 하고싶은 일을 하면됩니다._t pr i nt f (_T( "Updat ed Use r I D" ) ) ;

}} ;

이런식으로 상속받은클래스를사용할 때가상함수를 이용하면부모클래스의 실행시퀀

스에 참여할 수 있습니다. 어떻게 보면 함수 포인터와 비슷한 형태로 사용이 가능합니다.

5. 템플릿(Template)

템플릿(Templat e)을쉽게설명하자면어떠한형이들어와도처리할수있게하기위해만

들어진키워드라고볼수있습니다. 이부분도나중에엔진모듈을만들었을때상당히많이

쓰이게 되는 부분입니다. 간단한 예제 코드를 보면서 설명하도록 하겠습니다.

/ / t empl at e 선언t empl at e <cl a s s T>T add (T a , T b){

r et ur n a+b ;}

I NT add2 (I NT a , I NT b){

r et ur n a+b ;}

VOI D _t mai n (VOI D){

_t pri nt f (_T("%d, %f , %d , %f ") , add(10 , 15) , add(10 .6, 11.8) , add2(10 .6, 11.8) , add2(10 .6, 11.8) ) ;}

위의 코드는 템플릿의 사용을간단하게 예를 든 코드입니다. 일단 templat e <class T>를

선언하게 되면 T는 하나의형으로 사용이가능합니다. 즉, T는 INT형이 들어오면 INT형

으로, FLOAT형으로되면 FLOAT형으로인식이되는것입니다. 템플릿을이용하여 add

함수를 만들고, add(10 , 15)처럼 정수형 값을 넣으면 INT형으로 인식해서 INT 결과를

나오게 해주고, add(10 .6 , 11.8)처럼 실수형 값을 넣으면 FLOAT형으로 인식해서

Page 17: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍2 6

FLOAT 결과가나오게합니다. 템플릿과비교하기위해서 add2라는함수를하나더만들

었습니다. add2는 int형으로만들어진함수로, 만약데이터를실수형으로입력하면결과는

정수형으로 나오게 됩니다.

6. 연산자오버로딩(Operator Overloading)

간단히설명하자면기존에사용하고있는연산자의기능이외의기능을정의해서쓴다는뜻

입니다. 즉, 우리가흔히쓰는 = , - >, . 등을다른의미로정의해서쓰는것입니다. 예제를

보면서 설명하겠습니다.

cl a s s CSt r eam{publ i c :

BYTE *mBuf f e r Poi nt e r ;DWORD mLengt h ;

} ;

cl a s s CSt r eamSP{publ i c :

CSt r eamSP(VOI D){

St r eam = new CSt r eam( ) ;}

~CSt r eamSP(VOI D){

de l et e st r eam;}

CSt r eam* ope r at o r - >(VOI D){

r et u r n St r eam;}

ope r at o r CSt r eam* (VOI D){

r et u r n St r eam;}

pr i vat e :CSt r eam *St r eam;

} ;

Page 18: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

2 7Cha pter 1 기초

앞의코드는간단한스마트포인터를사용한것입니다. new/ delete에대한부담을줄이기

위해서 클래스를 지역변수처럼 선언해서 사용하는 방법입니다. 다시 설명을 하자면,

CStream이라는클래스가있고그것의생성, 삭제를관리하는클래스로 CSt reamSP라는

클래스를 만든 것입니다. 이렇게 되면 CSt reamSP Stream ; 이런 식으로 선언하게 되면

생성자에서 new를하게되고 자동으로개체가없어질 때, 즉 함수가종료될때 delete 하

게됩니다. 하지만 CStreamSP의멤버인 *Stream에대한접근이힘들어지기때문에 2가

지 연산자 오버로딩을 통해서 기존에 포인터 변수를 쓰는 것처럼 쓸 수 있게 하였습니다.

operator - >는 만약 CSt reamSP를 CStreamSP Stream ;이라고 선언해서 사용할 때

Stream- >m_Length 이런식으로 접근할수 있게해줍니다. 그리고 Conversion은 cout

<< Stream << endl ;이라고 할 때 에러가 나지 않고 CStreamSP의 멤버인 *Stream의

주소를리턴하게됩니다. 이런식으로기존의연산자를재정의해서쓸수있는방법이연산

자오버로딩(Operator Overloading)입니다. 이외에 new, delete overloading 등이있

지만, 그것은 실제 엔진 모듈을 보면서 설명하도록 하겠습니다.

7. 서버프로그램의생각방식

메모리 관리의 비교

속도위주로프로그래밍을할때가장고려되는사항은무엇일까요? 바로 new/ delet e입니

다. new/ delete를 할 때는 생각 외로 많은 시간이 소모되고, 작은 메모리를 자주

new/ delet e할경우단편화로인해전체적인성능저하가일어나게됩니다. 반응속도가생

명과도같은서버프로그램에서는절대피해야할요소중에하나입니다. 이런 new/ delete

를 피할 수 있는 방법은 처음부터 st at ic하게 메모리를 전부 alloc한 뒤 사용하는 방법과

MemoryPool을사용하는방법 2가지가있습니다. 앞으로함께제작할엔진모듈에서는이

두 가지 기법을 모두 사용해 보겠습니다.

TYPE에 대한 집착

우리는 정수형을 넣어야 한다면 무조건 INT로 선언하는 버릇이 있습니다. 하지만 이러한

버릇은나중에문제를일으킬수있는많은위험성을가지고있습니다. 하나의변수를선언

Page 19: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍2 8

하고형변환을할때, 꼭문제가없는지다시한번확인하고넘어가는버릇을들이는것이

좋습니다.

형 변환의 방법

우리는일반적으로형변환이라고하면앞에 (type*) 이런식으로형변환을하게됩니다.

하지만 좀 더 깊이 살펴보면 형 변환에는 dynamic_cast <type>, st at ic_cast<type>,

reinterpret_cast<type>, const_cast<type>가 있는 것을 알 수 있습니다. 첫 번째로

dynamic_cast<type>은 서로상속 관계에 있는객체의 포인터나 레퍼런스끼리형 변환을

할때사용하는방법입니다. 일반적으로 (type*)으로형변환을하는것은dynamic_cast<type>

입니다. 두번째로 static_cast<type>은논리적으로가능한형변환만을가능하게합니다. 즉, 상

속관계에있는포인터끼리만변환이됩니다. 세번째로 reinterpret_cast<type>은거의제약

이없는형변환방법으로서로다른형태의포인터형끼리도바꿀수있고일반숫자도포인

터형으로 변환할수있습니다. 대신이러한 변환에대해서는컴파일러가 책임을지지않습

니다. 마지막으로 const_cast <type>은 const가 있는 것을 const가 없는 것으로 바꿀 때

사용하는형변환입니다. 이러한형변환도제대로알고쓰는것이성능에많은도움을주니

꼭 쓰는 습관을 들이는 것이 좋습니다.

co ns t의 생활화

엔진모듈을만들때매우중요한사항입니다. 꼭정의해놓은형이입력되어야할경우사

용하게 됩니다. 엔진을제작한 프로그래머와사용하는 프로그래머는다를 수있으므로, 이

것은 꼭 한 가지 형으로만 입력해야 된다는 것을 알려줄 필요가 있습니다. 이 부분 역시

TYPE에 대한 집착과 같이 습관화하는 것이 좋습니다.

8. 스레드(Thread)

여기서는서버프로그램에서가장많이쓰이며, 그리고가장중요한스레드에대해서알아보

도록하겠습니다. 많은프로그래머들이단일스레드프로그래밍에대해서는많이익숙하지만

다중스레드프로그래밍에대해서는거부감이있거나잘모르는경우가많습니다. 하지만서

버프로그래머가되기위해서는다중스레드환경에익숙해져야할필요가있습니다. 그럼왜

Page 20: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

2 9Cha pter 1 기초

스레드를써야할까요? 가장큰이유는서버프로그램은한사용자의요청을처리하기 위해서

다른사용자가기다려서는안되기때문입니다. 그래서다중스레드를이용하여사용자의요

청에 대해 바로바로 응답을 주어야 합니다. 스레드의 기초가 되는 호출은 CreateThread

API 함수입니다. 하지만더많은옵션을이용하려면, C+ + 라이브러리의_beginthread나

_beginthreadex를사용할수있습니다. 이제부터는스레드사용을위해알아두어야할함수

들에 대해서 설명하도록 하겠습니다.

HANDLE Creat eThread(LPSECURITY_ATTRI BUTES l psa , DWORD cbSt ack,LPTHREAD_START_ROUTI NE l pSt a rt Addr , LPVOI D l pvThreadPa ram, DWORD f dwCreat e ,LPDWORD l pI DThread) : 스레드를 생성합니다.

RETURN : 생성되는 스레드의 핸들LPSECURITY_ATTRI BUTES l psa : 항상 NULL이여야 하는 값DWORD cbSt ack : 하나의 스레드를 생성하기 위해서 할당하는 메모리LPTHREAD_START_ROUTI NE l pSt a rt Addr : 스레드 작업을 하는 콜백 함수의 함수 포인터LPVOI D l pvThreadPa ram : 콜백 함수로 넘길 파라미터 값DWORD f dwCreat e : 스레드 생성 후의 상태 결정LPDWORD l pI DThread : 생성된 Thr ead I D 값

여기서 눈여겨볼 파라미터는 cbStack입니다. 현존하는윈도우즈에서관리할수 있는최대

영역은 4Gbytes입니다. 이것의 크기는 32bit가 표현할 수 있는 수의 크기와 일치합니다.

이중프로그래머가사용할수있는메모리의크기는 2Gbytes인데, cbStack의특별한옵션

을주지않으면스레드 1개당 1Mbytes의메모리를사용하게됩니다. 즉, 스레드가 2000개

생성되면모든메모리를모두사용하게되는것입니다. 이것이하나의연결에한개의스레

드를 할당하는 형태의 소켓 서버 구조가 2000개 이상의 연결을 받을 수 없는 이유입니다.

VOI D Exi t Thread(DWORD dwExi t Code) : 스레드를 종료합니다.

RETURN : 없음DWORD dwExi t Code : 스레드가 종료되면서 출력하는 수치로, Get Exi t CodeThread로 가져올 수 있습니다.

BOOL Te rmi nat eThread(HANDLE hThread , DWORD dwExi t Code) : Cl eanUp 없이 스레드를 바로 종료시킬 때 사용합니다.

RETURN : 성공일 경우 TRUEHANDLE hThread : 종료해야 하는 스레드 핸들

DWORD dwExi t Code : 스레드가 종료되면서 출력하는 수치로, Get Exi t CodeThread로 가져올 수 있습니다.

Page 21: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍30

DWORD SuspendThread(HANDLE hThread) : 스레드를 잠깐 멈출 때 사용합니다.

RETURN : 실패할 경우 0xFFFFFFFF를 리턴합니다.HANDLE hThread : 잠시 멈출 스레드의 핸들 값

DWORD ResumeThread(HANDLE hThread) : 잠시 멈춘 스레드를 다시 실행할 때 사용합니다.

RETURN : 실패할 경우 0xFFFFFFFF를 리턴합니다.HANDLE hThr ead : 다시 진행할 스레드의 핸들 값

지금까지꼭알아야할스레드관련 API 함수를알아보았습니다. 자세한것은나중에서버

를 제작하면서 예제를 통해 알아보겠습니다.

9. 파이버(Fiber)파이버라고하면생소하다고느끼는분들이많으리라생각됩니다. 흔히사용하는것은아니

지만 CPU의성능을최대한 끌어내어작업해야될 내용이있다면파이버가 그해결책이라

생각됩니다.

스레드는 선점 방식으로 멀티태스킹을 합니다. 시스템이 작업 시간이 끝났다고 결정을 하

면, 작업스레드에서 CPU를빼앗아다른작업스레드에게 CPU를할당합니다. 그러나좀

더긴시간동안 CPU를점유하기를원하는경우파이버를사용하게됩니다. 그럼파이버에

서 사용하는 기본 API 함수에 대해서 알아보도록 하겠습니다.

LPVOI DWI NAPI Conve rt ThreadToFi be r ( LPVOI D l pPa ramet e r): 메인 스레드를 파이버로 변환하는 함수입니다.

RETURN : 성공일 경우 파이버 주소가 나오게 됩니다.LPVOI D l pPa ramet e r : 파이버에 넘길 파라미터 값

LPVOI DWI NAPI Creat eFi be r (DWORD dwSt ackSi ze , PFI BER_START_ROUTI NE l pSt a rt Address ,LPVOI D l pPa ramet e r) : 파이버를 생성합니다.

RETURN : 성공일 경우 파이버 주소가 나오게 됩니다.DWORD dwSt ackSi ze : 1개의 파이버를 생성할 때 할당할 메모리 크기PFI BER_START_ROUTI NE l pSt a rt Address : 파이버에서 사용할 콜백 함수

Page 22: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

3 1Cha pter 1 기초

LPVOI D l pPa ramet e r : 파이버에 넘길 파라미터 값

VOI DWI NAPI Swi t chToFi be r (LPVOI D l pFi be r) : 파이버를 다른 파이버로 바꿀 때 사용합니다.RETURN : 없음LPVOI D l pFi be r : 바꿀 파이버의 주소 값

그럼 지금까지 알아본 API를 이용해서 간단한 예제를 만들어 보도록 하겠습니다.

#i nc l ude <wi ndows . h>

VOI D *f i be r [4] ;

VOI D f i be r 0 (VOI D*){

whi l e (TRUE){

f o r (I NT I =1 ; i <4 ; i ++)Swi t chTo Fi be r ( f i be r [ i ] ) ;

}}

VOI D CALLBACK f i be r 1(VOI D*){

whi l e (TRUE){

__t p r i nt f ( " Fi be r 1\ n" ) ;Swi t chTo Fi be r ( [0] ) ;

}}

VOI D CALLBACK f i be r 2 (VOI D*){

whi l e (TRUE){

__t p r i nt f ( " Fi be r 2\ n" ) ;Swi t chTo Fi be r ( [0] ) ;

}}

VOI D CALLBACK f i be r 3(VOI D*){

whi l e (TRUE){

__t p r i nt f ( " Fi be r 3\ n" ) ;Swi t chTo Fi be r ( [0] ) ;

}}

VOI D mai n (VOI D){

f i be r [0] = Conve rThr eadToFi be r (NULL) ;f i be r [1] = Cr eat eFi be r (0 , f i be r 1 , NULL) ;f i be r [2] = Cr eat eFi be r (0 , f i be r 2 , NULL) ;f i be r [3] = Cr eat eFi be r (0 , f i be r 3 , NULL) ;

Page 23: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

온라인게임서버프로그래밍32

f i be r0 (NULL) ;get cha r ( ) ;

}

10. Critical Section(임계구역)

보통일반적인다중스레드동기화방법은뮤텍스로알고있을것입니다. 하지만어느순간

에오직하나의스레드만호출하기원하는함수를가지고있다면? 물론뮤텍스를사용할수

도있겠지만뮤텍스는간단한작업을위해서많은오버헤드를가집니다. 이러한상황을해결

하기 위해서 윈도우즈는 Crit ical Sect ion (임계구역)을 제공합니다. Crit ical Sect ion은

간단한변수를플래그로이용해서여러개의스레드가동일한부분의코드를실행하는것을

막습니다. 그럼 API 함수들을 살펴보도록 하겠습니다.

voi d I ni t i a l i zeCri t i cal Sect i on(LPCRITI CAL_SECTI ON l pCri t i cal Sect i on): Cri t i cal Sect i on 개체를 초기화합니다.

RETURN : 없음LPCRITI CAL_SECTION l pCri t i cal Sect i on : 초기화할 CRITI CAL_SECTION개체의 주소를 넣어줍니다.

voi d Del et eCri t i cal Sect i on(LPCRITI CAL_SECTION l pCri t i cal Sect i on): Cri t i cal Sect i on을 삭제합니다.

RETURN : 없음LPCRITI CAL_SECTION l pCri t i cal Sect i on : 삭제할 CRITI CAL_SECTION개체의 주소를 넣어줍니다.

voi d Ent e rCri t i cal Sect i on(LPCRITI CAL_SECTION l pCri t i cal Sect i on): Cri t i cal Sect i on에 들어갑니다.

RETURN : 없음LPCRITI CAL_SECTION l pCri t i cal Sect i on : 사용할 동기화 개체

voi d LeaveCri t i cal Sect i on(LPCRITI CAL_SECTION l pCri t i cal Sect i on): Cri t i cal Sect i on을 빠져나올 때 사용합니다.

RETURN : 없음LPCRITI CAL_SECTION l pCri t i cal Sect i on : 사용할 동기화 개체

Page 24: 온라인 게임 서버 프로그래밍 · 2009-12-02 · 12 온라인게임서버프로그래밍 만드는방법은? 그럼모듈화에는어떠한방법이있을까요? lib, dll,

3 3Cha pter 1 기초

동일한 부분의 코드를 실행하는 것을 막기 위해서 CRITICAL_SECTION 변수를 정의

하고 그 주소를 Init ializeCrit icalSect ion으로 전달합니다. 그런 다음, 임계 함수는

EnterCrit icalSect ion과 함께 시작됩니다. 다른 스레드가 보호 함수 내부에 존재한다

면, 이 호출은 첫 스레드가 완수될 때까지 대기하게 됩니다. 그 후 더 이상 Crit ical

Sect ion이필요하지않다면, LeaveCrit icalSect ion 후 Delet eCrit icalSect ion을호출

하면 Crit ical Sect ion을빠져나온후이와연관되었던자원을모두해제하게됩니다. 이

Crit ical Sect ion의자세한예제는앞으로제작할기초라이브러리에서다시알아보도록

하겠습니다.

11. 마무리지금까지 가장 기초적인 부분에 대해 알아보았습니다. 이번 챕터에서는 엔진 모듈과 관리

모듈을만들기위해서사용하는부분들만다루었기때문에내용적인면으로는많이부실할

수있습니다. 좀더심도있는기초공부를원한다면 C/ C+ + 기술서를참고하기바랍니다.

다음 챕터부터는 앞에서 다룬 내용들을 기초로 하여 엔진 라이브러리 중 기초 라이브러리

제작에 대해서 설명하겠습니다.

모든프로그래머들에게그렇지만특히서버프로그래머에게는기초가매우중요합니다. UI가하나도

존재하지 않는 서버 프로그래머들은 매일 매일 검은 바탕의 흰 글씨만을 보면서 작업해야 하고 좀

더 예쁘고 편리한 것이 주된 작업이 아니라 좀 더 빠르게 성능 좋게 만드는 것이 중요합니다.