Frage zu Socket-Programmierung und select()



  • Ich bekomme diese Fehlermeldung:

    Unbehandelte Ausnahme bei 0x1029984f (msvcr90d.dll) in RN_Server.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00002745.
    


  • Dann lass mal den Debugger warm laufen und guck, an welcher Stelle es hackt.



  • Hab ich schon. Guck mal oben im Code, hab da einen Kommentar drin. An der Stelle wo n -1 wird bricht das Programm ab und der Fehler kommt



  • Den Grund (ich nehme mal an, dass das der Grund ist) dafür habe ich dir bereits in meinem ersten Post genannt. Oder hast du das schon ausprobiert?



  • Ja, ich hab das FD_ZERO schon getestet. Der Fehler bleibt leider der gleiche



  • Dann bau mal ein printf ("%s %d\n", strerror (errno), errno); mit vorherigem #include <errno.h> ein und schau nach, was der Fehler bedeutet bedeutet. (Oder wird das unter Windows mit WSAGetLastError (); gemacht?)



  • printf ("%s %d\n", strerror (errno), WSAGetLastError());
    

    Da gibt er folgendes aus:

    No Error 10038
    


  • http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx schrieb:

    WSAENOTSOCK
    10038

    Socket operation on nonsocket.
    An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.

    Dann hat der Client irgendwie die Verbindung abgebrochen oder der Socket ist im Server put gegangen. Kann jetzt auf den ersten Blick den Grund auch nicht erkennen...



  • Ja genau. Hilft es vl wenn ich den Code vom Client auch noch poste?

    // RN_P_Beispielclient.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    #include "stdafx.h"
    #include <winsock.h>
    #include <iostream>
    #include <conio.h>
    #include <io.h>
    
    #define PROTOPORT		5000		// Default Portnummer
    #define AF_INET_LEN		4			// Länge IPv4-Adresse in Byte
    
    using namespace std;
    
    int main(int argc, char* argv[])
    {
    //--------------------------------------------------------------------------------------
    // Program:   RN_P_Beispielclient.cpp
    //
    // Funktion:  Baut eine TCP-Verbindung zu einem Server auf, gibt dessen Nachricht
    //			  auf dem Bildschirm aus und bestätigt die Verbindung.
    //
    // Aufruf:    RN_P_Beispielclient [<Rechnername>][<Portnummer>]
    //            <Rechnername>: Rechnername des Servers
    //            <Portnummer>: Portnummer unter welcher der Server seinen 
    //							Dienst anbietet		
    //
    // Bemerkung: Die Eingabe der Parameter ist optional. Falls kein Rechnername
    //            spezifiziert ist, verwendet der Client "localhost" (127.0.0.1);
    //			  falls kein Port spezifiziert ist, wird der durch PROTOPORT definierte
    //            Default-Wert verwendet!
    //
    // Dr. W. Schmitt, 02.05.08
    //--------------------------------------------------------------------------------------
    	const char *Datum = "02.05.08";
    	int				Fehlerkode;			// Hilfsvariable zum Speichern eines Fehlerkodes
    	char localhost[] = "localhost";		// Default Hostname 
        hostent			*ptrh;				// Speichert den Namen des Clientrechners
        protoent		*ptrp;				// Speichert den Namen des Transp.Protok.
        sockaddr_in		serveradress;				// Speichert die Serveradresse
        SOCKET			sock;					// Socket Descriptor
    	unsigned short	port;				// Portnummer des Servers
        char			*host;				// Host Name static_cast<void*>
        unsigned int	n;					// Anzahl empfangener Bytes
        char			RecvBuf[100];		// Puffer für Empfangsdaten
        char			SendBuf[100];		// Puffer für Sendedaten
    	char *SendeText = "TCP-Verbindungsaufbau erfolgreich! \n";
    	WSADATA			wsaData;			// Speichert Winsock-Initialisierungsinfo
        WORD wVersionRequested;				// Speichert die gewünschte Version der Winsock-
    										// DLL
    	wVersionRequested = MAKEWORD(2, 2);
    // Initialisierung der Winsock-DLL	
    	Fehlerkode = WSAStartup(wVersionRequested, &wsaData);
    	if (Fehlerkode != NO_ERROR)
    	{
    		fprintf_s(stdout,"Initialisierung der Winsock-DLL fehlgeschlagen: %i\n",
    					Fehlerkode);
    	}
    
    //  Bildschirmausgabe einer Begrüßungsnachricht        
    	fprintf_s(stdout, "Hallo Client!\n");
    
        memset(&serveradress, 0, sizeof(serveradress));       // Initialisiere sad mit 0
        serveradress.sin_family = AF_INET;           // Setze "Internetadressierung"
    
    // Auswerten der Kommandozeilenparameter      
    	if (argc > 1) 
    	{						
    		// Falls <Rechnername> vorhanden
    		// dann in host speichern
    		host = argv[1];
    	}				
    	else 
    	{
    		// sonst verwende "localhost"
    		host = localhost;
    	}				
    
    	ptrh = gethostbyname(host);	        // <Rechnername> --> IP-Adresse
    
    	if (ptrh == NULL) 
    	{
            fprintf_s(stdout,"ungültige Rechneradresse: %s\n", host);
    		WSACleanup();
    		exit(EXIT_FAILURE);
    	}
    
        if (argc > 2) 
    	{                     
    		// Falls <Portnummer> vorhanden
    		// dann konvertiere nach int
    		port = atoi(argv[2]);
    	}			
        else
    	{
    		// sonst verwende Default-Wert 
    		port = PROTOPORT;
    	}				   
    
        if (port > 0)            
    		serveradress.sin_port = htons(port);		// Host --> Netzwerk-Byteordnung
    	else 
    	{								// Drucke Fehlermeldung; Programmende
    		fprintf_s(stdout,"Ungültige Portnummer %s\n",argv[2]);
    		WSACleanup();
    		exit(EXIT_FAILURE);
    	}
    
    	if (memcpy_s(&serveradress.sin_addr, AF_INET_LEN, ptrh->h_addr, ptrh->h_length))
    	{
    		fprintf_s(stdout,"Fehler beim Kopieren der Rechneradresse");
    		WSACleanup();
    		exit(EXIT_FAILURE);
    	}
    
        if ((ptrp = getprotobyname("tcp")) == NULL) 
    	{ // "tcp" --> Protokollcode
            fprintf_s(stdout, "Abbildung von \"tcp\" auf Protokollnummer nicht möglich!");
    		WSACleanup();
    		exit(EXIT_FAILURE);
    	}
    
    	// Erzeuge Socket
    	sock = socket(PF_INET, SOCK_STREAM, ptrp->p_proto); 
        if (sock == INVALID_SOCKET) {
    		fprintf_s(stdout, "Fehler bei Generierung von Socket: %ld\n", WSAGetLastError());
    		WSACleanup();
    		exit(EXIT_FAILURE);
    	}
    
    	// Aktiver Verbindungsaufbau zum Server
    	if (connect(sock, (struct sockaddr *)&serveradress, sizeof(serveradress)) == SOCKET_ERROR)
    	{
    		fprintf_s(stdout,"Fehler beim TCP-Verbindungsaufbau: %ld\n", WSAGetLastError());
    		WSACleanup();
    		exit(EXIT_FAILURE);
    	}
    
    	//solange du verbunden bist
    	while(connect)
    	{
    		fprintf(stdout, "Bitte Nachricht eingeben:\n");
    		//Lese Text von der Konsole ein und schreibe in SendBuf
    		cin.getline(SendBuf, 1000);
    		send(sock, SendBuf,strlen(SendBuf),0);
    
    		// Empfangene Daten lesen und auf dem Bildschirm schreiben
    		// Daten aus TCP-Empfangspuffer lesen und in RecvBuf schreiben    
    		n = recv(sock, RecvBuf, static_cast<int>(strlen(RecvBuf)), 0); 
    		RecvBuf[n] = '\0';					// String mit '\0' abschließen
    		if (fprintf_s(stdout, RecvBuf, n) < 0)
    		{
    			fprintf_s(stdout, "Schreib-/Lesefehler!\n");
    		}
    		//Falls senden fehlgeschlagen ist: Fehlermeldung und beenden mit Tastendruck
    		if (send(sock, SendBuf, static_cast<int>(strlen(SendBuf)), 0) <0)
    		{
    			fprintf_s( stdout, "Fehler beim Senden!\n" );
    			fprintf_s( stdout, "Zum beenden bitte Taste druecken" );
    			closesocket( sock );
    			WSACleanup();
    			while( !_kbhit() );
    				exit( EXIT_SUCCESS );
    		}
    		// Socket schließen und von der Winsock-DLL reservierten Ressourcen freigeben 
    		closesocket(sock);
    		WSACleanup();
    	}//Hauptschleife
    } // main
    


  • Ähm ja... Deine Schleifen-Konditionsvariable heißt connect, was in diesem Fall keine Variable sondern eine Funktion ist, auf die der Zeiger immer ungleich 0 ist, was bedeutet, dass die Schleife für immer läuft.
    Am Ende der Schleife schließt Du den Socket und räumst WSA auf, wobei du beim nächsten Schleifendurchlauf wieder mit Socket-Funktionen arbeitest?!
    cin.getline (); gibst du als Buffer-Größen-Parameter 1000 mit, obwohl der Buffer nur 100 Bytes groß ist. Außerdem verwendest du zwei Mal send (); , wobei du nur beim zweiten Mal prüfst, ob ein Fehler aufgetreten ist...

    Mein Tipp: Schmeiß den Code weg und fang noch mal ordentlich an. Ein gutes Tutorial findest du hier.



  • Ah ok. Die Differenz 100 zu 1000 war nur Testweise, habs vergessen zu ändern.
    Ansonsten Danke für den Tipp. Werd das dann morgen mal in Angriff nehmen.
    Falls es nicht klappt, meld ich mich hier wieder

    Schönen Abend noch



  • Vielleicht solltest du den Code selbst paar mal durchgehen bis es klingelt, bevor du hier postest...


Anmelden zum Antworten