Hi everybody. As of now, my server will accept clients in a loop, and will pass those clients off into a new windows thread. Inside the thread, the server will be able to receive any data each client may send.

When a client connects, the clientsConnected variable increments. So when 3 clients have connected, clientsConnected will hold a value of 3.

Trouble is, I do not know how to better maintain these connections.

Things I want to implement, but don't know how.

  • If a client disconnects, I want clientsConnected to drop down to 2.
  • I want to be able to hold data relating to each socket, such as "name".
  • I want to be able to loop through this container of all sockets and be able to send a message to all of them (client0, client1, client2, etc.) depending on how you help me manage all of these sockets.

Here is my current code:

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <winsock.h>
#include <iostream>
using namespace std;


// thread for receiving commands
DWORD WINAPI receive_commands(LPVOID lpParam)
{

	//set socket to the socket passed in as parameter
	SOCKET current_client = (SOCKET)lpParam;

	char receiveBuffer[256];	//buffer to hold received data
	char sendBuffer[256];	//buffer to hold sent data
	int result;		//contains return values for error checking

	//main loop
	while (true)
	{
		result = recv(current_client, receiveBuffer, sizeof(receiveBuffer), 0);
		Sleep(10);

		if (result > 0) 
		{
			cout << "Client " << "??: " << receiveBuffer << endl;
			if(strstr(receiveBuffer, "hello"))
			{
				//greet the user
				strcpy(sendBuffer, "Hello.");
				Sleep(10);
				send(current_client, sendBuffer, sizeof(sendBuffer), 0);
			}
			
			if(strstr(receiveBuffer, "goodbye"))
			{
				//disconnect the user

				strcpy(sendBuffer, "Goodbye!");
				Sleep(10);
				send(current_client, sendBuffer, sizeof(sendBuffer), 0);

				//close the socket and end the thread
				closesocket(current_client);
				
				ExitThread(0);
			}

			//clear the buffers
			strcpy(sendBuffer, "");
			strcpy(receiveBuffer, "");
		}
	} // end while
} // end receive_commands

int main()
{

	SOCKET sock; //the master socket which listens for connections
	DWORD thread; //for the thread
	WSADATA wsaData;
	sockaddr_in server;
	int port = 54321;
	int clientsConnected = 0;

	cout << "Server v1.0\n";
	cout << "===================\n";

	//start winsock
	int ret = WSAStartup(MAKEWORD(2,2), &wsaData);
	if(ret != 0) 
	{ 
		cout << "Winsock failed to start.\n";
		system("pause");
		return 1; 
	} //error checking
	else 
	{
		cout << "\nVersion: " << wsaData.wVersion
			 << "\nDescription: " << wsaData.szDescription
			 << "\nStatus: " << wsaData.szSystemStatus << endl << endl;
	}

	//fill in winsock struct
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(port);  //listen on port 54321

	//create the socket
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if(sock == INVALID_SOCKET) 
	{ 
		cout << "Invalid Socket.\n";
		system("pause");
		return 1; 
	} //error checking

	//bind the socket to our port (built in error-checking)
	if( bind(sock, (sockaddr*)&server, sizeof(server)) != 0 ) 
	{ 
		printf("");
		return 1; 
	} 

	//listen for a connection
	if(listen(sock, 5) != 0) { return 1; }

	//client socket
	SOCKET client;
	sockaddr_in from;
	int fromlen = sizeof(from);

	//loop forever
	while (true)
	{
		//accept connections 
		client = accept(sock, (struct sockaddr*)&from, &fromlen);
		cout << "Client connected.\n";
		clientsConnected++;
		cout << "Clients online: " << clientsConnected << endl;

		//create a thread and pass new client socket as parameter
		CreateThread(NULL, 0, receive_commands, (LPVOID)client, 0, &thread);
		
	}

	//shutdown winsock
	closesocket(sock);
	WSACleanup();

	//exit
	return 0;
}

Edited 7 Years Ago by BlackPhoenix: n/a

I like using IOCP I/O completion Ports. Works very nicely for minimal threads to maintain thousands of sockets!

Works well for only a couple sockets as well! Its a worker thread to event manager.

It involves, events, sockets, worker threads, and a IOCP setup. You can even assign a user value to each socket this way so when a thread wakes up from a socket event, you can associate it with an exact connection in your code. Something not easily done the old fashioned way!

Edited 7 Years Ago by wildgoose: n/a

This article has been dead for over six months. Start a new discussion instead.