Skip to content

Commit 4ab808a

Browse files
committed
접속/종료시 플레이어 클래스 처리, SendMsg 처리 하는 방식 추가
1 parent b87f934 commit 4ab808a

File tree

6 files changed

+100
-53
lines changed

6 files changed

+100
-53
lines changed

TCPServer/TCPServer/Iocp.cpp

Lines changed: 85 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,17 @@ bool IOCP_Server::StartServer()
8080
return true;
8181
}
8282

83-
void IOCP_Server::initClient(std::list<class PLAYER *>& player)
83+
void IOCP_Server::initClient()
8484
{
85-
// 플레이어 데이터를 미리 추가해 놓는다.
86-
for (int i = 0; i < MAX_PLAYER; ++i) {
87-
PLAYER * tmp_player = new PLAYER;
88-
tmp_player->set_init_player();
89-
player.push_back(tmp_player);
90-
}
85+
// 미리 player, player_session 공간을 할당 한다.
86+
player_session.reserve(MAX_PLAYER);
87+
player.reserve(MAX_PLAYER);
9188

9289
// 세션 데이터도 미리 추가해 놓는다.
9390
for (int i = 0; i < MAX_PLAYER; ++i) {
94-
PLAYER_Session * tmp_session = new PLAYER_Session;
95-
tmp_session->set_init_session();
96-
player_session.push_back(tmp_session);
91+
PLAYER_Session * pPlayerSession = new PLAYER_Session;
92+
pPlayerSession->set_init_session();
93+
player_session.push_back(pPlayerSession);
9794
}
9895
}
9996

@@ -137,7 +134,7 @@ bool IOCP_Server::CreateWokerThread()
137134
void IOCP_Server::WokerThread()
138135
{
139136
//CompletionKey를 받을 포인터 변수
140-
PLAYER_Session* pClientInfo = NULL;
137+
PLAYER_Session* pPlayerSession = NULL;
141138
//함수 호출 성공 여부
142139
BOOL bSuccess = TRUE;
143140
//Overlapped I/O작업에서 전송된 데이터 크기
@@ -157,7 +154,7 @@ void IOCP_Server::WokerThread()
157154
//////////////////////////////////////////////////////
158155
bSuccess = GetQueuedCompletionStatus(g_hiocp,
159156
&dwIoSize, // 실제로 전송된 바이트
160-
(PULONG_PTR)&pClientInfo, // CompletionKey
157+
(PULONG_PTR)&pPlayerSession, // CompletionKey
161158
&lpOverlapped, // Overlapped IO 객체
162159
INFINITE); // 대기할 시간
163160

@@ -176,8 +173,9 @@ void IOCP_Server::WokerThread()
176173
//client가 접속을 끊었을때..
177174
if (FALSE == bSuccess || (0 == dwIoSize && TRUE == bSuccess))
178175
{
179-
std::cout << "[" << (int)pClientInfo->get_unique_id() << "]" << "Socket 접속 끊김..." << std::endl;
180-
CloseSocket(pClientInfo);
176+
std::cout << "[" << (int)pPlayerSession->get_unique_id() << "] Socket 접속 끊김..." << std::endl;
177+
ClosePlayer(pPlayerSession->get_unique_id());
178+
CloseSocket(pPlayerSession);
181179
continue;
182180
}
183181

@@ -197,9 +195,12 @@ void IOCP_Server::WokerThread()
197195
t->event = T_NormalTime;
198196
timer.setTimerEvent(*t);
199197
//----------------------------------------------------
200-
//클라이언트에 메세지를 에코한다.
201-
/*SendMsg(pClientInfo, pOverlappedEx->m_szBuf, dwIoSize);
202-
BindRecv(pClientInfo);*/
198+
//클라이언트에 메세지를 에코한다. 'kch'일 경우에만 리턴을 하도록 하였다.
199+
if (!strcmp(pOverlappedEx->m_szBuf, "kch")) {
200+
SendMsg(pPlayerSession, pOverlappedEx->m_szBuf, dwIoSize);
201+
BindRecv(pPlayerSession);
202+
}
203+
203204
}
204205
break;
205206
case IOOperation::SEND:
@@ -219,7 +220,7 @@ void IOCP_Server::WokerThread()
219220
}
220221
}
221222

