레이블이 게임서버인 게시물을 표시합니다. 모든 게시물 표시
레이블이 게임서버인 게시물을 표시합니다. 모든 게시물 표시

2009년 11월 5일 목요일

Log Class 설계

● 클래스:Log Class 설계

현재 상태를 사용자에게 정확하고 자세하게 알려줄 수 있는 유일한 도구이다.

 

로그라는 특성상 어느 곳에서든지 사용하기 편하도록 Singleton클래스를 상속받아 전역 단일체 클래스로 만들자

 

로그를 필요한 때에 남기지 못하고 또 정확하게 남기지 못하면 서버가 제대로 동작하고 있는지, 문제는 없는지에 대한 정보를 정확하게 파악할 수 없다.

 

체계 없이 남겨진 로그 정보는 실제 필요한 로그를 찾는데 시간이 오래 걸 릴 뿐만 아니라 그게 대한 정보가 부족해 결국 시스템 부하만 줄 뿐 기능상으로는 유명무실해 진다.

 

1. Log 클래스의 종류를 나누자

- 알림오류로 나눠 자신이 원하는 정보를 보다 빨리 찾을 수 있도록 설계 하고

2. Log 클래스의 중요도를 나누자

- 각 종류마다 중요도 LOW, NORMAL, HIGH, CRITICAL등 등급을 나누어 쉽게 정보의 중요성을 파악할 수 있게 하자

2-1. 아래 나와 있는 enumLogInfoType은 Log클래스에서 사용할 로그 정보의 분류를 나열한 것이다

enum enumLogInfoType

{

    LOG_NONE= 0x00000000,

    LOG_INFO_LOW= 0x00000001,

    LOG_INFO_NORMAL= 0x00000002,

    LOG_INFO_HIGH= 0x00000004,

    LOG_INFO_CRITICAL= 0x00000008,

    LOG_INFO_ALL= 0x0000000F,

    LOG_ERROR_LOW= 0x00000010,

    LOG_ERROR_NORMAL= 0x00000020,

    LOG_ERROR_HIGH= 0x00000040,

    LOG_ERROR_CRITICAL= 0x00000080,

    LOG_ERROR_ALL= 0x00000100,

    LOG_ALL= 0x000001FF

};

각 등급마다 16진수로 설정하고 OR 연산을 할 수 있도록 2의n승으로 증가시킨다.

- 로그를 저장할 매체 : 파일, 출력 창, 윈도우, DB, TCP, UDP로 분류

enum enumLogStorageType

{

    STORAGE_F ILE= 0x00000000,

    STORAGE_DB= 0x00000001,

    STORAGE_WINDOW= 0x00000002,

    STORAGE_OUTPUTWND= 0x00000003,

    STORAGE_UDP= 0x00000004,

    STORAGE_TCP= 0x00000005

};

위의 enumLogStorageType은 로그를 저장할 매체에 대한 선언이다.

 

로그의 부하로 인해 속도에 문제가 생길 수 있기 때문에 최소한의 처리(로그를 내부 Queue에 넣고 바로 반환)만 하고 내부적으로 틱 쓰레드를 사용하여 일정 시간마다 Queue에 들어있던 로그를 가져와 처리하도록 한다.

서비스 할 때에는 로그를 최소한으로 하여 사용해야 한다.

 

 

3.로그를 남기는 시점

3-1. 에러 로그의 경우 모든 경우에 로그로 남긴다.

- 쉽게 넘긴 작은 에러 하나가 정말 큰 버그를 부른다.

3-2. 일반적인 정보 로그의 경우

- 함수 시작 부분과 모든 패킷 처리 시작 부분에 남기는 것이 좋다.

- 이유는 만약 어떤 처리를 하다 이유 없이 서버 프로세스가 죽었을 경우에 쉽게 그 위치를 파악할 수 있다.

