select() blockiert [gelöst]



  • Hallo,
    ich möchte einen Server programmieren, der mehrere Clients bedienen kann.
    Solange kein Client verbunden ist, geht select() ohne Blockade durch. Sobald sich aber der erste Client verbunden hat und seine gesendeten Daten empfangen wurden und dann select() ein weiteres mal aufgerufen wurde, blockiert select().

    Kann mir jemand sagen wieso? Schließlich gebe ich als vierten Parameter (struct timeval) nicht NULL an. Also sollte select doch nicht blockieren...

    Von der groben Struktur her ist es so:

    1. Es gibt ein Socket-Array um die verbundenen Clients zu verwalten

    2. Es gibt einen Thread, der auf verbindungen wartet. Kommt eine neue Verbindung an, wird diese im Socket-Array aufgenommen (sofern noch Platz ist)

    3. In der Main-Funktion gibt es eine Endlos-Schleife, die die Funktion getNextClient(...) aufruft. Wenn diese einen gültigen Socket zurückgibt, wird von diesem gelesen.

    4. Die Funktion getNextClient(...) arbeitet mit select und sieht folgendermaßen aus (erstmal ein paar Typedefs):

    typedef char RequestPuffer[6720];
    typedef char ResponsePuffer[10224];
    typedef SOCKET ClientArray[10];
    
    typedef SOCKET ClientArray[10];
    SOCKET getNextClient(ClientArray clients)
    {
    		fd_set kandidaten;
    		int y;
    		FD_ZERO(&kandidaten);
    		y=0;				
    		for(int x=0;x<sizeof(ClientArray)/sizeof(clients[0]);x++)
    		{
    			if(clients[x] != INVALID_SOCKET)
    			{
    				FD_SET(clients[x],&kandidaten);
    				y++;
    			}
    		}
    		if(y==0) //Noch keine Verbindung eingegangen
    		{
    			return INVALID_SOCKET;
    		}
    		kandidaten.fd_count = y;
    		struct timeval warteZeit;
    		warteZeit.tv_usec = 1;
    		printf("Hier 1\n");
    		int rc = select(0,&kandidaten,NULL,NULL,&warteZeit);
    		printf("Hier 2\n");
    		if(rc==SOCKET_ERROR)
    		{
    			printf("rc==SOCKET_ERROR\n");
    			printf("WSAGetLastError:%d\n",WSAGetLastError());
    			return INVALID_SOCKET;
    		}
    		for(unsigned int x=0;x<sizeof(clients)/sizeof(clients[0]);x++)
    		{
    			if(FD_ISSET(clients[x],&kandidaten))
    			{
    				return clients[x];
    			}
    		}
    		return INVALID_SOCKET;
    }
    

    Der Server liefert dann folgende Konsolen-Ausgabe:

    ...
    Anzahl verbundener Clients: 0
    getNextClient: -1
    Anzahl verbundener Clients: 0
    Verbindung hergestellt.
    Warte auf Verbindung...
    getNextClient: -1
    Anzahl verbundener Clients: 1
    Hier 1
    Hier 2
    getNextClient: 124
    Empfange Request
    Request empfangen: 6720 Bytes
    Anzahl verbundener Clients: 1
    Hier 1
    

    Hier noch die restlichen beteiligten Funktionen:

    static void VerbindenThread(LPVOID p)
    {
    	RequestResponseVerwaltung* verwaltung = (RequestResponseVerwaltung*)p;
    
    	struct sockaddr_in serverAddr;
    	u_long port = (u_long)atol(portStr);
    	serverAddr.sin_addr.s_addr = inet_addr(ipStr);
    	serverAddr.sin_port = htons(port);
    	serverAddr.sin_family = AF_INET;
    
    	struct sockaddr_in cli;
    	int cli_size = sizeof(cli);
    
    	unsigned int bytes,temp;
    
    	WSADATA	wsa;
    	if (WSAStartup(MAKEWORD(2.2, 2.2), &wsa))
    	{
    		printf("WSAStartup() failed, %d\n", WSAGetLastError());
    		system("pause");
    		return;
    	}
    	verwaltung->server = socket(serverAddr.sin_family, SOCK_STREAM, IPPROTO_TCP);
    	if (verwaltung->server == INVALID_SOCKET)
    	{
    		printf("socket() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return;
    	}
    
    	if (bind(verwaltung->server, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
    	{
    		printf("bind() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return;
    	}
    
    	if (listen(verwaltung->server, 3) == -1)
    	{
    		printf("listen () failed, %d\n",WSAGetLastError());
    		system("pause");
    		return;
    	}
    	for(unsigned int x=0;x<sizeof(ClientArray)/sizeof(SOCKET);x++)
    	{
    		verwaltung->clients[x] = INVALID_SOCKET;
    	}
    	verwaltung->warteAufVerbindungen = true;
    	while(verwaltung->verbindenRunning)
    	{
    		printf("Warte auf Verbindung...\n");
    		SOCKET client = accept(verwaltung->server, (sockaddr*)&cli, &cli_size);
    		printf("Verbindung hergestellt.\n");
    		WaitForSingleObject(verwaltung->mutex,INFINITE);
    		unsigned int freierSlot = sizeof(ClientArray)/sizeof(SOCKET); 
    		for(unsigned int x=0;x<sizeof(ClientArray)/sizeof(SOCKET);x++)
    		{
    			if(verwaltung->clients[x] == INVALID_SOCKET)
    			{
    				freierSlot = x;
    				break;
    			}
    		}
    		if(freierSlot == sizeof(ClientArray)/sizeof(SOCKET))
    		{
    			printf("Maximale Anzahl an Clients %cberschritten",129);
    			closesocket(client);
    			client = INVALID_SOCKET;
    		}
    		else
    		{
    			verwaltung->clients[freierSlot] = client;
    		}
    		ReleaseMutex(verwaltung->mutex);
    	}
    	verwaltung->warteAufVerbindungen = false;
    }
    
    int main()
    {
    	RequestResponseVerwaltung verwaltung;
    	verwaltung.warteAufVerbindungen = false;
    	verwaltung.verbindenRunning = true;
    	CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)VerbindenThread,&verwaltung,0,NULL);
    	while(!verwaltung.warteAufVerbindungen)
    	{
    		Sleep(10);
    	}
    
    	while(true)
    	{
    		int ch = getch();
    		if(ch == VK_ESCAPE)
    		{
    			return 0;
    		}
    		else
    		{
    			unsigned int anzahl = 0;
    			WaitForSingleObject(verwaltung.mutex,INFINITE);
    			for(unsigned int x=0;x<sizeof(verwaltung.clients)/sizeof(verwaltung.clients[0]);x++)
    			{
    				if(verwaltung.clients[x] != INVALID_SOCKET)
    				{
    					anzahl++;
    				}
    			}
    			printf("Anzahl verbundener Clients: %d\n",anzahl);
    			SOCKET client = getNextClient(verwaltung.clients);
    			printf("getNextClient: %d\n",client);
    			ReleaseMutex(verwaltung.mutex);
    
    			if(client != INVALID_SOCKET)
    			{
    			    RequestPuffer req;
    			    ResponsePuffer res;
    			    empfangeRequest(client,req);
    			    sendeResponse(client,res);
    			}
    		}
    	}
    }
    
    bool empfangeRequest(SOCKET client,RequestPuffer req)
    {
    	printf("Empfange Request\n");
    	unsigned int bytes = 0;
    	while(bytes<sizeof(RequestPuffer))
    	{
    		int temp = recv(client,&req[bytes],sizeof(RequestPuffer)-bytes, 0);
    		if (temp == -1)
    		{
    			printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(client);
    			client = INVALID_SOCKET;
    			return false;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    	printf("Request empfangen: %d Bytes\n",bytes);
    	return true;
    }
    
    bool sendeResponse(SOCKET client,ResponsePuffer res)
    {
    	printf("Sende Response\n");
    	res[sizeof(ResponsePuffer)-1] = 0;
    	unsigned int bytes = 0;
    	while(bytes < sizeof(ResponsePuffer))
    	{
    		int temp = send(client, &res[bytes],sizeof(ResponsePuffer), 0);
    		if (temp == -1)
    		{
    			printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(client);
    			client = INVALID_SOCKET;
    			return false;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    	printf("Response gesendet: %d Bytes\n",bytes);
    	return true;
    }
    

    MfG



  • Ich habe hier nochmal den Code vereinfacht, so dass keine Threads drin sind:

    #include <Windows.h>
    #include <conio.h>
    #include <stdio.h>
    
    typedef char RequestPuffer[6720];
    typedef char ResponsePuffer[10224];
    typedef SOCKET ClientArray[10];
    
    char* ipStr = "192.168.0.60";
    char* portStr = "17706";
    
    bool empfangeRequest(SOCKET client,RequestPuffer req)
    {
    	printf("Empfange Request\n");
    	unsigned int bytes = 0;
    	while(bytes<sizeof(RequestPuffer))
    	{
    		int temp = recv(client,&req[bytes],sizeof(RequestPuffer)-bytes, 0);
    		if (temp == -1)
    		{
    			printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(client);
    			client = INVALID_SOCKET;
    			return false;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    	printf("Request empfangen: %d Bytes\n",bytes);
    	return true;
    }
    bool sendeResponse(SOCKET client,ResponsePuffer res)
    {
    	printf("Sende Response\n");
    	res[sizeof(ResponsePuffer)-1] = 0;
    	unsigned int bytes = 0;
    	while(bytes < sizeof(ResponsePuffer))
    	{
    		int temp = send(client, &res[bytes],sizeof(ResponsePuffer), 0);
    		if (temp == -1)
    		{
    			printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(client);
    			client = INVALID_SOCKET;
    			return false;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    	printf("Response gesendet: %d Bytes\n",bytes);
    	return true;
    }
    
    SOCKET getNextClient(ClientArray clients)
    {
    		fd_set kandidaten;
    		int y;
    		FD_ZERO(&kandidaten);
    		y=0;				
    		for(int x=0;x<sizeof(ClientArray)/sizeof(clients[0]);x++)
    		{
    			if(clients[x] != INVALID_SOCKET)
    			{
    				FD_SET(clients[x],&kandidaten);
    				y++;
    			}
    		}
    		if(y==0) //Noch keine Verbindung eingegangen
    		{
    			return INVALID_SOCKET;
    		}
    		kandidaten.fd_count = y;
    		struct timeval warteZeit;
    		warteZeit.tv_usec = 1;
    		printf("Hier 1\n");
    		int rc = select(0,&kandidaten,NULL,NULL,&warteZeit);
    		printf("Hier 2\n");
    		if(rc==SOCKET_ERROR)
    		{
    			printf("rc==SOCKET_ERROR\n");
    			printf("WSAGetLastError:%d\n",WSAGetLastError());
    			return INVALID_SOCKET;
    		}
    		for(unsigned int x=0;x<sizeof(clients)/sizeof(clients[0]);x++)
    		{
    			if(FD_ISSET(clients[x],&kandidaten))
    			{
    				return clients[x];
    			}
    		}
    		return INVALID_SOCKET;
    }
    
    int main()
    {
    	SOCKET server;
    	ClientArray clients;
    
    	struct sockaddr_in serverAddr;
    	u_long port = (u_long)atol(portStr);
    	serverAddr.sin_addr.s_addr = inet_addr(ipStr);
    	serverAddr.sin_port = htons(port);
    	serverAddr.sin_family = AF_INET;
    
    	struct sockaddr_in cli;
    	int cli_size = sizeof(cli);
    
    	unsigned int bytes,temp;
    
    	WSADATA	wsa;
    	if (WSAStartup(MAKEWORD(2.2, 2.2), &wsa))
    	{
    		printf("WSAStartup() failed, %d\n", WSAGetLastError());
    		system("pause");
    		return 1;
    	}
    	server = socket(serverAddr.sin_family, SOCK_STREAM, IPPROTO_TCP);
    	if (server == INVALID_SOCKET)
    	{
    		printf("socket() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 2;
    	}
    
    	if (bind(server, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
    	{
    		printf("bind() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 3;
    	}
    
    	if (listen(server, 3) == -1)
    	{
    		printf("listen () failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 4;
    	}
    	for(unsigned int x=0;x<sizeof(ClientArray)/sizeof(SOCKET);x++)
    	{
    		clients[x] = INVALID_SOCKET;
    	}
    
    	printf("Warte auf Verbindung...\n");
    	SOCKET client = accept(server, (sockaddr*)&cli, &cli_size);
    	printf("Verbindung hergestellt.\n");
    	unsigned int freierSlot = sizeof(ClientArray)/sizeof(SOCKET); 
    	for(unsigned int x=0;x<sizeof(ClientArray)/sizeof(SOCKET);x++)
    	{
    		if(clients[x] == INVALID_SOCKET)
    		{
    			freierSlot = x;
    			break;
    		}
    	}
    	if(freierSlot == sizeof(ClientArray)/sizeof(SOCKET))
    	{
    		printf("Maximale Anzahl an Clients %cberschritten",129);
    		closesocket(client);
    		client = INVALID_SOCKET;
    	}
    	else
    	{
    		clients[freierSlot] = client;
    	}
    
    	int ch = VK_SPACE;
    	while(ch!=VK_ESCAPE)
    	{
    
    		SOCKET client = getNextClient(clients);
    		RequestPuffer req;
    		ResponsePuffer res;
    		empfangeRequest(client,req);
    		sendeResponse(client,res);
    		ch = getch();
    	}
    	system("pause");
    	return 0;
    }
    

    Hier starte ich den Server, dann den Client, und drücke dann im Server die Leertaste. Dann blockiert select().

    Ausgabe:

    Warte auf Verbindung...
    Verbindung hergestellt.
    Hier 1
    Hier 2
    Empfange Request
    Request empfangen: 6720 Bytes
    Sende Response
    Response gesendet: 10224 Bytes
    Hier 1
    

    Es geht erst weiter, wenn der Client erneut etwas sendet.

    Warte auf Verbindung...
    Verbindung hergestellt.
    Hier 1
    Hier 2
    Empfange Request
    Request empfangen: 6720 Bytes
    Sende Response
    Response gesendet: 10224 Bytes
    Hier 1
    Hier 2
    Empfange Request
    Request empfangen: 6720 Bytes
    Sende Response
    Response gesendet: 10224 Bytes
    

    Sollte select nicht durchgehen und danach kein Socket mehr in fd_set kandidaten gesetzt sein wenn der Client nicht erneut sendet? ODer hab ich da was falsch verstanden?

    EDIT: habe nochwas herausgefunden: Wenn ich empfangeRequest(client,req); UND sendeResponse(client,res); auskommentiere, dann geht selct durch - und zwar jedes mal wenn ich die Leertaste drücke.

    MfG



  • Ok jetzt wirds unheimlich:

    ich programmiere normalerweise mit VC++ 2010. Nun habe ich exakt den selben Code mal in VC++ 2008 kompiliert. Und da funktioniert es. select() blockiert nicht.

    Wie kann das sein?
    Was soll ich tun?
    Soll ich mich an Microsoft wenden?

    MfG

    EDIT:
    Hier mein aktuelles Programm. Ich wäre dankbar wenn das jemand ausprobieren könnte und mir ne Bestätigung gibt ob das bei euch auch so ist.

    Durch z.B. Leertaste drücken nur im Server, sollte der Server nicht blockieren.

    Noch was merkwürdiges: Wenn ich vor UND nach dem select()-Aufruf noch ein printf() mache (Zeilen 202 und 204), funktionierts auch in VC++ 2010.

    Server:

    #include <WinSock2.h>
    #include <conio.h>
    #include <stdio.h>
    
    typedef char RequestPuffer[6720];
    typedef char ResponsePuffer[10224];
    char* ipStr = "192.168.0.60";
    char* portStr = "17706";
    
    class RequestResponseServer
    {
    	public:
    		RequestResponseServer(unsigned int maxAnzahlClients);
    		~RequestResponseServer();
    		unsigned int starte();
    		bool verbindungAnnehmen();
    		const RequestPuffer* empfangeRequest();
    		bool sendeResponse(ResponsePuffer res);
    
    	protected:
    		bool empfangsbereit(SOCKET client);
    		void wähleNächstenClient();
    
    		struct sockaddr_in serverAddr;
    		struct sockaddr_in cli;
    		int cli_size;
    
    		unsigned int maxAnzahlClients;
    		RequestPuffer req;
    		SOCKET* clients;
    		SOCKET server;
    		unsigned int aktuellerIndex;
    };
    RequestResponseServer::RequestResponseServer(unsigned int maxAnzahlClients)
    {
    	clients = new SOCKET[maxAnzahlClients];
    	this->maxAnzahlClients = maxAnzahlClients;
    	for(unsigned int x=0;x<this->maxAnzahlClients;x++)
    	{
    		clients[x] = INVALID_SOCKET;
    	}
    	u_long port = (u_long)atol(portStr);
    	serverAddr.sin_addr.s_addr = inet_addr(ipStr);
    	serverAddr.sin_port = htons(port);
    	serverAddr.sin_family = AF_INET;
    	cli_size = sizeof(cli);
    	aktuellerIndex = 0;
    }
    RequestResponseServer::~RequestResponseServer()
    {
    	for(unsigned int x=0;x<maxAnzahlClients;x++)
    	{
    		if(clients[x] == INVALID_SOCKET)
    		{
    			closesocket(clients[x]);
    		}
    	}
    	delete[] clients;
    }
    void RequestResponseServer::wähleNächstenClient()
    {
    	for(unsigned int x=0;x<maxAnzahlClients;x++)
    	{
    		aktuellerIndex = (aktuellerIndex+1)%maxAnzahlClients;
    		if(clients[aktuellerIndex] != INVALID_SOCKET)
    		{
    			break;
    		}
    	}
    }
    bool RequestResponseServer::empfangsbereit(SOCKET client)
    {
    	if(client == INVALID_SOCKET)
    	{
    		return false;
    	}
    	fd_set kandidaten;
    	FD_ZERO(&kandidaten);
    	FD_SET(client,&kandidaten);
    	kandidaten.fd_count = 1;
    	struct timeval warteZeit;
    	warteZeit.tv_usec = 1;
    	warteZeit.tv_sec = 1;
    
    	int rc = select(0,&kandidaten,NULL,NULL,&warteZeit);
    	if(rc==SOCKET_ERROR)
    	{
    		printf("rc==SOCKET_ERROR\n");
    		printf("WSAGetLastError:%d\n",WSAGetLastError());
    		return INVALID_SOCKET;
    	}
    	if(FD_ISSET(client,&kandidaten))
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    bool RequestResponseServer::sendeResponse(ResponsePuffer res)
    {
    	printf("Sende Response\n");
    	res[sizeof(ResponsePuffer)-1] = 0;
    	unsigned int bytes = 0;
    	while(bytes < sizeof(ResponsePuffer))
    	{
    		int temp = send(clients[aktuellerIndex], &res[bytes],sizeof(ResponsePuffer), 0);
    		if (temp == -1)
    		{
    			printf("send(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(clients[aktuellerIndex]);
    			clients[aktuellerIndex] = INVALID_SOCKET;
    			return false;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    	printf("Response gesendet: %d Bytes\n",bytes);
    	return true;
    }
    const RequestPuffer* RequestResponseServer::empfangeRequest()
    {
    	wähleNächstenClient();
    	if(empfangsbereit(clients[aktuellerIndex]))
    	{
    		printf("Empfange Request\n");
    		unsigned int bytes = 0;
    		while(bytes<sizeof(RequestPuffer))
    		{
    			int temp = recv(clients[aktuellerIndex],&req[bytes],sizeof(RequestPuffer)-bytes, 0);
    			if (temp == -1)
    			{
    				printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    				closesocket(clients[aktuellerIndex]);
    				clients[aktuellerIndex] = INVALID_SOCKET;
    				return false;
    			}
    			else
    			{
    				bytes += temp;
    			}
    		}
    		printf("Request empfangen: %d Bytes\n",bytes);
    		return &req;
    	}
    	else
    	{
    		return NULL;
    	}
    }
    unsigned int RequestResponseServer::starte() 
    {
    	WSADATA	wsa;
    	if (WSAStartup(MAKEWORD(2.2, 2.2), &wsa))
    	{
    		printf("WSAStartup() failed, %d\n", WSAGetLastError());
    		system("pause");
    		return 1;
    	}
    	server = socket(serverAddr.sin_family, SOCK_STREAM, IPPROTO_TCP);
    	if (server == INVALID_SOCKET)
    	{
    		printf("socket() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 2;
    	}
    
    	if (bind(server, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
    	{
    		printf("bind() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 3;
    	}
    
    	if (listen(server, 3) == -1)
    	{
    		printf("listen () failed, %d\n",WSAGetLastError());
    		system("pause");
    		return 4;
    	}
    	printf("Server gestartet.\n");
    	return 0;
    }
    bool RequestResponseServer::verbindungAnnehmen()
    {
    	unsigned int index = maxAnzahlClients;
    	for(unsigned int x=0;x<maxAnzahlClients;x++)
    	{
    		if(clients[x] == INVALID_SOCKET)
    		{
    			index = x;
    			break;
    		}
    	}
    	if(index < maxAnzahlClients)
    	{
    		fd_set serverFD;
    		FD_ZERO(&serverFD);
    		FD_SET(server,&serverFD);
    		struct timeval warteZeit;
    		warteZeit.tv_usec = 1000;
    		//printf("F%chre select() aus.\n",129);
    		int rc = select(0,&serverFD,NULL,NULL,&warteZeit);
    		//printf("select() ausgef%chrt.\n",129);
    		if(rc==SOCKET_ERROR)
    		{
    			printf("rc==SOCKET_ERROR\n");
    			printf("WSAGetLastError:%d\n",WSAGetLastError());
    			return false;
    		}
    		else
    		{
    			if(FD_ISSET(server,&serverFD))
    			{
    				clients[index] = accept(server, (sockaddr*)&cli, &cli_size);
    			}
    		}
    	}
    	else
    	{
    		return false;
    	}
    }
    
    int main()
    {
    	RequestResponseServer* server = new RequestResponseServer(10);
    	server->starte();
    	printf("Taste dr%ccken um fortzufahren. ESC = Beenden\n",129);
    	int ch = getch();
    	while(ch!=VK_ESCAPE)
    	{
    		if(server->verbindungAnnehmen())
    		{
    			printf("Verbindung angenommen.\n");
    		}
    		else
    		{
    			printf("Keine Verbindung angenommen.\n");
    		}		
    		const RequestPuffer* req = server->empfangeRequest();
    		if(req)
    		{
    			printf("%s\n",*req);
    		}
    		printf("Taste dr%ccken um fortzufahren. ESC = Beenden\n",129);
    		ch = getch();
    	}
    	system("pause");
    	return 0;
    }
    

    Client

    #include "stdafx.h"
    #include <Windows.h>
    #include <conio.h>
    
    typedef char RequestPuffer[6720];
    typedef char ResponsePuffer[10224];
    
    const char* ipStr = "192.168.0.60";
    const char* portStr = "17706";
    
    struct RequestResponseVerwaltung
    {
    	RequestPuffer req;
    	ResponsePuffer res;
    
    	SOCKET server;
    	ClientArray clients;
    
    	bool running;
    	bool getDaten;
    };
    
    void RequestThread(LPVOID p)
    {
    	RequestResponseVerwaltung* verwaltung = (RequestResponseVerwaltung*)p;
    	WSADATA wsa;
    	if (WSAStartup(MAKEWORD(2.2, 2.2), &wsa))
    	{
    		char* str = new char[1024];
    		printf("WSAStartup() failed, %d\n", (unsigned long)WSAGetLastError());
    	}	
    	struct sockaddr_in addr;
    	u_long port = (u_long)atol(portStr);
    	addr.sin_addr.s_addr = inet_addr(ipStr);
    	addr.sin_port = htons(port);
    	addr.sin_family = AF_INET;
    
    	printf("Versuche Verbindung zum Server herzustellen...\n");
    	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	connect(clientSocket, (sockaddr*)&(addr), sizeof(addr));
    	printf("Verbindung zum Server hergestellt.\n");
    	unsigned int bytes = 0;
    	unsigned int temp;
    
    	strcpy(verwaltung->req,"<Request/>");
    
    	while(verwaltung->running)
    	{
    		while(!verwaltung->getDaten)
    		{
    			Sleep(10);
    		}
    		bytes = 0;
    		printf("Sende Request.\n");
    		while(bytes < sizeof(RequestPuffer))
    		{
    			temp = send(clientSocket, &verwaltung->req[bytes],sizeof(RequestPuffer)-bytes, 0);
    			if (temp == -1)
    			{
    				printf("send(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    				closesocket(clientSocket);
    				clientSocket = INVALID_SOCKET;
    				verwaltung->running = false;
    				break;
    			}
    			else
    			{
    				bytes += temp;
    			}
    		}
    		printf("Request gesendet.\n");
    		bytes = 0;
    		while(bytes<sizeof(ResponsePuffer))
    		{
    			temp = recv(clientSocket, &verwaltung->res[bytes],sizeof(ResponsePuffer)-bytes, 0);
    
    			if (temp == -1)
    			{
    				printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    				closesocket(clientSocket);
    				clientSocket = INVALID_SOCKET;
    				verwaltung->running = false;
    				break;
    			}
    			else
    			{
    				bytes += temp;
    			}
    		}
    		printf("Response empfangen.\n");
    		verwaltung->getDaten = false;
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	struct RequestResponseVerwaltung verwaltung;
    	verwaltung.running = true;
    
    	CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RequestThread,&verwaltung,0,NULL);
    
    	while(verwaltung.running)
    	{
    		printf("Taste dr%ccken um fortzufahren. ESC = Beenden\n",129);
    		int key = getch();
    		if(key == VK_ESCAPE)
    		{
    			verwaltung.running = false;
    		}
    		else
    		{
    			verwaltung.getDaten = true;
    		}
    	}
    
    	return 0;
    }
    


  • Also ich bin mir jetzt ziemlich sicher, dass es so ist:

    Solange sich noch kein Client verbunden hat, kann ich mit select() den Server-Socket überprüfen, ob ein neuer Client verbinden will

    Wenn ich aber einmal eine Verbindung zu einem Client angenommen habe und dann nochmal mittels select() überprüfen will, ob ein sich ein weiterer Client verbinden will, dann blockiert select().

    Weiß jemand was darüber?
    Soll das so sein / Ist das so gewollt?
    Stimmt meine Vermutung überhaupt?

    MFG



  • lies mal ein tut. zu select. denn ich glaube nicht das dieses gfrickel sich jemand antun wird!



  • Sorry, ich hab jetzt schon 3 Tutorials durch. Ich würde nicht hier im Forum fragen wenn ich selber nicht mehr weiterkommen würde und noch nicht tagelang im Internet gesucht hätte!

    Aktueller Stand ist übrigens dass es in VC++2008 genauso wenig funktioniert wie in VC++ 2010.

    Und das folgende "Gefrickel" funktioniert. Allerdings muss ich vor und nach dem select() ein Leerzeichen per printf() ausgeben. Wenn ich das nicht mache, blockiert select(). (Zeilen 226-228 im Server)

    Von so einem Sonderfall steht in keinem meiner Tutorials etwas.

    Den Code für den folgenden Server und Client zu testen ist kaum Aufwand. Einfach kopieren, 'WS2_32.Lib' bei 'Additional Dependencies' im Linker hinzufügen und kompilieren.

    Server starten, dann Client starten.

    Und dann mal 'printf(" ");' auskommentieren beim Server in den Zeilen 226 und 228 und nochmal versuchen.

    Ich wäre wirklich sehr dankbar!!!

    Server

    #include <stdio.h>
    #include <tchar.h>
    #include <WinSock2.h>
    #include <conio.h>
    
    typedef char RequestPuffer[6720];
    typedef char ResponsePuffer[10224];
    char* ipStr = "127.0.0.1";
    char* portStr = "17700";
    
    class RequestResponseServer
    {
    	public:
    		RequestResponseServer(unsigned int maxAnzahlClients);
    		~RequestResponseServer();
    		void sendeResponse(SOCKET client, ResponsePuffer res);
    		void empfangeRequest(SOCKET client,RequestPuffer req);
    		void start();
    		SOCKET wähleNächstenVerfügbarenClient();
    
    		struct sockaddr_in serverAddr;
    		struct sockaddr_in cli;
    		int cli_size;
    		SOCKET serverSocket;
    		SOCKET* clients;
    		unsigned int aktuellerClientIndex;
    		unsigned int maxAnzahlClients;
    		HANDLE mutex;
    };
    
    RequestResponseServer::RequestResponseServer(unsigned int maxAnzahlClients)
    {
    	mutex = CreateMutex(0,0,0);
    	aktuellerClientIndex = 0;
    	this->maxAnzahlClients = maxAnzahlClients;
    	clients = new SOCKET[maxAnzahlClients];
    	for(unsigned int x=0;x<maxAnzahlClients;x++)
    	{
    		clients[x] = INVALID_SOCKET;
    	}
    
    	u_long port = (u_long)atol(portStr);
    	serverAddr.sin_addr.s_addr = inet_addr(ipStr);
    	serverAddr.sin_port = htons(port);
    	serverAddr.sin_family = AF_INET;
    	cli_size = sizeof(cli);
    	WSADATA	wsa;
    	if (WSAStartup(MAKEWORD(2.2, 2.2), &wsa))
    	{
    		printf("WSAStartup() failed, %d\n", WSAGetLastError());
    		system("pause");
    		return;
    	}
    	serverSocket = socket(serverAddr.sin_family, SOCK_STREAM, IPPROTO_TCP);
    	if (serverSocket == INVALID_SOCKET)
    	{
    		printf("socket() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return;
    	}
    	if (bind(serverSocket, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
    	{
    		printf("bind() failed, %d\n",WSAGetLastError());
    		system("pause");
    		return;
    	}
    
    	if (listen(serverSocket, 3) == -1)
    	{
    		printf("listen () failed, %d\n",WSAGetLastError());
    		system("pause");
    		return;
    	}
    	printf("Server gestartet.\n");
    	return;
    }
    RequestResponseServer::~RequestResponseServer()
    {
    	for(unsigned int x=0;x<maxAnzahlClients;x++)
    	{
    		closesocket(clients[x]);
    	}
    	delete[] clients;
    }
    void RequestResponseServer::sendeResponse(SOCKET client, ResponsePuffer res)
    {
    	res[sizeof(ResponsePuffer)-1] = 0;
    	unsigned int bytes = 0;
    	while(bytes < sizeof(ResponsePuffer))
    	{
    		int temp = send(client, &res[bytes],sizeof(ResponsePuffer), 0);
    		if (temp == -1)
    		{
    			printf("send(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(client);
    			client = INVALID_SOCKET;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    }
    void RequestResponseServer::empfangeRequest(SOCKET client,RequestPuffer req)
    {
    	unsigned int bytes = 0;
    	while(bytes<sizeof(RequestPuffer))
    	{
    		int temp = recv(client,&req[bytes],sizeof(RequestPuffer)-bytes, 0);
    		if (temp == -1)
    		{
    			printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    			closesocket(client);
    			client = INVALID_SOCKET;
    		}
    		else
    		{
    			bytes += temp;
    		}
    	}
    }
    
    static void VerbindenThread(LPVOID p)
    {
    	RequestResponseServer* server = (RequestResponseServer*)p;
    
    	while(true)
    	{
    		unsigned int freierSlot = server->maxAnzahlClients;
    		for(unsigned int x=0;x<server->maxAnzahlClients;x++)
    		{
    			if(server->clients[x] == INVALID_SOCKET)
    			{
    				freierSlot = x;
    				break;
    			}
    		}
    		if(freierSlot == server->maxAnzahlClients)
    		{
    			continue;
    		}
    
    		SOCKET client;
    		fd_set serverFD;
    		FD_ZERO(&serverFD);
    		FD_SET(server->serverSocket,&serverFD);
    		serverFD.fd_count = 1;
    		struct timeval warteZeitAccept;
    		warteZeitAccept.tv_usec = 1;
    		int rcServer = select(0,&serverFD,NULL,NULL,&warteZeitAccept);
    		if(rcServer==SOCKET_ERROR)
    		{
    			printf("rc==SOCKET_ERROR\n");
    			printf("WSAGetLastError:%d\n",WSAGetLastError());
    			continue;
    		}
    		if(FD_ISSET(server->serverSocket,&serverFD))
    		{
    			WaitForSingleObject(server->mutex,INFINITE);
    			server->clients[freierSlot] = accept(server->serverSocket, (sockaddr*)&server->cli, &server->cli_size);
    			printf("\nNeue Verbindung aufgenommen. Client-Socket: %d\n",server->clients[freierSlot]);
    			ReleaseMutex(server->mutex);
    		}
    		else
    		{
    			continue;
    		}
    	}
    }
    
    SOCKET RequestResponseServer::wähleNächstenVerfügbarenClient()
    {
    	SOCKET ret = INVALID_SOCKET;
    	unsigned int tempIndex = (aktuellerClientIndex+1)%maxAnzahlClients;
    	WaitForSingleObject(mutex,INFINITE);
    	while(tempIndex >= aktuellerClientIndex+1)
    	{
    		if(clients[tempIndex] != INVALID_SOCKET)
    		{
    			aktuellerClientIndex = tempIndex;
    			ret = clients[tempIndex];
    			break;
    		}
    		tempIndex = (tempIndex+1)%maxAnzahlClients;
    	}
    	while(tempIndex < aktuellerClientIndex+1)
    	{
    		if(clients[tempIndex] != INVALID_SOCKET)
    		{
    			aktuellerClientIndex = tempIndex;
    			ret = clients[tempIndex];
    			break;
    		}
    		tempIndex++;
    	}
    	ReleaseMutex(mutex);
    	return ret;
    }
    void RequestResponseServer::start()
    {
    	SOCKET client = INVALID_SOCKET;
    	while(true)
    	{
    		client = wähleNächstenVerfügbarenClient();
    		if(client == INVALID_SOCKET)
    		{
    			continue;
    		}
    		fd_set clientsFD;
    		FD_ZERO(&clientsFD);
    		FD_SET(client,&clientsFD);
    		clientsFD.fd_count = 1;
    		struct timeval warteZeitReceive;
    		warteZeitReceive.tv_usec = 1;
    
    		printf(" ");
    		int rcClient = select(0,&clientsFD,NULL,NULL,&warteZeitReceive);
    		printf(" ");
    		if(rcClient==SOCKET_ERROR)
    		{
    			printf("rc==SOCKET_ERROR\n");
    			printf("WSAGetLastError:%d\n",WSAGetLastError());
    			break;
    		}
    		if(FD_ISSET(client,&clientsFD))
    		{
    			RequestPuffer req;
    			empfangeRequest(client,req);
    			printf("%s\n",req);
    
    			ResponsePuffer res;
    			sprintf(res,"Hallo Welt\n");
    			sendeResponse(client,res);
    
    		}
    		else
    		{
    			continue;
    		}
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	RequestResponseServer* server = new RequestResponseServer(10);
    	CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)VerbindenThread,server,0,NULL);
    	server->start();
    	system("pause");
    }
    

    Client:

    #include <stdio.h>
    #include <tchar.h>
    #include <WinSock2.h>
    #include <conio.h>
    
    typedef char RequestPuffer[6720];
    typedef char ResponsePuffer[10224];
    typedef SOCKET ClientArray[10];
    
    const char* ipStr = "127.0.0.1";
    const char* portStr = "17700";
    
    struct RequestResponseVerwaltung
    {
    	RequestPuffer req;
    	ResponsePuffer res;
    
    	SOCKET server;
    	ClientArray clients;
    
    	bool running;
    	bool getDaten;
    };
    
    void RequestThread(LPVOID p)
    {
    	RequestResponseVerwaltung* verwaltung = (RequestResponseVerwaltung*)p;
    	WSADATA wsa;
    	if (WSAStartup(MAKEWORD(2.2, 2.2), &wsa))
    	{
    		char* str = new char[1024];
    		printf("WSAStartup() failed, %d\n", (unsigned long)WSAGetLastError());
    	}	
    	struct sockaddr_in addr;
    	u_long port = (u_long)atol(portStr);
    	addr.sin_addr.s_addr = inet_addr(ipStr);
    	addr.sin_port = htons(port);
    	addr.sin_family = AF_INET;
    
    	printf("Versuche Verbindung zum Server herzustellen...\n");
    	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	connect(clientSocket, (sockaddr*)&(addr), sizeof(addr));
    	printf("Verbindung zum Server hergestellt.\n");
    	unsigned int bytes = 0;
    	unsigned int temp;
    
    	strcpy(verwaltung->req,"<Request/>");
    
    	while(verwaltung->running)
    	{
    		while(!verwaltung->getDaten)
    		{
    			Sleep(10);
    		}
    		bytes = 0;
    		printf("Sende Request.\n");
    		while(bytes < sizeof(RequestPuffer))
    		{
    			temp = send(clientSocket, &verwaltung->req[bytes],sizeof(RequestPuffer)-bytes, 0);
    			if (temp == -1)
    			{
    				printf("send(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    				closesocket(clientSocket);
    				clientSocket = INVALID_SOCKET;
    				verwaltung->running = false;
    				break;
    			}
    			else
    			{
    				bytes += temp;
    			}
    		}
    		printf("Request gesendet.\n");
    		bytes = 0;
    		while(bytes<sizeof(ResponsePuffer))
    		{
    			temp = recv(clientSocket, &verwaltung->res[bytes],sizeof(ResponsePuffer)-bytes, 0);
    
    			if (temp == -1)
    			{
    				printf("recv(): Verbindung zum Server unterbrochen. Grund: %d\n",WSAGetLastError());
    				closesocket(clientSocket);
    				clientSocket = INVALID_SOCKET;
    				verwaltung->running = false;
    				break;
    			}
    			else
    			{
    				bytes += temp;
    			}
    		}
    		printf("Response empfangen.\n");
    		printf("%s\n",verwaltung->res);
    		verwaltung->getDaten = false;	printf("verbindungAnnehmen() 2\n");
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	struct RequestResponseVerwaltung verwaltung;
    	verwaltung.running = true;
    
    	CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RequestThread,&verwaltung,0,NULL);
    
    	while(verwaltung.running)
    	{
    		printf("Taste dr%ccken um fortzufahren. ESC = Beenden\n",129);
    		int key = getch();
    		if(key == VK_ESCAPE)
    		{
    			verwaltung.running = false;
    		}
    		else
    		{
    			verwaltung.getDaten = true;
    		}
    	}
    
    	return 0;
    }
    


  • Vergewisser Dich mal, dass in warteZeitReceive.tv_sec auch wirklich 0 steht, bzw. initialisiere das mit 0.



  • Autsch! Das tat weh!
    Solch ein dummer Fehler von mir!

    Vielen Dank, Belli. Das war die Lösung!

    Vielen vielen Dank!!!



  • Gerne!


Anmelden zum Antworten