Server - mehrer Clients parallel abfragen ?



  • Hi,
    heute wollte ich einen einfachen Server schreiben, soweit so gut, aber als ich allerdings mehrer Sockets parallel abfragen wollte, funktionierte kein Verbindungsaufbau mehr. Zwar verliert Telnet auch die Verbindung, sobald ich den Server beende, dennoch zeigt mein Server keine neue Verbindung an.

    Hier mein Code:

    #include "auth-server.h"
    
    fd_set g_fdSet;
    
    int main(int argc, char *argv[])
    {
    	if (getuid() != 0 || getgid() != 0)
    	{	printf ("You're not root  => uid %d ; gid %d\nexiting.", getuid(), getgid());
    		return 0;
    	}
    
    	SERVER server = SERVER();
    
    	return 1;
    }
    
    SERVER::SERVER()
    {
    	Init();
    	printf ("HAO");
    
    }
    
    int SERVER::Init(void)
    {
    	m_SrvSocket = socket(AF_INET, SOCK_STREAM, 0);
    
    	if (m_SrvSocket < 0 )
    	{	printf ("---ERROR: Socket konnte nciht erstellt werden\n");
    		close (m_SrvSocket);
    		return 0;
    	} else
    		printf (".Socket erfolgreich erstellt\n");
    
    	memset (&m_Srvaddr, 0, sizeof(sockaddr_in));
    	m_Srvaddr.sin_family	  = AF_INET;
    	m_Srvaddr.sin_port	  = htons (25987);
    	m_Srvaddr.sin_addr.s_addr = INADDR_ANY;
    
    	if ( bind (m_SrvSocket, (struct sockaddr*)&m_Srvaddr, sizeof(m_Srvaddr) )  == -1 )
    	{
    		printf ("---ERROR: Socket konnte nicht gebunden werden;\n");
    		close (m_SrvSocket);
    		return 0;
    	} else
    		printf (".Socket erfolgreich gebunden\n");
    
    	if ( listen(m_SrvSocket, 5) == -1 )
    	{
    		printf ("---ERROR: listen.\n");
    		close (m_SrvSocket);
    		return 0;
    	}
    
    	printf ("OK");
    	Main();
    }
    
    int SERVER::Main(void)
    {
    
    /*	sockaddr b;
    	socklen_t c = sizeof(b);
    	int a;
    	a = accept(m_SrvSocket, (struct sockaddr*)&b, &c);
    
    /**/	printf ("YOO");
    	strctConnection newClient;
    	struct timeval tv;
    
    	FD_ZERO (&g_fdSet);	
    	FD_SET (m_SrvSocket, &g_fdSet);
    
    	for (std::vector<strctConnection>::const_iterator it = m_Clients.begin(); it != m_Clients.end(); it++)
    		FD_SET(it->Socket, &g_fdSet);
    
    	int rc = select (1, &g_fdSet, NULL, NULL, NULL);
    
    	if (FD_ISSET(m_SrvSocket, &g_fdSet))
    	{
    		socklen_t tmpsize = sizeof(newClient.addr);
    		newClient.Socket = accept (m_SrvSocket, (sockaddr*)&newClient.addr, &tmpsize);
    		m_Clients.push_back(newClient);
    
    		printf ("  $Client %s connected\n", inet_ntoa (newClient.addr.sin_addr));
    	}
    
    	for (std::vector<strctConnection>::const_iterator it = m_Clients.begin(); it != m_Clients.end(); it++)
    	{
    		if ( FD_ISSET( it->Socket, &g_fdSet ) )
    		{
    			char Buffer[1024];
    			int rc = recv (it->Socket, Buffer, 1024, 0);
    
    			if (rc == 0 || rc < 0 )
    			{
    				printf ("  $Client %s hat die Verbindung geschlossen\n", inet_ntoa (it->addr.sin_addr));
    				close (it->Socket);
    			} 
    			else
    			{
    				Buffer[rc] = '\0';
    				printf ("  $Client %s sandt: %s", inet_ntoa (it->addr.sin_addr), Buffer);
    			}
    		}
    	}
    
    }
    

    Allerdings bin ich mir nicht ganz über den ersten Parameter der Funktion select() im Klaren. Verusacht dies das Problem ??

    Gruß
    Simon



  • man select schrieb:

    n is the highest-numbered descriptor in any of the three sets, plus 1.

    Was ist daran unklar?



  • ok danke, aber es funktioniert trotzdem nicht.
    Ausserdem gibt mein Programm nichtmal OK aus, was ja unmittelbar nach bind geschehen sollte. Wenn ich allerdings ein Timeout setze, werden, nachdem die Zeit abgelaufen ist, alle Meldungen ausgegeben.

    Ist das normal ?!

    Gruß Simon



  • Hi,

    versuch doch mal, stdout zu flush()en, nachdem du was auf den Bildschirm schreibst.



  • Achja, der erste Parameter von select() ist bei dir auch falsch.
    Und zwar muss select() als ersten Parameter den höchsten FD+1 bekommen (wie dr. g. schon gesagt hat), der in deinem Feld ist (du hast ja nur eins). Das ist am Anfang dein Server-Socket, bei eingehenden Verbindungen werden die sicherlich höhere Nummern bekommen, also musst du fd_max dementsprechend erhöhen.



  • ich würd erstmal in der man page zu select schauen



  • Hallo,
    danke für die Antworten, aber ich hatte select() inzwischen mit dem richtigen Parameter versorgt, indem ich einfach die Clients durchzähle und den Wert um eins inkrementiere. Dennoch funktioniert mein Server auf keinerlei Anfragen. Wie oben schon beschrieben reißt zwar die Verbindung beim Client ab, sobald ich den Server beende, dennoch meldetet der Server keine neue Verbindung.

    Was sagt ihr eingentlich dazu, dass meine OK-Marke nicht erreicht wird ? Mir kommt das einwenig spanisch vor, weil ja dadurch gezeigt wird, dass mein Programm sich gar nicht bis zu dem Befehl select() vorarbeiten kann ?!

    Gruß
    Simon



  • Was sagt ihr eingentlich dazu, dass meine OK-Marke nicht erreicht wird ? Mir kommt das einwenig spanisch vor, weil ja dadurch gezeigt wird, dass mein Programm sich gar nicht bis zu dem Befehl select() vorarbeiten kann ?!

    Wurde ja schon gesagt, dass du mal flushen sollst. Entweder ein Newline ausgeben oder fflush(stdout) hinter das printf.



  • Hi,
    sorry, das hatte ich total überlesen. Damit funktioniert es, aber sollte ich jetzt nach jedem printf ein fflush(stdout); hinterherschieben ?

    Allerdings geht der Verbindungsaufbau immer noch nicht, hier nochmal die Serverschleife:

    while (true)
    	{
    		FD_ZERO (&g_fdSet);	
    		FD_SET (m_SrvSocket, &g_fdSet);
    
    		for (std::vector<strctConnection>::const_iterator it = m_Clients.begin(); it != m_Clients.end(); it++)
    			FD_SET(it->Socket, &g_fdSet);
    
    		if ( (select (m_countClients + 1, &g_fdSet, NULL, NULL, NULL) ) < 0)
    		{	perror ("select failed"); fflush(stdout);
    			close (m_SrvSocket);
    			return 0;
    		}
    
    		if (FD_ISSET(m_SrvSocket, &g_fdSet))
    		{
    			m_countClients++;
    			socklen_t tmpsize = sizeof(newClient.addr);
    			newClient.Socket = accept (m_SrvSocket, (sockaddr*)&newClient.addr, &tmpsize);
    			m_Clients.push_back(newClient);
    
    			printf ("  $Client %s connected\n", inet_ntoa (newClient.addr.sin_addr));
    			fflush(stdout);
    		}
    
    		for (std::vector<strctConnection>::const_iterator it = m_Clients.begin(); it != m_Clients.end(); it++)
    		{
    			if ( FD_ISSET( it->Socket, &g_fdSet ) )
    			{
    				char Buffer[1024];
    				int rc = recv (it->Socket, Buffer, 1024, 0);
    
    				if (rc == 0 || rc < 0 )
    				{
    					printf ("  $Client %s hat die Verbindung geschlossen\n", inet_ntoa (it->addr.sin_addr));
    					close (it->Socket);
    				} 
    				else
    				{
    					Buffer[rc] = '\0';
    					printf ("  $Client %s sandt: %s", inet_ntoa (it->addr.sin_addr), Buffer);
    				}
    			}
    		}
    	}
    


  • Wenn du ein \n mit ausgibst, brauchst du meist kein flush. Am besten du flusht immer dann explizit, wenn eben nichts auf dem Bildschirm erscheint. Meistens vor so Sachen wie sleep() oder select().

    m_countClients? Ich glaube du hast den ersten select-Parameter doch noch nicht verstanden.

    Das ist nicht die Anzahl der Clients, sondern der höchste Filedescriptor, von allen Clients. Ein Filedescriptor ist ja auch nur ein int.

    Also zB. so:

    int eins = socket(..);
    int zwei = socket(..);
    ...
    select(zwei+1, ...)
    

Anmelden zum Antworten