CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 2 of 2
  1. #1
    Join Date
    Apr 2017
    Posts
    1

    How to set up CTRL_CLOSE_EVENT

    Hi I'm relatively new to creating servers, using sockets etc. I am creating a multithreaded server which allows multiple users to connect, I want to implement a method where when the client exits it should send a quit message to the server, I have been trying to do this by using CTRL_CLOSE_EVENT but can not get my head round how to use it.

    here is my client code that I am trying to implement the close event on
    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string>
    
    // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
    #pragma comment (lib, "Ws2_32.lib")
    #pragma comment (lib, "Mswsock.lib")
    #pragma comment (lib, "AdvApi32.lib")
    
    
    #define DEFAULT_BUFLEN 512
    #define DEFAULT_PORT "27015"
    using namespace std;
    
    static BOOL CtrlHandler(DWORD fdwCtrlType)
    {
    	switch (fdwCtrlType)
    	{
    		// Handle the CTRL-C signal. 
    	case CTRL_CLOSE_EVENT:
    		Beep(600, 200);
    		printf("Ctrl-Close event\n\n");
    		return(TRUE);
    	default:
    		return FALSE;
    	}
    }
    int __cdecl main(int argc, char **argv)
    {
    	WSADATA wsaData;
    	DWORD fdwcontroltype = SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
    	
    	SOCKET ConnectSocket = INVALID_SOCKET;
    	struct addrinfo *result = NULL,
    		*ptr = NULL,
    		hints;
    	char *sendbuf = "this is a test";
    	char recvbuf[DEFAULT_BUFLEN];
    	int iResult;
    	int recvbuflen = DEFAULT_BUFLEN;
    
    	
    
    	// Initialize Winsock
    	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    	if (iResult != 0) {
    		printf("WSAStartup failed with error: %d\n", iResult);
    		return 1;
    	}
    
    	ZeroMemory(&hints, sizeof(hints));
    	hints.ai_family = AF_UNSPEC;
    	hints.ai_socktype = SOCK_STREAM;
    	hints.ai_protocol = IPPROTO_TCP;
    
    	// Resolve the server address and port
    	iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
    	if (iResult != 0) {
    		printf("getaddrinfo failed with error: %d\n", iResult);
    		WSACleanup();
    		return 1;
    	}
    
    	// Attempt to connect to an address until one succeeds
    	for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
    
    		// Create a SOCKET for connecting to server
    		ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
    			ptr->ai_protocol);
    		if (ConnectSocket == INVALID_SOCKET) {
    			printf("socket failed with error: %ld\n", WSAGetLastError());
    			WSACleanup();
    			return 1;
    		}
    
    		// Connect to server.
    		iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
    		if (iResult == SOCKET_ERROR) {
    			closesocket(ConnectSocket);
    			ConnectSocket = INVALID_SOCKET;
    			continue;
    		}
    		break;
    	}
    
    	freeaddrinfo(result);
    
    	if (ConnectSocket == INVALID_SOCKET) {
    		printf("Unable to connect to server!\n");
    		WSACleanup();
    		return 1;
    	}
    
    	// Send an initial buffer
    	iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    	if (iResult == SOCKET_ERROR) {
    		printf("send failed with error: %d\n", WSAGetLastError());
    		closesocket(ConnectSocket);
    		WSACleanup();
    		return 1;
    	}
    
    	printf("Bytes Sent: %ld\n", iResult);
    
    	
    	int quit = 1;
    	// Send and Receive until the peer closes the connection
    	do {
    		
    		
    		iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
    		
    			if (iResult > 0)
    				printf("Bytes received: %d\n", iResult);
    			else if (iResult == 0)
    				printf("Connection closed\n");
    			else
    				printf("recv failed with error: %d\n", WSAGetLastError());
    			if (fdwcontroltype == CTRL_CLOSE_EVENT)
    			{
    
    				send(ConnectSocket, (char*)&quit, sizeof(quit), 0);
    
    				iResult = shutdown(ConnectSocket, SD_BOTH);
    				if (iResult == SOCKET_ERROR) {
    					printf("shutdown failed with error: %d\n", WSAGetLastError());
    					closesocket(ConnectSocket);
    					WSACleanup();
    					return 1;
    				}
    		}
    	} while (iResult > 0);
    
    	// shutdown the connection since no more data will be sent
    	iResult = shutdown(ConnectSocket, SD_SEND);
    	if (iResult == SOCKET_ERROR) {
    		printf("shutdown failed with error: %d\n", WSAGetLastError());
    		closesocket(ConnectSocket);
    		WSACleanup();
    		return 1;
    	}
    	// cleanup
    	closesocket(ConnectSocket);
    	WSACleanup();
    	system("PAUSE");
    	return 0;
    }
    here is my server code if you want to try and use it, you will need to remove game.h include
    Code:
    #undef UNICODE
    
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <mutex>
    #include <iostream>
    #include <string>
    #include "game.h"
    #include <fstream>
    
    // Need to link with Ws2_32.lib
    #pragma comment (lib, "Ws2_32.lib")
    // #pragma comment (lib, "Mswsock.lib")
    #define DEFAULT_BUFLEN 512
    #define DEFAULT_PORT "27015"
    #define DEFAULT_IP "127.0.0.1 "
    std::mutex MyMutex;
    int ClientCount;
    using namespace std;
    std::ofstream outfile ("serverconfig.txt", std::ofstream::out | std::ofstream::app);
    int callThread(SOCKET ClientSocket,int ClientCount )
    {
    	
    	char recvbuf[DEFAULT_BUFLEN];
    	
    	int recvbuflen = DEFAULT_BUFLEN;
    		int iResult, iSendResult;
    		// Receive until the peer shuts down the connection
    			
    		printf("thread count: %d\n", ClientCount);
    			do {
    			
    
    				iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
    					if (iResult == 1)
    					{
    						
    						cout << "Client " << ClientCount << " has left" << endl;
    						closesocket(ClientSocket);
    						ClientCount--;
    						
    					}
    					if (iResult > 0) {
    						
    							printf("Bytes received: %d\n", iResult);
    						
    
    							
    							// Echo the buffer back to the sender
    							
    							iSendResult = send(ClientSocket, recvbuf, iResult, 0);
    						
    							if (iSendResult == SOCKET_ERROR) {
    								
    									printf("send failed: %d\n", WSAGetLastError());
    								
    									closesocket(ClientSocket); 
    									ClientCount--;
    									return 1;
    								
    							}
    						
    							printf("Bytes sent: %d\n", iSendResult);
    						
    					}
    				
    					else if (iResult == 0)
    					{
    						ClientCount--;
    						printf("Connection closing...\n");
    					}
    					else {
    					
    						printf("recv failed: %d\n", WSAGetLastError());
    					
    						closesocket(ClientSocket);
    						ClientCount--;
    						return 1;
    					
    				}
    					
    			} while (iResult > 0);
    
    			
    }
    
    
    int __cdecl main(void)
    {
    	WSADATA wsaData;
    	int iResult;
    
    	SOCKET ListenSocket = INVALID_SOCKET;
    	SOCKET ClientSocket = INVALID_SOCKET;
    
    	struct addrinfo *result = NULL;
    	struct addrinfo hints;
    
    	int iSendResult;
    	ClientCount = 0;
    	char recvbuf[DEFAULT_BUFLEN];
    	int recvbuflen = DEFAULT_BUFLEN;
    	std::thread myThreads[100];
    	game game1;
    	string type;
    	string map;
    	int level;
    	int max;
    	int min;
    	//output server details to file 
    	ofstream outfile;
    	outfile.open("serverconfig.txt");
    	outfile << DEFAULT_IP;
    	outfile << DEFAULT_PORT;
    	outfile.close();
    	//get start up data
    	/*cout << "please choose a type: 1: Deathmatch 2: Capture the flag 3: Blood Diamond" << endl;
    	cin >> type;
    	cout << "Please choose a map:" << endl;
    	cin >> map;
    	cout << "please choose a difficulty level between 1 - 3: " << endl;
    	cin >> level;
    	cout << "Please choose the max number of clients: " << endl;
    	cin >> max;
    	cout << "Please choose the min number of clients" << endl; 
    	cin >> min; */
    
    	// Initialize Winsock
    	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    	if (iResult != 0) {
    		printf("WSAStartup failed with error: %d\n", iResult);
    		return 1;
    	}
    
    	ZeroMemory(&hints, sizeof(hints));
    	hints.ai_family = AF_INET;
    	hints.ai_socktype = SOCK_STREAM;
    	hints.ai_protocol = IPPROTO_TCP;
    	hints.ai_flags = AI_PASSIVE;
    
    	// Resolve the server address and port
    	iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    	if (iResult != 0) {
    		printf("getaddrinfo failed with error: %d\n", iResult);
    		WSACleanup();
    		return 1;
    	}
    
    	// Create a SOCKET for connecting to server
    	ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    	if (ListenSocket == INVALID_SOCKET) {
    		printf("socket failed with error: %ld\n", WSAGetLastError());
    		freeaddrinfo(result);
    		WSACleanup();
    		return 1;
    	}
    
    	// Setup the TCP listening socket
    	iResult = ::bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    	if (iResult == SOCKET_ERROR) {
    		printf("bind failed with error: %d\n", WSAGetLastError());
    		freeaddrinfo(result);
    		closesocket(ListenSocket);
    		WSACleanup();
    		return 1;
    	}
    	
    	freeaddrinfo(result);
    	if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
    		printf("Listen failed with error: %ld\n", WSAGetLastError());
    		closesocket(ListenSocket);
    		WSACleanup();
    		return 1;
    	}
    	for (;;)
    	{
    		//creating a temp socket for accepting a connction
    		SOCKET ClientSocket;
    		// Accept a client socket
    		ClientSocket = accept(ListenSocket, NULL, NULL);
    		if (ClientSocket == INVALID_SOCKET) {
    			printf("accept failed: %d\n", WSAGetLastError());
    			closesocket(ListenSocket);
    			WSACleanup();
    			return 1;
    		}
    		else
    		{
    
    			myThreads[ClientCount] = std::thread(callThread,ClientSocket,ClientCount);
    			ClientCount++;
    
    			printf("normal count: %d\n", ClientCount);
    
    			if (ClientCount == 1)
    			{
    				cout << "Waiting for another Client to connect" << endl;
    			}
    			/*if (ClientCount >= 2)
    			{
    				cout << "Game" << type << "in progress" << endl;
    			}*/
    			
    		}
    	}
    
    	// shutdown the connection since we're done
    	iResult = shutdown(ClientSocket, SD_SEND);
    	if (iResult == SOCKET_ERROR) {
    		printf("shutdown failed with error: %d\n", WSAGetLastError());
    		closesocket(ClientSocket);
    		WSACleanup();
    		return 1;
    	}
    
    	// cleanup
    	closesocket(ClientSocket);
    	WSACleanup();
    	system("PAUSE");
    	return 0;
    }

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: How to set up CTRL_CLOSE_EVENT

    Code:
    int __cdecl main(int argc, char **argv)
    {
    	WSADATA wsaData;
    	DWORD fdwcontroltype = SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
    	
    	int quit = 1;
    	// Send and Receive until the peer closes the connection
    	do {
    		
    		
    		iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
    		
    			if (iResult > 0)
    				printf("Bytes received: %d\n", iResult);
    			else if (iResult == 0)
    				printf("Connection closed\n");
    			else
    				printf("recv failed with error: %d\n", WSAGetLastError());
    			if (fdwcontroltype == CTRL_CLOSE_EVENT)
    			{
    
    				send(ConnectSocket, (char*)&quit, sizeof(quit), 0);
    				...
    			}
    you seem to ignore what MSDN states about SetConsoleCtrlHandler function and its return value:
    SetConsoleCtrlHandler function
    Adds or removes an application-defined HandlerRoutine function from the list of handler functions for the calling process.
    If no handler function is specified, the function sets an inheritable attribute that determines whether the calling process ignores CTRL+C signals.
    Syntax

    C++

    BOOL WINAPI SetConsoleCtrlHandler(
    _In_opt_ PHANDLER_ROUTINE HandlerRoutine,
    _In_ BOOL Add
    );
    ...
    Return value

    If the function succeeds, the return value is nonzero.
    If the function fails, the return value is zero. To get extended error information, call GetLastError.
    So the return value has nothing to do with the type of control signal received by the handler!
    Besides, this function does NOT handle the control signal. It only sets the HandlerRoutine function to "handle control signals received by the process". See https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx and https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    Last edited by 2kaud; April 17th, 2017 at 09:35 AM.
    Victor Nijegorodov

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured