SlideShare a Scribd company logo
1 of 26
EasyGameServer
Source 협찬 by sm9
무엇을 알아볼까?
• 소스 출처 : https://github.com/zeliard/EasyGameServer
• 채팅을 뿌려주는 서버가 어떻게 작동하는지 원리를 알아본다
• 중요한 함수들 위주로 알아보자
1. EasyServer.cpp (_tmain 1/4 )
전역변수 선언
g_AcceptedSocket
Exception이 발생하면
ExceptionFilter 작동
ClientManager
DatabaseMager 초기화
WSDATA 초기화
ListenSocket 생성
1. EasyServer.cpp (_tmain 2/4 )
옵션 결정
ListenSocket을
Bind
ListenSocket을
Listen
EventHandle 생성
1. EasyServer.cpp (_tmain 3/4 )
스레드를 생성
ClientHandlingThread
함수를 실행한다.
SUSPENDED 상태다
DB Thread 생성
SUSPENDED 상태
전역 변수로 선언한
소켓에 accept 시도
Blocking 이므로 대기
Queue에 connectio이
있어야 넘어간다.
Accept 되면 Thread
Security 인자에 signal
을 줘서 실행시킨다
1. EasyServer.cpp (_tmain 4/4 )
서버가 종료되기 전에 할당된 자원을 해제한다
윈속은 WSACleanup()을 쓴다.
1. EasyServer.cpp
(ClientHandlingThread 1/2 )
WaitableTimer를 생성한다.
이 Thread는 10 밀리초마다 TimeProc을
수행하는 타이머를 설정하게 된다.
두 번째 인자는 최초 대기 시간이다.
100 nanosecond 단위이다.
세 번째 인자는 Timer 주기를 나타낸다.
millisecond 단위이다.
1. EasyServer.cpp
(ClientHandlingThread 2/2 )
WaitForSingleObjectEx 함수의 마지막 인자가 true
이므로 APC 큐에 뭔가 추가되면(연결이 되면) 호출
그렇지 않으면 대기 시간이 무한대이다
WaifForSingleObjectEx의 반환값이 WAIT_OBJECT_0
라면 signaled 상태라는 뜻이다.
이때 ClientManager는 새로운 ClientSession을 만든다.
g_AcceptedSocket은 지금 연결된 client 소켓 정보를
담고 있으므로 session 별로 고유한 소켓을 줄 수 있다.
ClientSession이 생성되었다면 연결 처리(OnConnect())
1. EasyServer.cpp (TimeProc)
이 함수는 ClientManager에게 주기적으로 할 일을
시킨다.
TimeProc을 호출하는 타이머가 10 밀리초 주기를
가지기 때문에 OnPeriodWork() 역시 10 밀리초
주기로 호출된다.
1. EasyServer.cpp
(DatabaseHandlingThread)
DatabaseManager에게 DB 작업을 수행시킨다.
DB 부분은 자세히 분석하지 않을 예정이다.
EasyGameServer에서는 DB 입출력이 그렇게 많지 않다.
개발하면서 필요하면 추가로 DB 부분을 알아보도록 하자.
2. ClientManager (CreateClient)
Singleton
새로운 연결이 있으면 CreateClient
함수를 부르고 소켓 정보를 할당
ClientSession이 생성되고 나면
List 형태로 담고 있는 mClientList에
저장한다.
이후부터
Main함수는 ClientManager를 통해
ClientSession에 일을 시킨다.
2. ClientManager (BroadcastPacket)
ClientSession 전체를 돌면서
패킷을 발송한다.
채팅 서버에서는 이 함수에서
각각의 클라이언트에게 대화를
중계한다.
2. ClientManager (BroadcastPacket)
GetTickCount()로 시스템 시간을 받아서
이전에 확인한 값과 1초 이상 차이나면
1초마다 할 일들을 수행한다.
CollectGarbageSession()에서
연결이 끊어진 세션을 정리하고,
ClientPeriodWork()에서
각각의 Client 마다 일을 시킨다.
2. ClientManager
(CollectGarbageSessions)
ClientSession을 전부 돌면서
응답이 없고 비동기 I/O중이 아닌
세션들을 vector에 모아놓는다.
이렇게 모아놓은 ClientSession은
고유한 socket정보로 구분되므로
연결을 끊고 List에서 삭제한다.
2. ClientManager (ClientPeriodWork)
심플하게 ClientSession 리스트를 돌면서
전부 OnTick()을 실행시키는 함수
주기적으로 할 일을 OnTick()에 넣어두면
ClientPeriodWork()때 전부 실행된다
2. ClientManager (FlushClientSend)
ClientSession List를 순회하면서 SendFlush()
함수를 실행시키는데, 버퍼에 쌓인 데이터를
전송하는 함수다.
여기서 실패하면 연결이 끊어진 것이다.
3. ClientSession (OnConnect)
소켓을 넌블러킹으로 바꾸지 않으면 서버 전체가 블로킹 될 수 있다.
Nagle 알고리즘을 끄면 서버 부하는 늘어나지만 실시간성은 높아진다. 채팅 서버이므로 끈다.
바로 PostRecv() 함수로 이어진다.
3. ClientSession (PostRecv)
mRecvBuffer는 Circular Buffer.
소스를 열어보면 버퍼를 두 개
부분으로 나눠 적절히 교체한다
잘못 짜면 바로 터진다(…)
WSARecv 함수는 연결된 소켓
에서 데이터를 받아온다.
비동기 입출력이 가능하다.
WSABUF에 값이 저장되며, 여러
개의 버퍼를 지정할 수도 있다.
RecvCompletion Callback함수가
등록되어 있다.
3. ClientSession (RecvCompletion)
데이터 읽기가 끝나면
OnRead() 함수로 정리하고
다시 PostRecv()로 돌아간다
3. ClientSession (OnRead 1/2)
RecvBuffer에는 Client에서
받은 데이터가 들어있다.
이 데이터는 패킷이므로 약속된
패킷 헤더 정보를 통해 전송이
제대로 됐는지 확인할 수 있다.
제대로 패킷을 받았다면 계속
진행한다.
3. ClientSession (OnRead 2/2)
패킷 type에 따라 다른 처리를 해 준다
로그인 패킷이면 DB에 값을 쓴다.
채팅 패킷이면 BroadCast 준비를 한다.
패킷을 보낸 플레이어의 id, 이름, 채팅
내용을 패킷에 담고 방송한다.
지금은 두 종류 패킷 밖에 없으므로 이
외에는 에러로 간주한다.
3. ClientSession (SendRequest)
Broadcast를 실행하면 ClientSession들은
SendRequest 함수를 실행한다.
SendRequest 자체는 서버의 버퍼에만
패킷 정보를 쓰는 과정이다.
ClientManager에는 이렇게 ClientSession
버퍼에 저장된 패킷을 전송하라는 Flush
ClientSend 함수가 있다. 이 함수는
Manager에서 주기적으로 불려오므로
쌓인 패킷들도 주기적으로 전송된다.
3. ClientSession (SendFlush)
PostRecv와 거의 같은 구조다.
다만 WSASend 함수를 쓰므로
소켓으로 데이터를 보낸다는 점
입출력이 끝나고 CallBack 함수로
SendCompletion을 호출하는 점이
다르다
3. ClientSession (SendFlush)
비동기 I/O 카운터를 하나 줄이고 OnWriteComplete 함수를 부르는 것이 이 함수의 본업이다
3. ClientSession (OnWriteComplete)
전송 완료한 데이터를 버퍼에서 덜어내는 일을 한다.
끝!
• 나머지 함수들은?
• 채팅 이외의 기능을 구현하려면 본격적으로 중요해진다
• 특히 DB 연동하는 부분은 캐릭터 좌표 등을 저장하고 있어서 일부러 언
급을 피했지만 채팅에 게임까지 들어가면 이 부분도 봐야 함
• 그 외
• Windows 시스템 프로그래밍 좀 더 봐야겠다
• MSDN도

