//////////////////////////////////////////////////////////////////////////////////////////////////
// 
//	ºñµ¿±â ¼ÒÄÏ ¼­¹ö
//	¿­Ç÷°­ÀÇ TCP/IP 21ÀåÀÇ ¿¹Á¦¸¦ Å¬·¹½ºÈ­
//	ÀÏ´Ü ¿¡ÄÚ ¼­¹öÀÌ¸ç. 167 ¹øÂ° ÁÙ¿¡¼­ ¼­¹ö¿¡¼­ ÇØÁÙ ÄÚµå¸¦ ÀÔ·ÂÇÏ¸é µÉµí..
//	


#define BUFSIZE 100		// ¹Þ¾Æ¿Ã µ¥ÀÌÅÍ ÃÖ´ë Å©±â
#define PORT 3000		// Æ÷Æ®¹øÈ£ ÇÒ´ç

// ÇØ´õÆÄÀÏ ¼±¾ð
#include <winsock2.h>
#include <iostream>

using namespace std;

// ws2_32.lib ¸µÅ©
#pragma comment(lib, "ws2_32.lib")

class socketServer
{
	private:
		// º¯¼ö ¼±¾ð	
		WSADATA wsaData;
		SOCKET hServSock;
		SOCKADDR_IN servAddr;

		SOCKET hSockArray[WSA_MAXIMUM_WAIT_EVENTS]; //¼ÒÄÏ ÇÚµé¹è¿­ - ¿¬°á ¿äÃ»ÀÌ µé¾î¿Ã ¶§¸¶´Ù »ý¼ºµÇ´Â ¼ÒÄÏÀÇ ÇÚµéÀ» ÀÌ ¹è¿­¿¡ ÀúÀå. (ÃÖ´ë64)
		SOCKET hClntSock;
		SOCKADDR_IN clntAddr;

		WSAEVENT hEventArray[WSA_MAXIMUM_WAIT_EVENTS];	// ÀÌº¥Æ® ¹è¿­ 
		WSAEVENT newEvent;
		WSANETWORKEVENTS netEvents;

		int clntLen;
		int sockTotal;
		int index, i;  
		char message[BUFSIZE];
		int strLen;

		void CompressSockets(SOCKET* hSockArray, int omitIndex, int total);
		void CompressEvents(WSAEVENT* hEventArray, int omitIndex, int total);
		void ErrorHandling(char *message);

	public:
		socketServer();
		int StartServer();
};

socketServer::socketServer()
{
	sockTotal=0;
}