222-
void IOCP_Server::CloseSocket(PLAYER_Session * pClientInfo, bool bIsForce)
223+
void IOCP_Server::CloseSocket(PLAYER_Session * pPlayerSession, bool bIsForce)
223224
{
224225
struct linger stLinger = { 0, 0 }; // SO_DONTLINGER로 설정
225226

@@ -230,14 +231,49 @@ void IOCP_Server::CloseSocket(PLAYER_Session * pClientInfo, bool bIsForce)
230231
}
231232

232233
//socketClose소켓의 데이터 송수신을 모두 중단 시킨다.
233-
shutdown(pClientInfo->m_socketSession, SD_BOTH);
234+
shutdown(pPlayerSession->m_socketSession, SD_BOTH);
234235

235236
//소켓 옵션을 설정한다.
236-
setsockopt(pClientInfo->m_socketSession, SOL_SOCKET, SO_LINGER, (char*)&stLinger, sizeof(stLinger));
237+
setsockopt(pPlayerSession->m_socketSession, SOL_SOCKET, SO_LINGER, (char*)&stLinger, sizeof(stLinger));
237238

238239
//소켓 연결을 종료 시킨다.
239-
closesocket(pClientInfo->m_socketSession);
240-
pClientInfo->m_socketSession = INVALID_SOCKET;
240+
closesocket(pPlayerSession->m_socketSession);
241+
pPlayerSession->m_socketSession = INVALID_SOCKET;
242+
}
243+
244+
void IOCP_Server::ClosePlayer(unsigned __int64 uniqueId)
245+
{
246+
player.erase(uniqueId);
247+
}
248+
249+
bool IOCP_Server::SendMsg(PLAYER_Session * pPlayerSession, char * pMsg, int nLen)
250+
{
251+
DWORD dwRecvNumBytes = 0;
252+
253+
// 전송될 메세지를 복사
254+
CopyMemory(pPlayerSession->get_Send_over().m_szBuf, pMsg, nLen);
255+
256+
257+
// Overlapped I/O을 위해 각 정보를 셋팅해 준다.
258+
pPlayerSession->get_Send_over().m_wsaBuf.len = nLen;
259+
pPlayerSession->get_Send_over().m_wsaBuf.buf = pPlayerSession->get_Send_over().m_szBuf;
260+
pPlayerSession->get_Send_over().m_eOperation = IOOperation::SEND;
261+
262+
int nRet = WSASend(pPlayerSession->m_socketSession,
263+
&(pPlayerSession->get_Send_over().m_wsaBuf),
264+
1,
265+
&dwRecvNumBytes,
266+
0,
267+
(LPWSAOVERLAPPED) & (pPlayerSession->get_Send_over()),
268+
NULL);
269+
270+
// socket_error이면 client socket이 끊어진걸로 처리한다.
271+
if (nRet == SOCKET_ERROR && (WSAGetLastError() != ERROR_IO_PENDING))
272+
{
273+
std::cout << "[Error] WSASend()함수 실패..! " << WSAGetLastError() << std::endl;
274+
return false;
275+
}
276+
return true;
241277
}
242278