- 모든 함수와 패킷에서 로그를 남긴다면 실제 서비스할 때에는 엄청난 부하가 생길 것이다. 그래서 앞에서 정한 등급에 따라 일정 등급 이하의 정보를 로그로 남기지 않거나 정보 관련 로그는 아예 남기지 않도록 할 수 있다.

 

4.무엇을 로그로 남길 것인가

4-1. 로그가 어떤 함수에서 남겨졌는지 알아야 한다.

4-2. 누구에 의해서 로그가 남겨졌는지를 알아야 한다.

- 시스템일수도 있고 패킷을 받아 남기는 것이라면 패킷을 보낸 해당 클라이언트가 될 수도 있다.

4-3. 로그가 발생되는 시간을 남겨야한다.

4-4. 로그의 종류가 에러라고 하면 에러가 어떤 작업을 하다가 발생한 것인지 남겨야하고 종류가 알림이라면 함수의 인자나 받은 패킷의 프로토콜 내용을 남겨야 한다.

2009년 10월 26일 월요일

서버 프로그래밍 기초

윈도우즈형과 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*를 의미 합니다.

 

32bit 환경에서의 데이터형에 따른 바이트 크기

데이터형

크기

설명

INT

4 바이트

 

INT32

4 바이트

 

INT64

8 바이트

64bit INT형으로 8바이트 크기

FLOAT

4 바이트

 

DOUBLE

8 바이트

 

BYTE

1 바이트

 

CHAR

1 바이트

 

WCHAR

2 바이트

Unicode를 표현하기 위한 데이터형

DWORD

4 바이트

 

USHOT

2 바이트

16bit 만큼의 숫자를 표현할 수 있음

SHORT

2 바이트

 

 

윈도우즈 함수와 ANSI 함수의 비교 및 설명 (대표적 함수)

윈도우즈(Windows)

ANSI

설명

FillMemory

memset

정해진 크기의 메모리에 데이터를 채울 때 사용

ZeroMemory

memset

정해진 크기의 메모리를 0으로 초기화할 때 사용

CopyMemory

memcpy

정해진 크기의 메모리를 복사할 때 사용

MoveMemory

memmove

정해진 크기의 메모리를 이동할 때 사용

[함수 원형]

VOID FillMemory(PVOID Destination, SIZE_T Length, BYTE Fill)

PVOID Destination

SIZE_T Length

BYTE Fill

값을 채울 메모리입니다.

값을 채울 크기입니다.

채울 1바이트 값입니다.

VOID ZeroMemory(PVOID Destination, SIZE_T Length)

PVOID Destination

SIZE_T Length

초기화할 메모리입니다.

초기화할 크기입니다.

VOID CopyMemory(PVOID Destination, CONST VOID* Source, SIZE_T Length)

PVOID Destination

CONST VOID* Source

SIZE_T Length

복사를 해 넣을 메모리입니다.

복사할 원본 메모리입니다.

복사할 크기입니다.

VOID MoveMemory(PVOID Destination, CONST VOID* Source, SIZE_T Length)

PVOID Destination

CONST VOID* Source

SIZE_T Length

옮겨 넣을 메모리입니다.

옮길 원본 메모리입니다.

옮길 크기입니다.

 

TCHAR 사용에 따른 문자열 함수

TCHAR

CHAR

설명

_tcscpy

strcpy

문자열을 복사할 때 사용

_tcsncpy

strncpy

문자열을 정해진 길이만큼 복사한다

_tcscmp

strcmp

문자열을 비교 한다

_tprintf

printf

화면에 문자열을 출력 한다

_stprintf

sprintf

정해진 버퍼에 정해진 형식의 문자열을 입력

_sntprintf

snprintf

정해진 버퍼에 정해진 길이만큼 정해진 형식의 문자열을 입력

[함수 원형]

TCHAR* _tcscpy(TCHAR *strDestination, CONST TCHAR *strSource)

RETURN

TCHAR *strDestination

CONST TCHAR *strSource

strDestination의 포인터

문자열을 복사해 넣을 메모리

원본 문자열

