#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
#include <windows.h>
#include <list>
#include <iterator>
#include<time.h>
/////////////////////////////////////////////////////////////////////////
CRITICAL_SECTION g_cs; //Thread synchronization object.
SOCKET g_hSocket; //server's listen socket
std::list<SOCKET> g_listClient; //List of linked client sockets. Manage sockets with a linked list.
//Save the socket of the newly connected client to the list.
BOOL AddUser(SOCKET hSocket)
{
::EnterCriticalSection(&g_cs);
g_listClient.push_back( hSocket );
::LeaveCriticalSection(&g_cs);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
//Send messages to all connected clients.
void SendChattingMessage(char *pszParam)
{
int nLength = strlen(pszParam);
std::list<SOCKET>::iterator it;
::EnterCriticalSection(&g_cs);
for (it = g_listClient.begin(); it != g_listClient.end(); ++it)
::send(*it, pszParam, sizeof(char)* (nLength + 1), 0);
::LeaveCriticalSection(&g_cs);
}
/////////////////////////////////////////////////////////////////////////
//Ctrl+C when detect event, terminate program
BOOL CtrlHandler(DWORD dwType)
{
if (dwType == CTRL_C_EVENT)
{
std::list<SOCKET>::iterator it;
//Close all connected clients and listening sockets and exit the program.
::shutdown(g_hSocket, SD_BOTH);
::EnterCriticalSection(&g_cs);
for (it = g_listClient.begin(); it != g_listClient.end(); ++it)
::closesocket(*it);
//Delete all information registered in the list of links.
g_listClient.clear();
::LeaveCriticalSection(&g_cs);
puts("All client connections have been terminated.");
//Wait for the threads communicating with the client to end.
::Sleep(100);
::DeleteCriticalSection(&g_cs);
::closesocket(g_hSocket);
::WSACleanup();
exit(0);
return TRUE;
}
return FALSE;
}
int flag = 0;
time_t start, end;
/////////////////////////////////////////////////////////////////////////
//thread function that provides a chat message service to clients.
//One thread is created for each connected client.
DWORD WINAPI ThreadFunction(LPVOID pParam)
{
char szBuffer[128] = { 0 };
int nReceive = 0;
SOCKET hClient = (SOCKET)pParam;
if (flag == 0) {
flag = 1;
start = time(NULL);
}
std::cout << (double)(time(NULL) - start) << std::endl;
puts("connected new client");
while ((nReceive = ::recv(hClient,
szBuffer, sizeof(szBuffer), 0)) > 0)
{
puts(szBuffer);
//Send received strings to all connected clients
SendChattingMessage(szBuffer);
memset(szBuffer, 0, sizeof(szBuffer));
}
puts("disconnected by client");
::EnterCriticalSection(&g_cs);
g_listClient.remove(hClient);
::LeaveCriticalSection(&g_cs);
::closesocket(hClient);
return 0;
}
/////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsa = { 0 };
if (::WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
puts("ERROR: Can't initial window socket");
return 0;
}
::InitializeCriticalSection(&g_cs);
//When the Ctrl+C key is pressed, it detects it and registers the function to be processed.
if ( ::SetConsoleCtrlHandler(
(PHANDLER_ROUTINE)CtrlHandler, TRUE) == FALSE )
puts("ERROR: Unable to enroll Ctrl+C controller");
//Create Connection Waiting Socket
g_hSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (g_hSocket == INVALID_SOCKET)
{
puts("ERROR: Unable to create connection waiting socket.");
return 0;
}
SOCKADDR_IN svraddr = { 0 };
svraddr.sin_family = AF_INET;
svraddr.sin_port = htons(25000);
svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (::bind(g_hSocket,
(SOCKADDR*)&svraddr, sizeof(svraddr)) == SOCKET_ERROR)
{
puts("ERROR: Unable to port and Ip into socket");
return 0;
}
//
if (::listen(g_hSocket, SOMAXCONN) == SOCKET_ERROR)
{
puts("ERROR: Unable to convert Listen status");
return 0;
}
puts("*** Start Chatting server ***");
//Process and respond to client connections
SOCKADDR_IN clientaddr = { 0 };
int nAddrLen = sizeof(clientaddr);
SOCKET hClient = 0;
DWORD dwThreadID = 0;
HANDLE hThread;
//Accept client connections and create a new socket (open)
while ((hClient = ::accept(g_hSocket,
(SOCKADDR*)&clientaddr, &nAddrLen)) != INVALID_SOCKET)
{
if (AddUser(hClient) == FALSE)
{
puts("ERROR: Unable to process client connection.");
CtrlHandler(CTRL_C_EVENT);
break;
}
//Received a string from the client.
hThread = ::CreateThread(NULL,
0,
ThreadFunction,
(LPVOID)hClient,
0,
&dwThreadID);
::CloseHandle(hThread);
}
puts("*** terminate chatting server ***");
return 0;
}