#include <iostream>
using namespace std;

#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")

#define  BUF_SIZE	 64

int main(int argc, char* argv[]) {
	WSADATA			wsd;			//WSADATA變數
	SOCKET			sServer;		//伺服器Socket
	SOCKET			sClient;		//客戶端Socket
	SOCKADDR_IN		addrServ;;		//伺服器地址
	char			buf[BUF_SIZE];	//接收資料緩衝區
	int				retVal;			//返回值
	int             bufNum = 0;
	//Select模式的相關變數
	FD_SET			socketSet;		//伺服器Sockets集合
	FD_SET			readSet;		//測試可讀性的Sockets集合
	FD_SET			writeSet;		//測試可寫性的Sockets集合
	bool			bSent;			//是否回傳訊息給Client的記號
	//初始化Socket動態庫
	if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
		cout << "WSAStartup failed!" << endl;
			system("pause");
		return 1;
	}

	//初始化Sockets集合
	FD_ZERO(&socketSet);
	
	//建立Socket
	sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	
	if(INVALID_SOCKET == sServer) {
		cout << "socket failed!" << endl;
		WSACleanup();//釋放Socket資源;
			system("pause");
		return  -1;
	}
	//將伺服器Socket加入伺服器Sockets集合
	FD_SET(sServer, &socketSet);
	
	//伺服器Socket地址 
	addrServ.sin_family = AF_INET;
	addrServ.sin_port = htons(4999);
	addrServ.sin_addr.s_addr = INADDR_ANY;

	//綁定Socket
	retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
	if(SOCKET_ERROR == retVal) 	{	
		cout << "bind failed!" << endl;
		closesocket(sServer);	//關閉Socket
		WSACleanup();			//釋放Socket資源;
			system("pause");
		return -1;
	}
	
	//開始監聽 
	retVal = listen(sServer, 1);
	if(SOCKET_ERROR == retVal) {
		cout << "listen failed!" << endl;		
		closesocket(sServer);	//關閉Socket
		WSACleanup();			//釋放Socket資源;
			system("pause");
		return -1;
	}
	cout << "Server is listening..." << endl;
	//待續_Start
	//伺服器只管接收客戶端的連線以及問候語，所以只要判斷可讀性便可
	while (1) {
		FD_ZERO(&readSet);		//清空測試可讀性
		FD_ZERO(&writeSet);		//清空測試可寫性
		bSent = false;
		readSet = socketSet;	//將要測試可讀性的Socket加入readSet
		writeSet = socketSet;	//將要測試可讀性的Socket加入writeSet
		if (SOCKET_ERROR == select(0, &readSet, &writeSet, NULL, NULL)) {
			cout << "select() returned with error " << WSAGetLastError() << endl;
			closesocket(sServer);	//關閉Socket
			WSACleanup();			//釋放Socket資源;
				system("pause");
			return -1;
		}
		//接下來看看測試的結果
		if (FD_ISSET(sServer, &readSet)) {//伺服器Socket還在集合中嗎？
			//在，那表示有客戶端的連線進來了
			cout << "Client is connecting...";
			sClient = accept(sServer, NULL, NULL);
			if(INVALID_SOCKET == sClient) {
				cout << "accept failed!" << endl;
				closesocket(sServer);	//關閉Socket
				WSACleanup();			//釋放Socket資源;
					system("pause");
				return -1;
			}
			cout << " connected." << endl;
			//將客戶端Socket加入伺服器Sockets集合
			FD_SET(sClient, &socketSet);
				system("pause");
		}
		if (FD_ISSET(sClient, &readSet)) {//客戶端Socket還在集合中嗎？
			//接收客戶端資料
			ZeroMemory(buf, BUF_SIZE);
			retVal = recv(sClient, buf, BUF_SIZE, 0);
			if (SOCKET_ERROR == retVal) {
				cout << "recv failed!" << endl;		
				closesocket(sServer);	//關閉Socket
				closesocket(sClient);	//關閉Socket		
				WSACleanup();			//釋放Socket資源;
					system("pause");
				return -1;
			}
			if (0==retVal) break;
			cout<<"MSG Received from Client: "<<buf<<endl;
			bSent = true;
		}		
		if (FD_ISSET(sClient, &writeSet) && bSent) {//客戶端Socket還在集合中嗎？
			if (SOCKET_ERROR == retVal) {
				cout << "recv failed!" << endl;		
				closesocket(sServer);	//關閉Socket
				closesocket(sClient);	//關閉Socket		
				WSACleanup();			//釋放Socket資源;
				system("pause");
				return -1;
			}
			retVal = send(sClient, buf, strlen(buf), 0);
			if (!strcmp(buf,"bye")) break;
		}
		Sleep(100);	//休息一段時間以降低在While迴圈中CPU的使用率
	}
    //待續_End
	
	//退出
	closesocket(sServer);		//關閉Socket
	closesocket(sClient);		//關閉Socket
	WSACleanup();				//釋放Socket資源;

	system("pause");
	return 0;
}