TCHAR* _tcsncpy(TCHAR *strDestination, CONST TCHAR *strSource, SIZE_T count)

RETURNT

CHAR *strDestination CONST TCHAR *strSource SIZE_T count

strDestination의 포인터

문자열을 복사해 넣을 메모리

원본 문자열

복사해 넣을 문자열의 길이

INT _tcscmp(CONST TCHAR *string1, CONST TCHAR *string2)

RETURNT

CONST TCHAR *string1 CONST TCHAR *string2

0일 경우 같고 0이 아닐 경우 같지 않은 문자열

비교할 문자열 1

비교할 문자열 2

INT _tprintf(CONST TCHAR *format, [argument])

RETURNT

CONST TCHAR *format

출력된 문자열의 개수

포맷 문자열

INT _stprintf(TCHAR *buffer, CONST TCHAR *format, [argument])

RETURNT

TCHAR *buffer

CONST TCHAR *format

출력된 문자열의 개수

문자열을 입력할 메모리

포맷 문자열

INT _sntprintf(TCHAR *buffer, SIZE_T count, CONST TCHAR *format, [argument])

RETURNT

TCHAR *buffer

SIZE_T count

CONST TCHAR *format

출력된 문자열의 개수

문자열을 입력할 메모리

입력할 문자열의 개수

포맷 문자열

 

2009년 10월 24일 토요일

기존의 MMORPG의 서버 구성도

- MMORPG 게임 서버 : 인증서버, 게임서버, NPC서버, DBCache서버, DB서버
- 프론트앤드 서버 : 클라이언트가 직접붙는 서버를 프론트앤드
- 백앤드 서버 : 뒤에서 내부아이피로 물리는 서버를 백앤드서버
- 프론트앤드계열 : 로긴서버, 게임서버
- 백앤드계열 : 디비캐쉬, NPC, DB서버

 

 MMORPG는 대규모 멀티플레이어 온라인 롤플레잉 게임(Massively Multiplayer Online Role-playing Game)을 말합니다.

MMORPG에서는 수 천명의 플레이어가 같은 시간에 같은 세계 안에 존재하게 됩니다. 이 것은 항상 흥미로운 것들로 가득 찬 엄청나게 풍부하고 활동적인 요소들을 창출해냅니다.

MMORPG는 광활한 대지와 바다를 둘러싼 거의 무한한 퀘스트를 포함한 수천 시간의 게임플레이를 제공합니다.

월드 오브 워크래프트는 플레이어가 항상 새로운 모험과 장소, 몬스터, 아이템 등을 접할 수 있도록 지속적으로 새로운 컨텐츠를 추가하고 있습니다

 

게임 실행하면 로그인과정이 필요하니까 로그인서버(혹은 인증서버)로 붙어야 겠죠. 인증이 되면 게임서버에 붙을테고 게임서버에 부하를 줄이기 위해서 메신저서버를 따로 떼어서 채팅이나 잡다구리를 떼어내는 경우가 있습니다. 그리고 게임에 필요한 모든 db데이터에 중간 다리 역할을 하는 DB Cache Server가 필요할테고, mmo라면 게임서버에 붙는 NPC서버가 존재하여 게임서버에 몬스터를 Spawn해주겠죠.

크게는 이렇게 인증서버, 게임서버, NPC서버, DBCache서버로 구성되는것이 일반적입니다. DB는 따로 있구요. 부하에 따라서 혹은 효율에 따라서 세분화되어 따로 떼어내거나 동접늘어났을때 서버를 나누는것도 생각해야 하는데.. 처음부터 그수준까지 생각할 필요는 없구요. 위에 4가지 서버가 안죽고 효율적으로 탄탄하게 버티도록 만드는 것이 중요한것 같네요. NPC서버는 성격이 좀 다르니 빼고 나머지 세가지 서버는 각각 더미클라이언트 만개정도 띄워서 스트레스테스트를 통과하면.. 그다음 NPC서버 만들어 붙여보믄 되겠습니다.