More Related Content

What's hot

Spring환경설정하기
Spring환경설정하기Spring환경설정하기
Spring환경설정하기
ChangJoo Park
 
07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도
ssuser3fb17c
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
우영 주
 
7급 공무원도 쉽게 따라하는 쉘 스크립트
7급 공무원도 쉽게 따라하는 쉘 스크립트7급 공무원도 쉽게 따라하는 쉘 스크립트
7급 공무원도 쉽게 따라하는 쉘 스크립트
Young-Ho Cha
 
Servlet jsp 13장
Servlet jsp 13장Servlet jsp 13장
Servlet jsp 13장
JeongBong Kim
 
[E6]2012. netty internals
[E6]2012. netty internals[E6]2012. netty internals
[E6]2012. netty internals
NAVER D2
 

What's hot (20)

Get started with netty
Get started with nettyGet started with netty
Get started with netty
 
Reactive Programming with Rxjs
Reactive Programming with RxjsReactive Programming with Rxjs
Reactive Programming with Rxjs
 
Spring환경설정하기
Spring환경설정하기Spring환경설정하기
Spring환경설정하기
 
고급시스템프로그래밍
고급시스템프로그래밍고급시스템프로그래밍
고급시스템프로그래밍
 
07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도
 
Promise 패턴 공부
Promise 패턴 공부Promise 패턴 공부
Promise 패턴 공부
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Tcp ip & io model
Tcp ip & io modelTcp ip & io model
Tcp ip & io model
 
