gcgc- cgcii 서버 엔진에 적용된 기술 (6) - cgcii server sample
Post on 19-Jul-2015
137 Views
Preview:
TRANSCRIPT
Sample ServerCGCIICho sanghyun’s Game Classes II
1. Component of CGCII Server System2. Simple Server3. Simple Client4. Message Sending/Reading5. Easy to development
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(…) → 메시지 전송되어 오면 호출됨
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 에서 할당받도록…
CGCIICho sanghyun’s Game Classes II
실행처리 Server Coding (2)
이걸로 서버 동작 ! 특별한 초기화하지 않아도 기본
Thread, Pool, Socket 등등 내부적으로 초기화 처리됨 !
이보다 더 쉬울 수 있나요 ?
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 로 동작시키고 싶다면 ?
역시 끝
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. 전송한다 .
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;
};
CGCIICho sanghyun’s Game Classes II
실행처리
Stream I/O 형식으로 써넣는 방법도 지원한다
Message Sending (3)
void CSocket::OnConnect(){
CCGBuffer bufSend = MEM_POOL_ALLOC(32);
bufSend<<WORD()<<WORD(MESSAGE_CHATTING)<<int(5)<<“Hello CGCII World!!”<<SET_MESSAGE_LENGTH();
Send(bufSend);}
void CSocket::OnConnect(){
CCGBuffer bufSend = MEM_POOL_ALLOC(32);
bufSend<<WORD()<<WORD(MESSAGE_CHATTING)<<int(5)<<“Hello CGCII World!!”<<SET_MESSAGE_LENGTH();
Send(bufSend);}
void CSocket::OnConnect(){
Send(CCGBuffer(MEM_POOL_ALLOC(32)) <<WORD()<<WORD(MESSAGE_CHATTING)<<int(5)<<“Hello CGCII World!!”<<SET_MESSAGE_LENGTH());}
void CSocket::OnConnect(){
Send(CCGBuffer(MEM_POOL_ALLOC(32)) <<WORD()<<WORD(MESSAGE_CHATTING)<<int(5)<<“Hello CGCII World!!”<<SET_MESSAGE_LENGTH());}
한줄로…
void CSocket::OnConnect(){
CCGBuffer(MEM_POOL_ALLOC(32)) <<WORD()<<WORD(MESSAGE_CHATTING)<<int(5)<<“Hello CGCII World”<<SET_MESSAGE_LENGTH() >> SEND(this);}
void CSocket::OnConnect(){
CCGBuffer(MEM_POOL_ALLOC(32)) <<WORD()<<WORD(MESSAGE_CHATTING)<<int(5)<<“Hello CGCII World”<<SET_MESSAGE_LENGTH() >> SEND(this);}
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 해낸다 .
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 을 알면 직접 값을 읽을 수 있다 .
CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (1)
그렇다면진짜 개발이 쉽다란 ?
진짜 이보다 더 쉬울 수 있을 까요 ?
Of Course!
문법적으로 더 간결한 코드로 구현이 가능하다 ?→ 원초적 도구 논쟁 JAVA, C++, C# 등등 …
CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (2)
→ 필요한 기능이 구현된 풍부한 라이브러리가 있다 .→ 검증된 코드와 충분한 참고자료가 존재한다 .
→ 경력자의 입장에서는 익숙함 !→ 초보자의 입장에서는 대세 개발 방법이 뭐냐 ?
∵ 기타 디버깅이 쉽다 , 안정적이다 , 싸다 등등은 각자 결론 정해놓고 좋을 대로 끼워맞추는 용도 !
대부분은 기능의 문제에 관심 !!
한걸음 더 나아가면 심리적 요인 !
사장님의 내면적 요인도 존재 !→ 개발 인력을 쉽게 찾을 수 있나 !→ 개발 리스크는 적은가 ?
→ 기능 구현의 문제가 가장 중요한 문제임을 부정할 순 없음 .
CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (3)
→ 쉬운 개발이란 문법적 간결성의 문제일 수 있다 .
코드가 대여섯 줄이라면…
→ 기능 구현의 문제일 수 있다 .
아주 단순한 기능만 구현하는 프로그래밍이라면…
하지만 게임 서버는 점점 복잡해져만 가고… 문제는 적은 코드 작성의 문제 혹은 기능 구현의 문제가 아닌
→ 보다 단순한 모델인로 파악할 수 있도록 하는 시도 !
→ 복잡성 해결의 문제 !
CGCIICho sanghyun’s Game Classes II
실행처리 개발하기 쉽다란 ? (4)
기존 프로그래밍에 비해 Structured Programming 이 개선한 것은 ?
<Iteration><Selection><Sequence>
→ 생산성 개선은 문법적 간결성이나 재사용성에 대한 것이 아닌 이해 , 수정 , 검증의 개선으로…
→ 소프트웨어를 순차진행 , 선택 , 반복 3 요소의 직렬화 만으로 설계하는 것이 핵심 .
CallCall
Return
Return
인지의 흐름
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 는 복잡성에 대한 개선에 대한 또 다른 접근…
CGCIICho sanghyun’s Game Classes II
질문 ?예외처리
질문 ?sangduck@cgcii.co.kr
top related