GCGC- CGCII 서버 엔진에 적용된 기술 (6) - CGCII Server Sample
1. Sample ServerCGCIICho sanghyun’s Game Classes II
1. Component of CGCII Server System
2. Simple Server
3. Simple Client
4. Message Sending/Reading
5. Easy to development
2. CGCIICho sanghyun’s Game Classes II
실행처리 CGCII Server System (1)
• 접속을 받는 Socket 객체
• 접속이 들어오면 내 부적으로 NEW<TSOCKET> 으로 소켓 객체를 생성해서 접속 처
리 !
• Socket 객체
• TSOCKET 을 묶어서 관리해줄 객체
// 1) Socket 을 NEW<> 를 사용해서 생성
CGPTR<CSocket> pSocket = NEW<CSocket>()
…
// 2) 접속된 Socket 으로 메시지 전송하려 하면 ..
pSocket->Send([ 전송할 내용 ])
// 1) Socket 을 NEW<> 를 사용해서 생성
CGPTR<CSocket> pSocket = NEW<CSocket>()
…
// 2) 접속된 Socket 으로 메시지 전송하려 하면 ..
pSocket->Send([ 전송할 내용 ])
• 재정의 가능한 다양한 virtual 로 선언된 훅 함수들이 존재함 .
virtual void OnConnect()→ 접속될 때 호출됨
virtual void OnFailConnect() → 접속실패 때 호출됨
virtual void OnDisconnect () → 접속 종료될 때 호출됨
virtual void OnMessage(…) → 메시지 전송되어 오면 호출됨
3. CGCIICho sanghyun’s Game Classes II
실행처리
class CSocket :
public CGNetSocket::CTCP<>
{
private:
virtual void OnConnect() { printf(“ 접속되었다” );}
virtual void OnDisconnect() { printf(“ 접속 종료되었다 .”);}
virtual DWORD OnMessage(CGMSG& p_rMSG) { printf(“ 메시지 왔다 .”); return TRUE;}
};
class CSocket :
public CGNetSocket::CTCP<>
{
private:
virtual void OnConnect() { printf(“ 접속되었다” );}
virtual void OnDisconnect() { printf(“ 접속 종료되었다 .”);}
virtual DWORD OnMessage(CGMSG& p_rMSG) { printf(“ 메시지 왔다 .”); return TRUE;}
};
3. 훅 (Hook) 함수를 재정의 한다 .
OnConnect: 접속되었을 때 호출
OnDisconnect: 접속종료 되었을 때 호출
OnMessage: Message 가 도착했을 때 호출
1. Socket Class 를 상속받는다 .
Server Coding (1)
#include "stdafx.h"
#include "Socket.h"
CGOBJ<CGNetAcceptor::CBase<CSocket>> g_acceptor;
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
g_acceptor.Listen(20000);
while(_getch()!=27);
return 0;
}
#include "stdafx.h"
#include "Socket.h"
CGOBJ<CGNetAcceptor::CBase<CSocket>> g_acceptor;
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
g_acceptor.Listen(20000);
while(_getch()!=27);
return 0;
}
3. Acceptor 선언
4. 20000 번 port Listen 시작
5. ESC 누를 때까지 대기 !
끝
,
public NCGPoolable<CSocket>
2. Pool 에서 할당받도록…
4. CGCIICho sanghyun’s Game Classes II
실행처리 Server Coding (2)
이걸로 서버 동작 !
특별한 초기화하지 않아도 기본
Thread, Pool, Socket 등등 내부적으로 초기화 처리됨 !
이보다 더 쉬울 수 있나요 ?
5. CGCIICho sanghyun’s Game Classes II
실행처리
class CSocket :
public CGNetSocket::CTCP<>,
public CGNetIO::Connector::NTCP
{
private:
virtual void OnConnect() { printf(“ 접속되었다” );}
virtual void OnFailConnect() { printf(“ 접속실패 !”);}
virtual void OnDisconnect() { printf(“ 접속 종료되었다 .”);}
virtual DWORD OnMessage(CGMSG& p_rMSG) { printf(“ 메시지 왔다 .”); return TRUE;}
};
class CSocket :
public CGNetSocket::CTCP<>,
public CGNetIO::Connector::NTCP
{
private:
virtual void OnConnect() { printf(“ 접속되었다” );}
virtual void OnFailConnect() { printf(“ 접속실패 !”);}
virtual void OnDisconnect() { printf(“ 접속 종료되었다 .”);}
virtual DWORD OnMessage(CGMSG& p_rMSG) { printf(“ 메시지 왔다 .”); return TRUE;}
};
3. OnFailConnect() 추가 . 나머지는 똑같음 .
1. 동일하게 Socket Class 를 상속받는다 .
Client Coding (1)
#include "stdafx.h"
#include "Socket.h"
CGOBJ<CSocket> g_socket;
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
g_socket.Connect(“localhost”, 20000);
while(_getch()!=27);
return 0;
}
#include "stdafx.h"
#include "Socket.h"
CGOBJ<CSocket> g_socket;
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
g_socket.Connect(“localhost”, 20000);
while(_getch()!=27);
return 0;
}
4. Socket 선언
5. local host:20000 번에 접속 시도한다 .
2. IConnector 도 상속받는다 .(Connect 기능을 위해 )
CGExecutor::Default::InitInstance(CGEXECUTOR_NOTHREAD);
for(;;)
{
CGExecutor::Default::RunExecutor();
if(_kbhit()==1 && _getch()==27) break;
}
Ex2) No-Thread 이므로 매번 호출해주어야 함 !
Ex1) No-Thread 로 동작하기 위한 설정 !
( 이걸 설정하지 않으면 자체 Thread 를 생성해
서 처리됨 .)
6. ESC 누를 때까지 대기 !
No Thread 로 동작시키고 싶다면 ?No Thread 로 동작시키고 싶다면 ?
역시 끝
6. CGCIICho sanghyun’s Game Classes II
실행처리
접속 때 MESSAGE_CHATTING 메시지를 전송하게 하려면…
void CSocket::OnConnect()
{
CCGBuffer bufSend = MEM_POOL_ALLOC(1024);
bufSend.Append<WORD>();
bufSend.Append<WORD>(MESSAGE_CHATTING);
bufSend.Append<int>(5);
bufSend.AppendString<char>(“Hello CGCII World”);
bufSend.SendMessageLength();
Send(bufSend);
}
void CSocket::OnConnect()
{
CCGBuffer bufSend = MEM_POOL_ALLOC(1024);
bufSend.Append<WORD>();
bufSend.Append<WORD>(MESSAGE_CHATTING);
bufSend.Append<int>(5);
bufSend.AppendString<char>(“Hello CGCII World”);
bufSend.SendMessageLength();
Send(bufSend);
}
1. CCGBUFFER 에 메모리를 할당한다 .
Message Sending (1)
2. Append 를 사용해서 전송할 메시지를 작성한다 .
3. 전송한다 .
7. CGCIICho sanghyun’s Game Classes II
실행처리
구조체로 써넣는 방법은 기본적으로 지원한다 .
void CSocket::OnConnect()
{
SMESSAGE_TEST temp;
temp. sizeMessage = sizeof(SMESSAGE_TEST);
temp. wMessage = MESSAGE_TEST;
temp. iValue = 5;
CCGBuffer bufSend = MEM_POOL_ALLOC(sizeof(SMESSAGE_TEST));
bufSend.Append<SMESSAGE_TEST>(temp);
Send(bufSend);
}
void CSocket::OnConnect()
{
SMESSAGE_TEST temp;
temp. sizeMessage = sizeof(SMESSAGE_TEST);
temp. wMessage = MESSAGE_TEST;
temp. iValue = 5;
CCGBuffer bufSend = MEM_POOL_ALLOC(sizeof(SMESSAGE_TEST));
bufSend.Append<SMESSAGE_TEST>(temp);
Send(bufSend);
}
Message Sending (2)
1. struct 를 선언해 값을 설정
2. Append 로 한번에 써넣는다 .
3. 전송한다 .
struct SMESSAGE_WELCOME
{
WORD sizeMessage;
WORD wMessage;
int iValue;
};
struct SMESSAGE_WELCOME
{
WORD sizeMessage;
WORD wMessage;
int iValue;
};
9. CGCIICho sanghyun’s Game Classes II
실행처리
받은 MESSAGE_WELCOME 메시지를 읽기…
void CSocket::OnMessage(CGMSG& p_rMSG)
{
CGNETMSG& rMSG = (CGNETMSG&) p_rMSG;
CCGMemoryPtr ptrBuffer = p_rMSG.Buffer;
WORD wSize = ptrBuffer.ExtractHead<WORD>();
WORD wMessage = ptrBuffer.ExtractHead<WORD>();
int iValue = ptrBuffer.ExtractHead<int>();
const char* strValue = ptrBuffer.ExtractHeadString<char>();
…
}
void CSocket::OnMessage(CGMSG& p_rMSG)
{
CGNETMSG& rMSG = (CGNETMSG&) p_rMSG;
CCGMemoryPtr ptrBuffer = p_rMSG.Buffer;
WORD wSize = ptrBuffer.ExtractHead<WORD>();
WORD wMessage = ptrBuffer.ExtractHead<WORD>();
int iValue = ptrBuffer.ExtractHead<int>();
const char* strValue = ptrBuffer.ExtractHeadString<char>();
…
}
1. CGNETMSG 로 Casting 한다 .
Message Reading (1)
2. 임시 포인터를 선언해 Buffer 의 포인터를 넣는다 .
3. 값들을 Extract 해낸다 .
10. CGCIICho sanghyun’s Game Classes II
실행처리
Offset 을 알 경우 바로 값을 읽을 수 있다 .
void CSocket::OnMessage(CGMSG& p_rMSG)
{
CGNETMSG& rMSG = (CGNETMSG&) p_rMSG;
WORD wSize = rMSG .Buffer.Head<WORD>(0);
WORD wMessage = rMSG .Buffer.Head<WORD>(2);
int iValue = rMSG .Buffer.Head<int>(4);
const char* strValue = rMSG .Buffer.GetHeadString<char>(8);
…
}
void CSocket::OnMessage(CGMSG& p_rMSG)
{
CGNETMSG& rMSG = (CGNETMSG&) p_rMSG;
WORD wSize = rMSG .Buffer.Head<WORD>(0);
WORD wMessage = rMSG .Buffer.Head<WORD>(2);
int iValue = rMSG .Buffer.Head<int>(4);
const char* strValue = rMSG .Buffer.GetHeadString<char>(8);
…
}
Message Reading (2)
내부 포인터를 옮기지 않고 직접 읽기 .
Offset 을 알면 직접 값을 읽을 수 있다 .
11. CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (1)
그렇다면
진짜 개발이 쉽다란 ?
진짜 이보다 더 쉬울 수 있을 까요 ?
Of Course!
문법적으로 더 간결한 코드로 구현이 가능하다 ?
→ 원초적 도구 논쟁 JAVA, C++, C# 등등 …
12. CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (2)
→ 필요한 기능이 구현된 풍부한 라이브러리가 있다 .
→ 검증된 코드와 충분한 참고자료가 존재한다 .
→ 경력자의 입장에서는 익숙함 !
→ 초보자의 입장에서는 대세 개발 방법이 뭐냐 ?
∵ 기타 디버깅이 쉽다 , 안정적이다 , 싸다 등등은 각자 결론 정해
놓고 좋을 대로 끼워맞추는 용도 !
대부분은 기능의 문제에 관심 !!
한걸음 더 나아가면 심리적 요인 !
사장님의 내면적 요인도 존재 !
→ 개발 인력을 쉽게 찾을 수 있나 !
→ 개발 리스크는 적은가 ?
→ 기능 구현의 문제가 가장 중요한 문제임을 부정할 순 없음 .
13. CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (3)
→ 쉬운 개발이란 문법적 간결성의 문제일 수 있다 .
코드가 대여섯 줄이라면…
→ 기능 구현의 문제일 수 있다 .
아주 단순한 기능만 구현하는 프로그래밍이라면…
하지만 게임 서버는 점점 복잡해져만 가고…
문제는 적은 코드 작성의 문제 혹은 기능 구현의 문제가 아닌
→ 보다 단순한 모델인로 파악할 수 있도록 하는 시도 !
→ 복잡성 해결의 문제 !
14. CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (4)
기존 프로그래밍에 비해 Structured Programming 이 개선한 것은 ?
<Iteration><Selection><Sequence>
→ 생산성 개선은 문법적 간결성이나 재사용성에 대한 것이
아닌 이해 , 수정 , 검증의 개선으로…
→ 소프트웨어를 순차진행 , 선택 , 반복 3 요소의 직렬화
만으로 설계하는 것이 핵심 .
Call
Call
Return
R
eturn
인지의 흐름
15. CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (5)
Object Oriented Programming 이 개선한 것은 ?
소프트웨어를 독립된 함수들의 나열이 아니라 객체들 간의 관계로 이해할 수 있도록 해준다 .
Connect (…)
Accept (…)
SendBuffer (…)
SendString (…)
ReceiveString (…)
Close (…)
Open (…)
기능의 나열 프레임워크
객체간의 관계
확장성 & 유연성
재정의와 합성
• 복잡성 문제 대응 용의
• Design Patterns
• but 특화문제
조금만 제작된 용도와 다른 용도로
사용하려 하면 오히려 족쇄
• 기능적 문제 해결 수준
• 소프트웨어 대형화로 인한 복잡
화문제 대응에 한계
• 객체 조합과 합성 그리고
Generics
• CGCII 는 OOP 와 Generics 를
최대한 활용한 개방적 구조 .
OOP 는 복잡성에 대한 개선에 대한 또 다른 접근…