C++/IOCP
메인 코드만 저장. 나머지 내용은 SVN에 있음.
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#include <windows.h>
#include <process.h>
#define MESSAGE_SIZE 100
#define MAX_CLIENT 3
using namespace std;
struct E_DEFINE
{
enum ENUM
{
MAX_USER = 3,
};
};
// 전역 변수
SOCKET stClientSocket[MAX_CLIENT]; // 접속중인 클라이언트 소켓
int g_nClientCnt = 0; // 접속중인 클라이언트의 수
HANDLE g_hIocp = 0; // IOCP 핸들 값
// 소켓 정보 구조체 OVERLAPPED로 캐스팅 되어서 넘어간다
typedef struct SocketInfo
: public OVERLAPPED
{
WSAOVERLAPPED m_OverLapped;
SOCKET m_sSocket;
WSABUF m_WsaDataBuf;
int m_nReadLen;
int m_nWriteLen;
char m_cBuff[MESSAGE_SIZE];
SOCKADDR_IN m_siSocketAddr;
}SOCKETINFO, *PSOCKETINFO;
void SendMSG(char * message, int len, SOCKETINFO * pSocketInfo ); // 접속중인 유저들에게 패킷 broadcast 함수
DWORD WINAPI Thread_Func( LPVOID parm ); // IOCP 입력 결과에 의해서 사용될 함수
void ClientDisconnect( SOCKETINFO * pSocketInfo ); // 클라이언트 접속 종료 처리 함수
void ConsoleLog( char * strLOG ); // 콘솔 로그 출력 함수
void main()
{
ConsoleLog("Server Start");
WSADATA wsaData;
SOCKET hServSock;
SOCKADDR_IN servAddr, clntAddr;
SOCKETINFO * pSocketInfo;
char message[] = "Hello World";
char RecvBuff[100];
char szPort[] = "50001";
HANDLE hThread;
DWORD hThreadID;
if( 0 != WSAStartup(MAKEWORD( 2, 2 ), &wsaData ) )
{
ConsoleLog( "StartUp ERROR!" );
}
hServSock = socket( PF_INET, SOCK_STREAM, 0 );
if( INVALID_SOCKET == hServSock )
{
ConsoleLog( "Socket Open ERROR!" );
}
ZeroMemory( &servAddr, sizeof(servAddr) );
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(szPort));
if( SOCKET_ERROR == bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)))
{
ConsoleLog( "Bind ERROR!" );
}
if( SOCKET_ERROR == listen( hServSock, 5 ))
{
ConsoleLog( "Listen ERROR!" );
}
g_hIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
SYSTEM_INFO stSysInfo;
GetSystemInfo( &stSysInfo );
const int dwProcessors = stSysInfo.dwNumberOfProcessors * 2 + 2;
for( int i = 0; i < dwProcessors; i++ )
{
hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Thread_Func, 0, 0, &hThreadID );
}
while(TRUE)
{
SOCKET hClientSock;
SOCKADDR_IN hSockAddr;
int nRead = MESSAGE_SIZE;
int nFlags = 0;
int nSockAddrLen = sizeof( hSockAddr );
hClientSock = accept(hServSock, (SOCKADDR*)&hSockAddr, &nSockAddrLen );
if( INVALID_SOCKET == hClientSock )
{
ConsoleLog( "Accept ERROR!" );
}
pSocketInfo = new SOCKETINFO;
pSocketInfo->m_nReadLen = 0;
pSocketInfo->m_nWriteLen = 0;
pSocketInfo->m_sSocket = hClientSock;
pSocketInfo->m_cBuff[0] = '\0';
memcpy( &(pSocketInfo->m_siSocketAddr), &hSockAddr, nSockAddrLen );
ZeroMemory( &(pSocketInfo->m_OverLapped), sizeof(pSocketInfo->m_OverLapped) );
pSocketInfo->m_WsaDataBuf.len = MESSAGE_SIZE;
pSocketInfo->m_WsaDataBuf.buf = pSocketInfo->m_cBuff;
g_hIocp = CreateIoCompletionPort( (HANDLE)hClientSock , g_hIocp, (unsigned long)pSocketInfo, 0 );
if( nullptr == g_hIocp )
{
ConsoleLog( "CreateIoCompletion ERROR!" );
delete pSocketInfo;
continue;
}
if( SOCKET_ERROR == WSARecv( pSocketInfo->m_sSocket, &(pSocketInfo->m_WsaDataBuf), 1, (LPDWORD)(&pSocketInfo->m_nReadLen), (LPDWORD)(&nFlags), &(pSocketInfo->m_OverLapped), NULL ) );
{
int nRet = WSAGetLastError();
if( WSAGetLastError() != WSA_IO_PENDING )
{
ConsoleLog( "WSARecv ERROR!" );
delete pSocketInfo;
continue;
}
}
OVERLAPPED stOverLapped;
WSABUF dataBuf;
dataBuf.buf = message;
dataBuf.len = strlen(message);
ZeroMemory( &stOverLapped, sizeof(OVERLAPPED) );
DWORD dwBufferProgress;
if( WSASend( hClientSock, &dataBuf, 1, (LPDWORD)&dwBufferProgress, 0, NULL, NULL ) == SOCKET_ERROR )
{
if( WSAGetLastError() != WSA_IO_PENDING )
{
ConsoleLog( "WSASend ERROR" );
}
}
// 클라이언트 빈자리 검사 및 인원 제한
int nEmptyClientSlot = 0;
for( int nEmptyClientSlot = 0; nEmptyClientSlot<MAX_CLIENT; nEmptyClientSlot++ )
{
if( 0 == stClientSocket[nEmptyClientSlot] )
{
stClientSocket[g_nClientCnt] = hClientSock;
char strClinetInfo[100] = "";
sprintf( strClinetInfo, "Client %d accept || IP : %s", g_nClientCnt, inet_ntoa(hSockAddr.sin_addr) );
ConsoleLog( strClinetInfo );
g_nClientCnt++;
break;
}
}
}
// Socket Close
closesocket(hServSock);
WSACleanup();
return;
}
// 접속중인 전체 유저에게 Send하는 함수
void SendMSG(char * message, int len, SOCKETINFO * pSocketInfo )
{
DWORD dwBufferProgress;
int nRetVal ;
int nError;
for( int i = 0; i < g_nClientCnt; i++ )
{
if( 0 == stClientSocket[i] )
{
continue;
}
nRetVal = WSASend( stClientSocket[i], &pSocketInfo->m_WsaDataBuf, 1, &dwBufferProgress, 0, NULL, NULL );
nError = WSAGetLastError();
//send( stClientSocket[i], pSocketInfo->m_WsaDataBuf.buf, len, 0);
}
}
DWORD WINAPI Thread_Func(LPVOID parm)
{
HANDLE hCompletionPort = (HANDLE)parm;
DWORD dwTransFerred = 0;
int nFlag = 0;
int nKey = 0;
int nRet = 0;
int nErrorNum = 0;
SOCKETINFO * pSocketInfo;
OVERLAPPED *pOverLapped;
while(TRUE)
{
GetQueuedCompletionStatus( g_hIocp, (LPDWORD)&dwTransFerred, (LPDWORD)&nKey, (LPOVERLAPPED*)(&pOverLapped), INFINITE );
pSocketInfo = (SOCKETINFO*)nKey;
if( 0 == dwTransFerred )
{
ClientDisconnect( pSocketInfo );
closesocket( pSocketInfo->m_sSocket );
delete pSocketInfo;
continue;
}
if( nullptr == pSocketInfo )
{
continue;
}
if( 0 != dwTransFerred )
{
SendMSG(pSocketInfo->m_cBuff, dwTransFerred, pSocketInfo );
}
ZeroMemory( &(pSocketInfo->m_OverLapped), sizeof( OVERLAPPED ));
pSocketInfo->m_WsaDataBuf.len = MESSAGE_SIZE;
pSocketInfo->m_WsaDataBuf.buf = pSocketInfo->m_cBuff;
nFlag = 0;
nRet = WSARecv( pSocketInfo->m_sSocket, &(pSocketInfo->m_WsaDataBuf), 1, (LPDWORD)(&dwTransFerred), (LPDWORD)(&nFlag), &(pSocketInfo->m_OverLapped), NULL );
nErrorNum = WSAGetLastError();
}
return 0;
}
void ClientDisconnect( SOCKETINFO * pSocketInfo )
{
if( nullptr == pSocketInfo )
{
return;
}
char strClinetInfo[100] = "";
for( int i = 0; i < MAX_CLIENT; i++ )
{
if( pSocketInfo->m_sSocket == stClientSocket[i] )
{
sprintf( strClinetInfo, "Client %d Disconnect || IP : %s", i, inet_ntoa(pSocketInfo->m_siSocketAddr.sin_addr) );
stClientSocket[i] = 0;
g_nClientCnt--;
if( g_nClientCnt < 0 )
{
g_nClientCnt = 0;
}
break;
}
}
ConsoleLog( strClinetInfo );
}
void ConsoleLog( char * strLOG = nullptr )
{
SYSTEMTIME stSystemTime;
GetLocalTime( &stSystemTime );
char strTime[200] = "";
if( nullptr == strLOG )
{
strLOG = "";
}
sprintf_s( strTime, "[%d%02d%02d] %s",
stSystemTime.wYear,
stSystemTime.wMonth,
stSystemTime.wDay,
strLOG);
cout<< strTime << endl;
}
'내가만든 > 라인들' 카테고리의 다른 글
[로그분할기] 텍스트 용량별 분할기 (0) | 2016.02.28 |
---|---|
[이벤트] 카카오톡 욕설 집계 스크립트 (0) | 2016.02.28 |
[이벤트] 크리스마스 트리 (0) | 2016.02.28 |
[메모리풀] 헤더 파일 (0) | 2016.02.28 |
[채팅] 클라이언트 코드 (0) | 2016.02.28 |