취약점 점검도구 실습 보고서
취약점 점검도구 실습 보고서 취약점 점검도구 실습 보고서
취약점 점검도구 실습 보고서
 
shell and process
shell and processshell and process
shell and process
 
7급 공무원도 쉽게 따라하는 쉘 스크립트
7급 공무원도 쉽게 따라하는 쉘 스크립트7급 공무원도 쉽게 따라하는 쉘 스크립트
7급 공무원도 쉽게 따라하는 쉘 스크립트
 
Servlet jsp 13장
Servlet jsp 13장Servlet jsp 13장
Servlet jsp 13장
 
분산 트랜잭션 - 큰힘에는 큰 책임이 따른다 [MongoDB]
분산 트랜잭션 - 큰힘에는 큰 책임이 따른다 [MongoDB]분산 트랜잭션 - 큰힘에는 큰 책임이 따른다 [MongoDB]
분산 트랜잭션 - 큰힘에는 큰 책임이 따른다 [MongoDB]
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
Thread
ThreadThread
Thread
 
Ubuntu 8.04 Desktop에서 Elgg설치하기
Ubuntu 8.04 Desktop에서 Elgg설치하기Ubuntu 8.04 Desktop에서 Elgg설치하기
Ubuntu 8.04 Desktop에서 Elgg설치하기
 
[E6]2012. netty internals
[E6]2012. netty internals[E6]2012. netty internals
[E6]2012. netty internals
 
04 프로세스
04 프로세스04 프로세스
04 프로세스
 
톰캣 #08-웹서버 연동
톰캣 #08-웹서버 연동톰캣 #08-웹서버 연동
톰캣 #08-웹서버 연동
 
Ch7,8. Configmaps, Secrets and API
Ch7,8. Configmaps, Secrets and APICh7,8. Configmaps, Secrets and API
Ch7,8. Configmaps, Secrets and API
 

Similar to Easy gameserver

