Server verwaltet Clients per Threads

MrBean06

Grünschnabel
Hallo,

ich würde gerne realisieren, das mehrere Clients ein Lebenszeichen an einen Server senden, und diese Clients beim Server über Threads verwaltet werden.
Die Clients sollten dann in einer Liste oder Map gespeichert werden und einen "Lebenszeichentimer" bekommen.
Wie muss ich dieses Problem am besten angehen?

Danke
 
Ja, das es ein wenig mehr wird ist mir schon klar. Ein Client und einen Server habe ich auch schon programmiert. Nun wollte ich mich an die Threads machen die die Clientsverwaltung übernehmen... und bräuchte da doch ein wenig mehr Hilfe...
 
Also mein Client sendet momentan einfach nur eine Nachricht:
Code:
#include "stdafx.h" 
#include <iostream>
#include <winsock2.h>

//Mitteilung an den Linker, wo sich die nötigen Implemanteation der Winsock Funktionen befinden
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int main()
{
	WSADATA wsa;
	//initialisierung von Winsock (Parameter(Version, Infos zur API))
  WSAStartup (MAKEWORD (1,1) ,&wsa);

	//Schnittstelle zur Netzwerkschicht
	SOCKET s;
	char clientNummer[254] = "Client 1\r\n";
	//Socket beinhaltet (IP, TCP, Raw-Sockets das Protokoll)
	s = socket (AF_INET, SOCK_STREAM, 0 );
	
	//hier wird die Serveradresse gespeichert	
	sockaddr_in addr;
	//umwandeln von einem IP Strin in einen 4 byte Wert
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	//mit htons wird ein short (TCP Ports) von host byte order (höchstes byte links) in network byte order umgewandelt (höchstes byte rechts)
	addr.sin_port = htons (1001);
	//Adressenfamilie -> IP
	addr.sin_family = AF_INET;

	//Verbindung zum Server (Verbindung zum eigenen Socket, Serveradresse, Größe der Serveradresse) 
	if(connect(s, (SOCKADDR *) &addr, sizeof(addr)) == SOCKET_ERROR)
		//wenn kein Connect, dann gibt es einen Socketerror und es wird eine Fehlermeldung ausgegeben
		return (MessageBox(0, "Verbindung fehlgeschlagen!", "WinSock Tutorial Series", MB_ICONEXCLAMATION));
	
	//zusendene Daten(mein Socket, den wert aus dem Buffer, Länge des Buffer, Flag)
	send(s, clientNummer, strlen(clientNummer), 0);

	cout<<"\nEnde";
	cin.get();
	return 0;
}

Und mein Server empfängt diese und gibt sie aus:

Code:
// Server.cpp : Definiert den Einsprungpunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <winsock2.h>
#include <iostream>

//Mitteilung an den Linker, wo sich die nötigen Implemanteation der Winsock Funktionen befinden
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int main()
{
	WSADATA wsa;
	//initialisierung von Winsock (Parameter(Version, Infos zur API))
	WSAStartup (MAKEWORD (1,1) ,&wsa);


	SOCKET listenSocket;
	listenSocket = socket (AF_INET, SOCK_STREAM, 0 );
		
	sockaddr_in addr;
	addr.sin_addr.s_addr = INADDR_ANY; 
	addr.sin_port = htons (1001);
	addr.sin_family = AF_INET;

	if(bind(listenSocket,(struct sockaddr*)&addr, sizeof(addr)) == -1)
	{
		cout<<"Fehler bei bind";
	}	
			
	if (listen(listenSocket,3) == -1)
	{
		cout<<"Fehler beim listen";
				
	}
	printf("Waiting for client to connect...\n");

	SOCKET clientSocket = accept(listenSocket,(struct sockaddr*)&addr, 0); 
	if (clientSocket == -1) 
	{ 
		cout<<"Fehler bei accept";
		closesocket(listenSocket);
    WSACleanup();
    return 1;

	} 
	cout<<"Client connected."<<endl;

	char buffer[254]; 
	int bytes; 
    
	//Daten die empfangen werden 
	bytes = recv(clientSocket, buffer, sizeof(buffer) - 1, 0); 
  
 
	buffer[bytes] = '\0';

  
	cout<<buffer;
	MessageBox(0, buffer, "Client Connect!", MB_ICONINFORMATION);
	
	//listenSocket wird geschlossen
	closesocket(listenSocket);
	WSACleanup();

	cout<<"Close Connect";
	cin.get();
	return 0;
}