처음부터 다만들고 다돌려보긴 빡쎄구요.


여기서 클라이언트가 직접붙는 서버를 프론트앤드, 뒤에서 내부아이피로 물리는 서버를 백앤드서버라 하는데 로긴서버, 게임서버는 프론트앤드계열이고, 디비캐쉬, NPC, DB서버는 백앤드가 되겠네요.


구조는 그리 중요하지 않으니 자신이 할수 있는 간단한거부터 하나씩 구현해보시구 스트레스 테스트 확실하게 해보는 게 좋을거 같네요.


제일 간단한 로긴서버라도 상용서버에서는 최대한 많은 클라이언트를 받아서 로긴을 빨리 처리해줘야하므로 DB에서 매번 아이디, 패스워드 읽어서 비교하고 응답 패킷보내지 않고 내부적으로 Cache를 두고 한번 로그인하면 메모리에 올렸다가 그다음부터는 메모리 검색해서 결과 돌려줍니다. 그러면 패스워드 변경이나 유저 탈퇴등등 캐쉬에서 삭제해야 하는 경우는 삭제도 해야하구요.. 변경된경우는 다시 DB로 Flush를 해줘야 합니다.

복잡하죠. 많은 사용자 받기위해서 제대로 만들라면 끝도 없습니다. DB에서 매번 읽어서 결과 보내주는 것부터 확실하게 만들고 그다음 최적화를 해야겠죠.


제일 복잡한 게임서버나 NPC서버는 게임로직이나 엄청난 규모의 몬스터테이블, 아이템테이블, 스킬테이블 등등..이 들어가므로 유지보수가 쉬워야 하는 효율을 지니고 있어야 하고 (하드코딩보다 스크립트로 서버구조를 변경가능하도록..) 또한 클라이언트가 행동한 어떤 한 패킷의 결과를 계산해서 유효한 반경에 있는 모든 다른 클라이언트에 브로드캐스팅하는 것이 중요한 네트워크 성능 이슈인데, 그래서 보통은 Zone이라고 해서 브로드캐스팅할 영역을 나누거나 기타 다른 여러가지 효율을 위한 기법이 내부적으로 설계가 되어 있어야 합니다.

그리고 프로그래머들이 (저도 포함) 간과하는 문제중에 DB에 스키마 설정이나 테이블, 필드 만들고 최적화 하는일입니다. 이것은 자기가 경력이 안되면 잘하는 사람 하루혹은 며칠을 데려다가라도 제대로 만들어 놔야 합니다. 저장프로시저같은것도 만들어달라고 하구요. 대게 SQL 책보고 대충 만들어 놓고 나서 나중에 MSSQL이 후지다느니 오라클도 돈값을 못한다느니 그럽니다. MSSQL, Oracle, MySQL모두 훌륭합니다. 제대로만 쓴다면...


마지막으로 서버를 MS기반으로 구성할것인지 Unix(Linux)계열로 구성할것인지에서 만드는 사람이 우선 자신있는것으로 해야겠지요. 다 장단점이 있습니다. 제경우는 linux는 많이 못해보고 MS로 주로 작업했구요. linux는 서버 소켓 프로그래밍으로 최근에는 epoll, kqueue, RTS등을 사용하려고 한다던데.. 상용 리눅스 서버는 대부분 아직까지도 select, poll 방식입니다. (제작년기준 -_-) MS는 정보공유가 아무래도 Linux보다는 잘되다 보니 대부분 상용서버도 iocp로 만들죠. 굳이 최신의 기술을 쓰는것은 제 경험상 그다지 중요하지 않더군요.. 가장 정보공유가 잘되는 기술을 선택하는게 좋은것 같습니다. iocp로 한대로 돌려서 처리되는걸 select방식으로 10대 돌리면 된다는 거죠. iocp코딩을 해도 제대로 만들지 않으면 한대로 돌릴수 있는걸 10대이상 돌려야 하는 경우가 나오는걸 많이 봤습니다.