[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발
NAVER D2
 
중급 소켓프로그래밍
중급 소켓프로그래밍중급 소켓프로그래밍
중급 소켓프로그래밍
quxn6
 
Introduction to Fork Join Framework_SYS4U I&C
Introduction to Fork Join Framework_SYS4U I&CIntroduction to Fork Join Framework_SYS4U I&C
Introduction to Fork Join Framework_SYS4U I&C
sys4u
 

Similar to Easy gameserver (20)

Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQL
 
Gcd ppt
Gcd pptGcd ppt
Gcd ppt
 
Servlet3
Servlet3Servlet3
Servlet3
 
Zoo keeper 소개
Zoo keeper 소개Zoo keeper 소개
Zoo keeper 소개
 
[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성[2D4]Python에서의 동시성_병렬성
[2D4]Python에서의 동시성_병렬성
 
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
 
[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화
 
Implementing remote procedure calls rev2
Implementing remote procedure calls rev2Implementing remote procedure calls rev2
Implementing remote procedure calls rev2
 
.NET에서 비동기 프로그래밍 배우기
.NET에서 비동기 프로그래밍 배우기.NET에서 비동기 프로그래밍 배우기
.NET에서 비동기 프로그래밍 배우기
 
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
[오픈소스컨설팅]Fault Tolerance Architecture by Netflix
 
Nodejs_chapter3
Nodejs_chapter3Nodejs_chapter3
Nodejs_chapter3
 
L4교육자료
L4교육자료L4교육자료
L4교육자료
 
Blockchain 4th dapp programming
Blockchain 4th dapp programmingBlockchain 4th dapp programming
Blockchain 4th dapp programming
 
[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발
 
Mcollective orchestration tool 소개
Mcollective orchestration tool 소개Mcollective orchestration tool 소개
Mcollective orchestration tool 소개
 
중급 소켓프로그래밍
중급 소켓프로그래밍중급 소켓프로그래밍
중급 소켓프로그래밍
 
Free rtos seminar
Free rtos seminarFree rtos seminar
Free rtos seminar
 
[143] Modern C++ 무조건 써야 해?
[143] Modern C++ 무조건 써야 해?[143] Modern C++ 무조건 써야 해?
[143] Modern C++ 무조건 써야 해?
 
Introduction to Fork Join Framework_SYS4U I&C
Introduction to Fork Join Framework_SYS4U I&CIntroduction to Fork Join Framework_SYS4U I&C
Introduction to Fork Join Framework_SYS4U I&C
 
Python으로 채팅 구현하기
Python으로 채팅 구현하기Python으로 채팅 구현하기
Python으로 채팅 구현하기
 

More from 진상 문 (10)

Project Anarchy(Vision Engine)으로 게임 툴 만들기! part2
Project Anarchy(Vision Engine)으로 게임 툴 만들기! part2Project Anarchy(Vision Engine)으로 게임 툴 만들기! part2
Project Anarchy(Vision Engine)으로 게임 툴 만들기! part2
 
[C++ beginner] sizeof()
[C++ beginner] sizeof()[C++ beginner] sizeof()
[C++ beginner] sizeof()
 
Project Anarchy(Vision Engine)으로 게임 툴 만들기! part1
Project Anarchy(Vision Engine)으로 게임 툴 만들기! part1Project Anarchy(Vision Engine)으로 게임 툴 만들기! part1
Project Anarchy(Vision Engine)으로 게임 툴 만들기! part1
 
Pervasive computing
Pervasive computingPervasive computing
Pervasive computing
 
ABI란 무엇인가요?
ABI란 무엇인가요?ABI란 무엇인가요?
ABI란 무엇인가요?
 
Dll 파일 호출의 2가지 방법
Dll 파일 호출의 2가지 방법Dll 파일 호출의 2가지 방법
Dll 파일 호출의 2가지 방법
 
C# 뉴비를 위한 맛보기 2
C# 뉴비를 위한 맛보기 2C# 뉴비를 위한 맛보기 2
C# 뉴비를 위한 맛보기 2
 
C# 뉴비를 위한 맛보기
C# 뉴비를 위한 맛보기C# 뉴비를 위한 맛보기
C# 뉴비를 위한 맛보기
 
무중력 상태에 필요한 기초 물리
무중력 상태에 필요한 기초 물리무중력 상태에 필요한 기초 물리
무중력 상태에 필요한 기초 물리
 
Halo ce anniversary Postmortem
Halo ce anniversary PostmortemHalo ce anniversary Postmortem
Halo ce anniversary Postmortem
 

Easy gameserver

  • 2. 무엇을 알아볼까? • 소스 출처 : https://github.com/zeliard/EasyGameServer • 채팅을 뿌려주는 서버가 어떻게 작동하는지 원리를 알아본다 • 중요한 함수들 위주로 알아보자
  • 3. 1. EasyServer.cpp (_tmain 1/4 ) 전역변수 선언 g_AcceptedSocket Exception이 발생하면 ExceptionFilter 작동 ClientManager DatabaseMager 초기화 WSDATA 초기화 ListenSocket 생성
  • 4. 1. EasyServer.cpp (_tmain 2/4 ) 옵션 결정 ListenSocket을 Bind ListenSocket을 Listen EventHandle 생성
  • 5. 1. EasyServer.cpp (_tmain 3/4 ) 스레드를 생성 ClientHandlingThread 함수를 실행한다. SUSPENDED 상태다 DB Thread 생성 SUSPENDED 상태 전역 변수로 선언한 소켓에 accept 시도 Blocking 이므로 대기 Queue에 connectio이 있어야 넘어간다. Accept 되면 Thread Security 인자에 signal 을 줘서 실행시킨다
  • 6. 1. EasyServer.cpp (_tmain 4/4 ) 서버가 종료되기 전에 할당된 자원을 해제한다 윈속은 WSACleanup()을 쓴다.
  • 7. 1. EasyServer.cpp (ClientHandlingThread 1/2 ) WaitableTimer를 생성한다. 이 Thread는 10 밀리초마다 TimeProc을 수행하는 타이머를 설정하게 된다. 두 번째 인자는 최초 대기 시간이다. 100 nanosecond 단위이다. 세 번째 인자는 Timer 주기를 나타낸다. millisecond 단위이다.
  • 8. 1. EasyServer.cpp (ClientHandlingThread 2/2 ) WaitForSingleObjectEx 함수의 마지막 인자가 true 이므로 APC 큐에 뭔가 추가되면(연결이 되면) 호출 그렇지 않으면 대기 시간이 무한대이다 WaifForSingleObjectEx의 반환값이 WAIT_OBJECT_0 라면 signaled 상태라는 뜻이다. 이때 ClientManager는 새로운 ClientSession을 만든다. g_AcceptedSocket은 지금 연결된 client 소켓 정보를 담고 있으므로 session 별로 고유한 소켓을 줄 수 있다. ClientSession이 생성되었다면 연결 처리(OnConnect())
  • 9. 1. EasyServer.cpp (TimeProc) 이 함수는 ClientManager에게 주기적으로 할 일을 시킨다. TimeProc을 호출하는 타이머가 10 밀리초 주기를 가지기 때문에 OnPeriodWork() 역시 10 밀리초 주기로 호출된다.
  • 10. 1. EasyServer.cpp (DatabaseHandlingThread) DatabaseManager에게 DB 작업을 수행시킨다. DB 부분은 자세히 분석하지 않을 예정이다. EasyGameServer에서는 DB 입출력이 그렇게 많지 않다. 개발하면서 필요하면 추가로 DB 부분을 알아보도록 하자.
  • 11. 2. ClientManager (CreateClient) Singleton 새로운 연결이 있으면 CreateClient 함수를 부르고 소켓 정보를 할당 ClientSession이 생성되고 나면 List 형태로 담고 있는 mClientList에 저장한다. 이후부터 Main함수는 ClientManager를 통해 ClientSession에 일을 시킨다.
  • 12. 2. ClientManager (BroadcastPacket) ClientSession 전체를 돌면서 패킷을 발송한다. 채팅 서버에서는 이 함수에서 각각의 클라이언트에게 대화를 중계한다.
  • 13. 2. ClientManager (BroadcastPacket) GetTickCount()로 시스템 시간을 받아서 이전에 확인한 값과 1초 이상 차이나면 1초마다 할 일들을 수행한다. CollectGarbageSession()에서 연결이 끊어진 세션을 정리하고, ClientPeriodWork()에서 각각의 Client 마다 일을 시킨다.
  • 14. 2. ClientManager (CollectGarbageSessions) ClientSession을 전부 돌면서 응답이 없고 비동기 I/O중이 아닌 세션들을 vector에 모아놓는다. 이렇게 모아놓은 ClientSession은 고유한 socket정보로 구분되므로 연결을 끊고 List에서 삭제한다.
  • 15. 2. ClientManager (ClientPeriodWork) 심플하게 ClientSession 리스트를 돌면서 전부 OnTick()을 실행시키는 함수 주기적으로 할 일을 OnTick()에 넣어두면 ClientPeriodWork()때 전부 실행된다
  • 16. 2. ClientManager (FlushClientSend) ClientSession List를 순회하면서 SendFlush() 함수를 실행시키는데, 버퍼에 쌓인 데이터를 전송하는 함수다. 여기서 실패하면 연결이 끊어진 것이다.
  • 17. 3. ClientSession (OnConnect) 소켓을 넌블러킹으로 바꾸지 않으면 서버 전체가 블로킹 될 수 있다. Nagle 알고리즘을 끄면 서버 부하는 늘어나지만 실시간성은 높아진다. 채팅 서버이므로 끈다. 바로 PostRecv() 함수로 이어진다.
  • 18. 3. ClientSession (PostRecv) mRecvBuffer는 Circular Buffer. 소스를 열어보면 버퍼를 두 개 부분으로 나눠 적절히 교체한다 잘못 짜면 바로 터진다(…) WSARecv 함수는 연결된 소켓 에서 데이터를 받아온다. 비동기 입출력이 가능하다. WSABUF에 값이 저장되며, 여러 개의 버퍼를 지정할 수도 있다. RecvCompletion Callback함수가 등록되어 있다.
  • 19. 3. ClientSession (RecvCompletion) 데이터 읽기가 끝나면 OnRead() 함수로 정리하고 다시 PostRecv()로 돌아간다
  • 20. 3. ClientSession (OnRead 1/2) RecvBuffer에는 Client에서 받은 데이터가 들어있다. 이 데이터는 패킷이므로 약속된 패킷 헤더 정보를 통해 전송이 제대로 됐는지 확인할 수 있다. 제대로 패킷을 받았다면 계속 진행한다.
  • 21. 3. ClientSession (OnRead 2/2) 패킷 type에 따라 다른 처리를 해 준다 로그인 패킷이면 DB에 값을 쓴다. 채팅 패킷이면 BroadCast 준비를 한다. 패킷을 보낸 플레이어의 id, 이름, 채팅 내용을 패킷에 담고 방송한다. 지금은 두 종류 패킷 밖에 없으므로 이 외에는 에러로 간주한다.
  • 22. 3. ClientSession (SendRequest) Broadcast를 실행하면 ClientSession들은 SendRequest 함수를 실행한다. SendRequest 자체는 서버의 버퍼에만 패킷 정보를 쓰는 과정이다. ClientManager에는 이렇게 ClientSession 버퍼에 저장된 패킷을 전송하라는 Flush ClientSend 함수가 있다. 이 함수는 Manager에서 주기적으로 불려오므로 쌓인 패킷들도 주기적으로 전송된다.
  • 23. 3. ClientSession (SendFlush) PostRecv와 거의 같은 구조다. 다만 WSASend 함수를 쓰므로 소켓으로 데이터를 보낸다는 점 입출력이 끝나고 CallBack 함수로 SendCompletion을 호출하는 점이 다르다
  • 24. 3. ClientSession (SendFlush) 비동기 I/O 카운터를 하나 줄이고 OnWriteComplete 함수를 부르는 것이 이 함수의 본업이다
  • 25. 3. ClientSession (OnWriteComplete) 전송 완료한 데이터를 버퍼에서 덜어내는 일을 한다.
  • 26. 끝! • 나머지 함수들은? • 채팅 이외의 기능을 구현하려면 본격적으로 중요해진다 • 특히 DB 연동하는 부분은 캐릭터 좌표 등을 저장하고 있어서 일부러 언 급을 피했지만 채팅에 게임까지 들어가면 이 부분도 봐야 함 • 그 외 • Windows 시스템 프로그래밍 좀 더 봐야겠다 • MSDN도