Wie gesagt als nächstes würde ich gerne realisieren, das ich mehrere Clients habe die sich mit dem Server verbinden sollen und dort möglichst verwaltet werden, sprich gespeichert mit ihrer ID(z.b. Port oder irgend eine Zahl, vielleicht die sie senden) und einer Zeit (Intervall).
Ist das möglich und kann ich das über Threads realisieren?
 
Am ende des Clients sollte man eigentlich aufräumen:

closesocket(s);
WSACleanup();

Wäre dein Problem nicht einfacher zu lösen über...Arrays?
Nun ja, bessere Frage: was willst du eigentlich überhaupt mit
dem Programm bezwecken wenns fertig ist?
 
Ja alles zu schließen hatte ich vergessen.

Was mir das Programm bringen soll..., persönlich nicht viel, aber mein Prof möchte das ich das programmiere, ist ne Studienarbeit, soll aber auch nicht zu gewaltig werden. Es geht halt um verteilte Systeme, sprich wie man Dinge parallel abarbeiten könnte. Sprich man sollte Threads, Mutex, Semaphoren oder was ähnliches verwenden.
Was würdest du denn mit dem Array anfangen wollen, meinst du nur die Speicherung der Clients, das würde sicherlich auch über Arrays gehen?
 
Hallo,

also prinzipiell hast du dir die Antwort doch schon selber gegeben :)
Du verwendest Threads für die Bearbeitung und eine map welche client Deskriptoren mit timerwert verknüpft ...
Das mit dem Threads könnte man folgendermaßen realisieren:

C++:
#define MAX_CLIENTS 10

map <int, int> g_client_timevals;

void server_thread (void *user_data)
{
  int cd = (int) user_data;

  while (1)
    {
      // sende und empfange von cd und überprüfe auf gültigkeit des time values
    }
}

int main (int argc, char **argv)
{
  struct sockaddr_in client_addr, server_addr;
  size_t csize;
  thread td[MAX_CLIENTS];
  ...;
  for (int i = 0; i < MAX_CLIENTS; i++)
    {
      cd = accept (sdescr, (struct sockaddr *) &client_addr, &csize);
      if (cd != -1)
        {
          g_client_timevals[cd] = time (NULL);
          td[i] = create_thread (server_thread, cd);
        }
       else
          //error handling
    }
  ...;
}

Wobei wenn du g_client_timevals in den Threads beschreibst (d.h. gleichzeitig auf den gleichen Key schreibend zugreifst) solltest du darauf achten das du die Variable entsprechend schützt.

Gruß,
RedWing
 
Zuletzt bearbeitet:
Danke erstmal, ich werde es mal ausprobieren, ob ich da was hinbekomme.

Doch das nächste Problem hast du ja schon angesprochen..., wie schütze ich den Zugriff auf die Variable, und wie könnte ich jetzt z.B. den Userzugriff integrieren, wenn ich den Timerintervall (wie lange Client als aktiv steht) manuell verändern möchte?
 
Wie du globale Variablen mit Mutexen oder Semaphoren schützen kannst hängt ganz von der Programmierumgebung ab die dir das Multithreading anbietet

Die Usereingabe würde ich auch in einen extra Thread packen. Dieser gibt dem Benutzer ein Menu aus: So in der Art:

Code:
1) print all connected client descriptors and their time-to-live values
2) change the time-to-live value of  a particular client

Der user kann dann eingeben was er machen möchte und kann ggf. einen neuen Zeitwert setzen oder irgendwie so.


Gruß,
RedWing
 
Zurück