두서없이 쭈욱 덧붙였습니다. 참고가 되시길..

 

출처 : 게임 개발자 네트워크 카페

MMORPG 게임서버 프로그래밍...

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

Q>게임 서버에서 각 클라이언트로 브로드캐스팅이라고 하나요?

 

A>시간 간격 및 데이타 갱신: 플레이어를 예를 든다면 움직인 플레이어만 움직인 플레이어만 그 플레이어의 시야거리내에 있는 다른 플레이어에게 브로드캐스팅합니다. 즉, 움직이지 않는다면 보내지 않는것이 좋습니다.

 

만약 일정한 시간간격이라면 상황에 따라  나눌수가 있는데 제 개인적으로는 전투처럼 바로 처리는 100msec 일반적인 이동은 500~1000msec를 설정합니다.

 

Q>얼마정도 인원의 클라이언트에게 제공하는것이 좋은가?

A>플레이어 시야거리내에 있는 모든 사람에게 해야 합니다.

 

위 내용은 MMORPG를 기준으로 합니다.  캐주얼 게임이면 다를게 설정을 해야 합니다.

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

A> 책추천 및 테스트 방법

1. Scott meyers 가 쓴 책은 전부 보세요. 정말로 좋습니다->Scott meyers는 천재

2. 최근에 번역되어서 나온 GameCoding Complete

3. Win32 멀티 스레드 프로그래밍

4. Win32 SystemProgramming

5. Gems1~4

6. Windows 구조와 원리 그리고 Codes 등등입니다.

7. MSDN 항상 최신의 것을 설치해서 변경된 것을 보세요

Q> 서버 개발

A> 서버 개발을 할때는 꼭 멀티스레드로 만들어야 합니다. 그리고 테스트는 멀티 프로세서

 기반에서 해야 합니다. 즉, 물리적으로 CPU가 두개인 것을 사용하지 못할때는 HyperThreading에서

 개발 및 테스트를 해야합니다. 그리고 물리적으로 컴퓨터를 따로 설치할 수가 없으면 VMWare와

 같은 OS Emulation 소프트웨어를 이용해서 테스트를 해야 합니다. 같은 로컬에서 클라이언트/서버

 테스트는 될 수 있는대로 안하는게 좋습니다.

 


제 답변이 도움이 되었다니 저도 기쁩니다.^^

 

부담갖지 마시고 질문하세요^^ 제가 아는 한 답변드리겠습니다.^^

단,  제 말이 성경책처럼 항상 옳은게 아니라 실수할 수도 있고 잘못 알고있을 수도 있습니다.

 

Q>혹시 게임서버와 시스템에 관해서 책 좀 추천해 주실 수 있을런지요?
>인테넷 주소도 좋습니다.
>
>저는 현재 경력 1년 좀 넘은 클라이언트 프로그래머입니다.
>아직 미흡한 점이 많고 잘 모르는 부분이 많습니다.
>게다가 정보력도 부족해서 인터넷에서 찾는것도 잘 못하였는데,
>경준님께서 강의해주신 것과 또 강연때 알려주신 웹사이트에서
>많은 도움을 받았습니다. 찾다가 보니 몰랐던 것이 많더군요.. ^^;
>특히 gameai.net인가요 거기서 여러가지를 알게되어 좋았습니다.
>
>다시 한번 감사를 드리며,
>바쁘시다라도 좋은 답변 부탁드립니다.
>그럼 늘 좋은 일만 있으시길 기대하며 이만 줄입니다.
>
>추신: 서버프로그래밍을 집에서 제가 테스트 하려면 어떻게 하는게 좋을런지도 조
>언 부탁드립니다.
>아니면 보다 쉽게 제가 테스트를 할수 있는 방법이 있는지도요.

 

A> 책추천 및 테스트 방법

1. Scott meyers 가 쓴 책은 전부 보세요. 정말로 좋습니다->Scott meyers는 천재