243279
bool IOCP_Server::CreateAccepterThread()
@@ -257,36 +293,45 @@ void IOCP_Server::AccepterThread()
257293
while (mIsAccepterRun)
258294
{
259295
// 접속을 받을 구조체의 인덱스를 얻어온다.
260-
PLAYER_Session* pClientInfo = GetEmptySession();
261-
if (NULL == pClientInfo) {
296+
PLAYER_Session* pPlayerSession = GetEmptySession();
297+
if (NULL == pPlayerSession) {
262298
std::cout << "[Error] Client Full..!" << std::endl;
263299
return;
264300
}
265301

266302
// 클라이언트 접속 요청이 들어올 때까지 기다린다.
267-
pClientInfo->m_socketSession = WSAAccept(listenSocket, reinterpret_cast<sockaddr *>(&client_addr), &client_len, NULL, NULL);
268-
if (INVALID_SOCKET == pClientInfo->m_socketSession) {
303+
pPlayerSession->m_socketSession = WSAAccept(listenSocket, reinterpret_cast<sockaddr *>(&client_addr), &client_len, NULL, NULL);
304+
if (INVALID_SOCKET == pPlayerSession->m_socketSession) {
269305
continue;
270306
}
271307

272308
// I/O Completion Port객체와 소켓을 연결시킨다.
273-
bool bRet = BindIOCompletionPort(pClientInfo);
309+
bool bRet = BindIOCompletionPort(pPlayerSession);
274310
if (false == bRet) {
275311
return;
276312
}
277313

278-
//Recv Overlapped I/O작업을 요청해 놓는다.
279-
bRet = BindRecv(pClientInfo);
314+
// Recv Overlapped I/O작업을 요청해 놓는다.
315+
bRet = BindRecv(pPlayerSession);
280316
if (false == bRet) {
281317
return;
282318
}
283319

320+
// session에 set 해준다.
321+
pPlayerSession->set_unique_id(uniqueId);
322+
323+
// 플레이어를 set 해준다.
324+
class PLAYER * acceptPlayer = new class PLAYER;
325+
acceptPlayer->set_sock(pPlayerSession->m_socketSession);
326+
acceptPlayer->set_unique_id(uniqueId);
327+
player.insert(std::unordered_map<unsigned __int64, class PLAYER *>::value_type(uniqueId, acceptPlayer));
328+
284329
//클라이언트 갯수 증가
285330
++uniqueId;
286331

287332
char clientIP[32] = { 0, };
288333
inet_ntop(AF_INET, &(client_addr.sin_addr), clientIP, 32 - 1);
289-
std::cout << "[접속(" << uniqueId << ")] Client IP : " << clientIP << " / SOCKET : " << (int)pClientInfo->m_socketSession << std::endl;
334+
std::cout << "[접속(" << uniqueId << ")] Client IP : " << clientIP << " / SOCKET : " << (int)pPlayerSession->m_socketSession << std::endl;
290335

291336

292337
}
@@ -303,10 +348,10 @@ PLAYER_Session* IOCP_Server::GetEmptySession()
303348
return nullptr;
304349
}
305350

306-
bool IOCP_Server::BindIOCompletionPort(PLAYER_Session * pClientInfo)
351+
bool IOCP_Server::BindIOCompletionPort(PLAYER_Session * pPlayerSession)
307352
{
308-
// socket과 pClientInfo를 CompletionPort객체와 연결시킨다.
309-
auto hIOCP = CreateIoCompletionPort((HANDLE)pClientInfo->m_socketSession, g_hiocp, (ULONG_PTR)(pClientInfo), 0);
353+
// socket과 pPlayerSession를 CompletionPort객체와 연결시킨다.
354+
auto hIOCP = CreateIoCompletionPort((HANDLE)pPlayerSession->m_socketSession, g_hiocp, (ULONG_PTR)(pPlayerSession), 0);
310355

311356
if (NULL == hIOCP || g_hiocp != hIOCP) {
312357
std::cout << "[Error] CreateIoCompletionPort()함수 실패 : " << GetLastError() << std::endl;
@@ -316,22 +361,22 @@ bool IOCP_Server::BindIOCompletionPort(PLAYER_Session * pClientInfo)
316361
return true;
317362
}
318363

319-
bool IOCP_Server::BindRecv(PLAYER_Session * pClientInfo)
364+
bool IOCP_Server::BindRecv(PLAYER_Session * pPlayerSession)
320365
{
321366
DWORD dwFlag = 0;
322367
DWORD dwRecvNumBytes = 0;
323368

324369
//Overlapped I/O을 위해 각 정보를 셋팅해 준다.
325-
pClientInfo->get_Recv_over().m_wsaBuf.len = MAX_SOCKBUF;
326-
pClientInfo->get_Recv_over().m_wsaBuf.buf = pClientInfo->get_Recv_over().m_szBuf;
327-
pClientInfo->get_Recv_over().m_eOperation = IOOperation::RECV;
370+
pPlayerSession->get_Recv_over().m_wsaBuf.len = MAX_SOCKBUF;
371+
pPlayerSession->get_Recv_over().m_wsaBuf.buf = pPlayerSession->get_Recv_over().m_szBuf;
372+
pPlayerSession->get_Recv_over().m_eOperation = IOOperation::RECV;
328373

329-
int nRet = WSARecv(pClientInfo->m_socketSession,
330-
&(pClientInfo->get_Recv_over().m_wsaBuf),
374+
int nRet = WSARecv(pPlayerSession->m_socketSession,
375+
&(pPlayerSession->get_Recv_over().m_wsaBuf),
331376
1,
332377
&dwRecvNumBytes,
333378
&dwFlag,
334-
(LPWSAOVERLAPPED) & (pClientInfo->get_Recv_over()),
379+
(LPWSAOVERLAPPED) & (pPlayerSession->get_Recv_over()),
335380
NULL);
336381

337382
//socket_error이면 client socket이 끊어진걸로 처리한다.

TCPServer/TCPServer/Iocp.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class IOCP_Server {
1313
bool initServer();
1414
bool BindandListen(const u_short port);
1515
bool StartServer();
16-
void initClient(std::list<class PLAYER *>& player);
16+
void initClient();
1717
void destroyThread();
1818

1919
private:
@@ -32,9 +32,11 @@ class IOCP_Server {
3232
bool CreateAccepterThread(); // AcceptThread init
3333
void AccepterThread(); // AcceptThread
3434
PLAYER_Session* GetEmptySession(); // Empty Session Search
35-
bool BindIOCompletionPort(PLAYER_Session* pClientInfo); // Bind
36-
bool BindRecv(PLAYER_Session* pClientInfo); // WSARecv Overlapped I/O 작업을 시킨다.
37-
void CloseSocket(class PLAYER_Session* pClientInfo, bool bIsForce = false); // Socket 연결을 끊는다.
35+
bool BindIOCompletionPort(PLAYER_Session* pPlayerSession); // Bind
36+
bool BindRecv(PLAYER_Session* pPlayerSession); // WSARecv Overlapped I/O 작업을 시킨다.
37+
void CloseSocket(class PLAYER_Session* pPlayerSession, bool bIsForce = false); // Socket 연결을 끊는다.
38+
void ClosePlayer(unsigned __int64 uniqueId); // Socket 연결을 끊는다.
39+
bool SendMsg(PLAYER_Session* pPlayerSession, char* pMsg, int nLen); // Packet Send 처리를 한다.
3840
};
3941

4042
#endif

TCPServer/TCPServer/Main.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
#include "Main.h"
22

33
IOCP_Server iocp_server;
4-
std::list<PLAYER *> player;
4+
std::unordered_map<unsigned __int64, PLAYER *> player;
55
SERVER_Timer timer;
66

77
int main() {
88
std::cout << "Client Start Packet No : " << CLIENT_BASE << std::endl;
99
std::cout << "Max Client Packet No : " << MAX_CLIENT_PROTOCOL_NO << std::endl;
1010
std::cout << "Server Start Packet No : " << SERVER_BASE << std::endl;
1111
std::cout << "Max Server Packet No : " << MAX_SERVER_PROTOCOL_NO << std::endl << std::endl;
12-
1312
iocp_server.initServer(); // Socket 생성
1413
iocp_server.BindandListen(SERVERPORT); // Listen 처리
15-
iocp_server.initClient(player); // Player Init
14+
iocp_server.initClient(); // Player Init
1615
iocp_server.StartServer(); // Server 시작
1716
timer.startTimer(iocp_server.getHandle()); // Timer 시작
1817
}

TCPServer/TCPServer/Main.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <ctime>
2121
#include <list>
2222
#include <vector>
23+
#include <unordered_map>
2324
#include <chrono>
2425
#include <queue>
2526
#include <mutex>
@@ -33,6 +34,6 @@
3334
#include "Timer.h"
3435

3536
extern IOCP_Server iocp_server;
36-
extern std::list<PLAYER *> player;
37+
extern std::unordered_map<unsigned __int64, PLAYER *> player;
3738
extern SERVER_Timer timer;
3839
#endif

TCPServer/TCPServer/Timer.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ void SERVER_Timer::setTimerEvent(Timer_Event t)
3737
void SERVER_Timer::startTimer(HANDLE& handle)
3838
{
3939
g_hiocp = handle;
40-
timer_tread = std::thread([this]() { Timer_Thread(); });
41-
timer_tread.join();
40+
timer_thread = std::thread([this]() { Timer_Thread(); });
41+
timer_thread.join();
4242
}
4343

4444
void SERVER_Timer::destroyTimer()
4545
{
46-
timer_tread.join();
46+
timer_thread.join();
4747
}
4848

4949
SERVER_Timer::SERVER_Timer()
@@ -53,5 +53,5 @@ SERVER_Timer::SERVER_Timer()
5353

5454
SERVER_Timer::~SERVER_Timer()
5555
{
56-
timer_tread.join();
56+
timer_thread.join();
5757
}

TCPServer/TCPServer/Timer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class SERVER_Timer {
2929

3030
private:
3131
HANDLE g_hiocp;
32-
std::thread timer_tread;
32+
std::thread timer_thread;
3333
std::mutex mLock;
3434
std::chrono::high_resolution_clock::time_point serverTimer;
3535
std::priority_queue <Timer_Event, std::vector<Timer_Event>, comparison> timer_queue;

0 commit comments

Comments
 (0)