int socketServer::StartServer()
{

	// À©¼Ó ÃÊ±âÈ­ (¼º°ø½Ã 0, ½ÇÆÐ½Ã ¿¡·¯ ÄÚµå¸®ÅÏ)
	if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){
		ErrorHandling("WSAStartup() error!");
	}

	
	// ¼ÒÄÏ »ý¼º (¼º°ø½Ã ÇÚµéÀ», ½ÇÆÐ½Ã "INVALID_SOCKET" ¹ÝÈ¯)
	hServSock = socket(PF_INET, SOCK_STREAM, 0);
	
	
	// ¼ÒÄÏ »ý¼º ½ÇÆÐ Ã³¸®
	if(hServSock==INVALID_SOCKET){
		ErrorHandling("socket() error");
	}


	// ¼ÒÄÏ Åë½ÅÀ» À§ÇÑ ±âº» Á¤º¸ 
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAddr.sin_port = htons(PORT);


	// ÁÖ¼Ò¿Í Port ÇÒ´ç (¹ÙÀÎµå!!)
	if(bind(hServSock, (struct sockaddr *) &servAddr, sizeof(servAddr))==SOCKET_ERROR){
		ErrorHandling("bind() error");
	}


	// ÀÌº¥Æ® ¹ß»ýÀ» È®ÀÎ (¼º°ø½Ã 0, ½ÇÆÐ½Ã "SOCKET_ERROR" ¹ÝÈ¯)
	newEvent = WSACreateEvent();
	if(WSAEventSelect(hServSock, newEvent, FD_ACCEPT)==SOCKET_ERROR){
		ErrorHandling("WSAEventSelect() error");
	}


	// ¿¬°á ´ë±â ¿äÃ» »óÅÂ·ÎÀÇ ÁøÀÔ (½ÅÈ£°¡ µé¾î¿Ã¶§±îÁö ´ë±â)
	if(listen(hServSock, 5)==SOCKET_ERROR){
		ErrorHandling("listen() error");
	}
  

	// ¼­¹ö ¼ÒÄÏ ÇÚµé Á¤º¸
	hSockArray[sockTotal]=hServSock;

	// ÀÌº¥Æ® ¿ÀºêÁ§Æ® ÇÚµé Á¤º¸
	hEventArray[sockTotal]=newEvent;

	// ÀüÃ¼ ¼ÒÄÏ¼ö
	sockTotal++;

  

	// ·çÇÁ
	while(1)
	{
		// ÀÌº¥Æ® Á¾·ù ±¸ºÐÇÏ±â(WSAWaitForMultipleEvents)
		index = WSAWaitForMultipleEvents(sockTotal, hEventArray, FALSE, WSA_INFINITE, FALSE);
		index = index-WSA_WAIT_EVENT_0;

		for(i=index; i<sockTotal; i++)
		{
			index = WSAWaitForMultipleEvents(1, &hEventArray[i], TRUE, 0, FALSE);			
			
			if((index==WSA_WAIT_FAILED || index==WSA_WAIT_TIMEOUT)) continue;
			else
			{
				index = i;
				WSAEnumNetworkEvents(hSockArray[index], hEventArray[index], &netEvents);
								

				// ÃÊ±â ¿¬°á ¿äÃ»ÀÇ °æ¿ì.
				if(netEvents.lNetworkEvents & FD_ACCEPT) 
				{
					if(netEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
					{
						puts("Accept Error");
						break;
					}

					clntLen = sizeof(clntAddr);
					
					// ¿¬°áÀ» ¼ö¶ô (accept | ¼º°ø½Ã ¼ÒÄÏÇÚµé ½ÇÆÐ½Ã "INVALID_SOCKET" ¹ÝÈ¯)
					hClntSock = accept(hSockArray[index], (SOCKADDR*)&clntAddr, &clntLen);

					// ÀÌº¥Æ® Ä¿³Î ¿ÀºêÁ§Æ® »ý¼º(WSACreateEvent)
					newEvent=WSACreateEvent();

					// ÀÌº¥Æ® ¹ß»ý À¯¹« È®ÀÎ(WSAEventSelect)
					WSAEventSelect(hClntSock, newEvent, FD_READ|FD_CLOSE);

					hEventArray[sockTotal]=newEvent;
					hSockArray[sockTotal]=hClntSock;
					sockTotal++;
				
					printf("»õ·Î ¿¬°áµÈ ¼ÒÄÏÀÇ ÇÚµé %d \n", hClntSock);
				}

				
				// µ¥ÀÌÅÍ Àü¼ÛÇØ¿Ã °æ¿ì.
				if(netEvents.lNetworkEvents & FD_READ) 
				{
					if(netEvents.iErrorCode[FD_READ_BIT] != 0)
					{
						puts("Read Error");
						break;
					}

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
//
//		¼­¹ö ÀÛ¾÷Àº ¿©±â¼­ ´ÙÇÏ°ÚÁö..
//

					// µ¥ÀÌÅÍ¸¦ ¹ÞÀ½ (message¿¡ ¹ÞÀº µ¥ÀÌÅÍ¸¦ ´ãÀ½)
					strLen=recv(hSockArray[index-WSA_WAIT_EVENT_0],message, sizeof(message), 0);					
					
					// µ¥ÀÌÅÍ ³¡¿¡ ³Î°ª ÀÔ·Â
					message[strLen]=0;
					
					// ¿¡ÄÚ(µ¥ÀÌÅÍ¸¦ÁØ Å¬¶óÀÌ¾ðÆ®¿¡ ´Ù½Ã µ¥ÀÌÅÍ½î±â)
					send(hSockArray[index-WSA_WAIT_EVENT_0], message, strLen,0);
					
					// ¿¹ÀÇ»ó È­¸é¿¡µµ ÇÑ¹ø º¸¿©Áà¾ßÁö
					cout<<message;

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
				}


				// ¿¬°á Á¾·á ¿äÃ»ÀÇ °æ¿ì.
				if(netEvents.lNetworkEvents & FD_CLOSE)
				{
					if(netEvents.iErrorCode[FD_CLOSE_BIT] != 0)
					{
						puts("Close Error");
						break;
					}
				
					WSACloseEvent(hEventArray[index]);
					
					// ¼ÒÄÏ Á¾·ù
					closesocket(hSockArray[index]);
					printf("Á¾·á µÈ ¼ÒÄÏÀÇ ÇÚµé %d \n", hSockArray[index]);

					sockTotal--;
					
					// ¹è¿­ Á¤¸®.
					CompressSockets(hSockArray, index, sockTotal);
					CompressEvents(hEventArray, index, sockTotal);
				}

			}//else
		}//for
	}//while

  
  
	// ÇÒ´ç ¹ÞÀº ¸®¼Ò½º ¹ÝÈ¯.
	WSACleanup();
	
	
	return 0;
}

/************************************
/* 
/*	CompressSockets
/*
*/
void socketServer::CompressSockets(SOCKET* hSockArray, int omitIndex, int total)
{
	int i;
	
	for(i=omitIndex; i<total; i++)
	{
		hSockArray[i]=hSockArray[i+1];
	}
}

/************************************
/* 
/*	CompressEvents
/*
*/
void socketServer::CompressEvents(WSAEVENT* hEventArray, int omitIndex, int total)
{
	int i;

	for(i=omitIndex; i<total; i++)
	{
		hEventArray[i]=hEventArray[i+1];
	}
}

/************************************
/* 
/*	ErrorHandling
/*
*/
void socketServer::ErrorHandling(char *message)
{	
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}




// ÇÑ¹ø ½ÇÇàÇØº¸´Â ¸ÞÀÎÇÔ¼ö!!
/************************************
/* 
/*	main
/*
*/
int main(){

	// ¼­¹ö ÀÎ½ºÅÏÆ®
	socketServer server;
	
	// ¼­¹ö½ÃÀÛ
	server.StartServer();
}