2. 최근에 번역되어서 나온 GameCoding Complete

3. Win32 멀티 스레드 프로그래밍

4. Win32 SystemProgramming

5. Gems1~4

6. Windows 구조와 원리 그리고 Codes 등등입니다.

7. MSDN 항상 최신의 것을 설치해서 변경된 것을 보세요

Q> 서버 개발

A> 서버 개발을 할때는 꼭 멀티스레드로 만들어야 합니다. 그리고 테스트는 멀티 프로세서

 기반에서 해야 합니다. 즉, 물리적으로 CPU가 두개인 것을 사용하지 못할때는 HyperThreading에서

 개발 및 테스트를 해야합니다. 그리고 물리적으로 컴퓨터를 따로 설치할 수가 없으면 VMWare와

 같은 OS Emulation 소프트웨어를 이용해서 테스트를 해야 합니다. 같은 로컬에서 클라이언트/서버

 테스트는 될 수 있는대로 안하는게 좋습니다.

 

그럼 즐거운 오후 보내세요


 

 

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

Q>1. VMWare와 같은 OS Emulation 소프트웨어를 사용하면 한 pc에서 서버와 클라이
언트를 동시에 사용가능하단 말씀인지요?

 

A> 네 VMWare 3.0이상을 사용하시면 OS 설치후 네트워크 아이피로 새로 하나 할당

할 수있습니다. 즉, 한 PC에 완전히 분리된 새로운 OS가 작동합니다.

 

Q>2.서버의 예제 소스들이 있는 사이트가 있을까요? 보통 채팅 예제들은 있던데

A>으로 게임서버로 확장이 가능한지요? 전부다 나와있는 사이트는 없습니다.

다만 "MMORPG Game Server Programming for Linux"라는 책에 기본동작하는 완벽한

예제 코드가 있습니다.

 

Q>3. 또한 서버는 db와 연동된다고 들었습니다. db는 어떻게 연동이 되는건지요?

A> 저는 주로 MS-SQL  2000을 이용합니다. 일반적으로 ODBC,ADO를 사용합니다.

솔직히 DB는 VisualC++ 연결해서 쿼리 또는 StoredProc를 호출하는 수준입니다.

이부분은 저도 약합니다.ㅠㅠ

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

Q> 크리티컬 섹션의 단점?

A> 우선 윈도우의 4가지 동기화 객체를 확실히 알고 프로그램 하시기를 권장합니다.

저도 예전에는 거의 CriticalSection을 사용했습니다. 솔직히 CriticalSection이 직관적이고

사용하기가 쉽습니다.

그리고 CriticalSection은 동기화 객체중 속도가 가장 빠르다는 장점이 있습니다.

 

CriticalSection은 커널 객체가 아닙니다.

즉, 커널이 관리하지 않습니다.

그래서 만약 CriticalSection에서 Enter한 후에 그 스레드가 정지하면

DeadLock에 빠집니다.

스레드는 커널에서 관리하기 때문에 스레드는 커널에서 지워서 없애버리지만

CriticalSection은 커널이 관리 하지 않아서 데드락에 빠집니다.

실제로 이런 버그가 발생하면 잡는것도 어렵습니다. 왜냐하면 프로세스는 죽지않고

스레드만 멈추어서 외부에서는 알아차리기가 어렵습니다.

 

또 한가지는 시간 설정입니다. 즉 뮤텍스를 사용하면 WaitForSingleObject API

를 사용해서 스레드 내에서 함수 호출 시간을 관리 할 수있습니다. 만약 100msec안에

처리 못한다면 다른 스레드에 제어권을 넘기거나 하는 여지가 있습니다.

그러나 CriticalSection은 불가능 하죠.

 

분명히 CriticalSection은 잘만 사용하면 강력합니다.

제가 권장하는 것은 최대한 짧게 CriticalSection을 사용하는 것입니다.

 

제가 생각하는 CriticalSection장단점입니다.

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