[c]Speicherzugriffsfehler



  • Hallo,

    ich will, dass ein Client den Server nach den Dateien im Verzeichnis fragt und danach der Server den Client die Dateien im Verzeichnis schickt und sie auf Clientseite aufgelistet werden.

    Dies habe ich so realisiert (unter Voraussetzung, dass die beiden schon kommunizieren) - server rennt immer:
    Nun die Fehler:
    der server macht dann folgendes, sobald der befehl gesendet wurde:

    6 Dateien im Verzeichnis: /home/steps/Desktop/HTS/ref
    Speicherzugriffsfehler

    auf dem Clienten passiert folgendes:
    [quote]...HTS1_CUebung.pdflaleiwaund.ccemyfirsttime.mpeg
    [/qoute]

    meine 2 fehler die ich nicht finde, bzw nicht schaffe es anders zu machen aber gerne anders hätte:

    1. dass sich der server nicht aufhängt (also den Speicherzugriffsfehler finden) (anm. wir arbeiten ohne ide bzw sind dazu gezwungen)

    2. wie kann ich dem Server beibringen dass er jede einzelne Datei quasi mit \n schickt, also dass es nicht in einer Schnur geschrieben wird.

    ich hoffe mir kann wer helfen, ich bin schon am verzweifeln! 😡



  • manuzi1 schrieb:

    1. dass sich der server nicht aufhängt (also den Speicherzugriffsfehler finden) (anm. wir arbeiten ohne ide bzw sind dazu gezwungen)

    Wer zwingt dich dazu? Auf deinem eigenem Computer solltest du die Software nutzen können, die dir gefällt.

    $ valgrind --leak-check=yes ./programname argumente
    

    Das Programm wird vorher mit Debugsymbolen -g und ohne Optimierung -O0 compiliert.

    manuzi1 schrieb:

    2. wie kann ich dem Server beibringen dass er jede einzelne Datei quasi mit \n schickt, also dass es nicht in einer Schnur geschrieben wird.

    Die Idee mit dem Newline anhängen war schon ganz gut, nur musst du dafür einen extra Speicher bereit stellen. Also zuerst den Namen dort hin kopieren und dann Newline anhängen. Den erstellen Buffer sendest du dann.



  • Paul Müller schrieb:

    manuzi1 schrieb:

    1. dass sich der server nicht aufhängt (also den Speicherzugriffsfehler finden) (anm. wir arbeiten ohne ide bzw sind dazu gezwungen)

    Wer zwingt dich dazu? Auf deinem eigenem Computer solltest du die Software nutzen können, die dir gefällt.

    $ valgrind --leak-check=yes ./programname argumente
    

    Das Programm wird vorher mit Debugsymbolen -g und ohne Optimierung -O0 compiliert.

    Der Server soll ja endlos laufen. Und wenn die Speicherzugriffsfehler eintritt (wie eben immer) dann stürzt der Server ab und ich bin wieder in der standard Shell im Verzeichnis 😉

    Ich hab mir das Programm jetzt mal installiert und es spuckt halt auch was aus. Wenn ich es mit

    $ valgrind --leak-check=yes ./programname argumente
    

    mache, fällt auf, dass auf der Client-Seite nur mehr die erste Datei also der .
    ausgegeben wird.

    hier mal das was er ausgespuckt hat:

    valgrind --leak-check=yes ./server 6543 ref
    ==17658== Memcheck, a memory error detector
    ==17658== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
    ==17658== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
    ==17658== Command: ./server 53511 ref
    ==17658== 
    Verzechnis schon vorhanden
    Waiting for connections...
    Client connected from 127.0.0.1:53511...
    Message received: LIST
    
    6 Dateien im Verzeichnis: /home/steps/Desktop/HTS/ref
    ==17658== Conditional jump or move depends on uninitialised value(s)
    ==17658==    at 0x4078296: vfprintf (vfprintf.c:1292)
    ==17658==    by 0x409A4DB: vsprintf (iovsprintf.c:43)
    ==17658==    by 0x4082B4A: sprintf (sprintf.c:34)
    ==17658==    by 0x8048D99: main (in /home/me/Desktop/server)
    ==17658== 
    ==17658== Use of uninitialised value of size 4
    ==17658==    at 0x4027FC5: strchrnul (mc_replace_strmem.c:711)
    ==17658==    by 0x40782CC: vfprintf (printf-parse.h:99)
    ==17658==    by 0x409A4DB: vsprintf (iovsprintf.c:43)
    ==17658==    by 0x4082B4A: sprintf (sprintf.c:34)
    ==17658==    by 0x8048D99: main (in /home/me/Desktop/server)
    ==17658== 
    ==17658== Invalid read of size 1
    ==17658==    at 0x4027FC5: strchrnul (mc_replace_strmem.c:711)
    ==17658==    by 0x40782CC: vfprintf (printf-parse.h:99)
    ==17658==    by 0x409A4DB: vsprintf (iovsprintf.c:43)
    ==17658==    by 0x4082B4A: sprintf (sprintf.c:34)
    ==17658==    by 0x8048D99: main (in /home/me/Desktop/server)
    ==17658==  Address 0xb is not stack'd, malloc'd or (recently) free'd
    ==17658== 
    ==17658== 
    ==17658== Process terminating with default action of signal 11 (SIGSEGV)
    ==17658==  Access not within mapped region at address 0xB
    ==17658==    at 0x4027FC5: strchrnul (mc_replace_strmem.c:711)
    ==17658==    by 0x40782CC: vfprintf (printf-parse.h:99)
    ==17658==    by 0x409A4DB: vsprintf (iovsprintf.c:43)
    ==17658==    by 0x4082B4A: sprintf (sprintf.c:34)
    ==17658==    by 0x8048D99: main (in /home/me/Desktop/server)
    ==17658==  If you believe this happened as a result of a stack
    ==17658==  overflow in your program's main thread (unlikely but
    ==17658==  possible), you can try to increase the size of the
    ==17658==  main thread stack using the --main-stacksize= flag.
    ==17658==  The main thread stack size used in this run was 8388608.
    ==17658== 
    ==17658== HEAP SUMMARY:
    ==17658==     in use at exit: 40 bytes in 1 blocks
    ==17658==   total heap usage: 8 allocs, 7 frees, 32,960 bytes allocated
    ==17658== 
    ==17658== LEAK SUMMARY:
    ==17658==    definitely lost: 0 bytes in 0 blocks
    ==17658==    indirectly lost: 0 bytes in 0 blocks
    ==17658==      possibly lost: 0 bytes in 0 blocks
    ==17658==    still reachable: 40 bytes in 1 blocks
    ==17658==         suppressed: 0 bytes in 0 blocks
    ==17658== Reachable blocks (those to which a pointer was found) are not shown.
    ==17658== To see them, rerun with: --leak-check=full --show-reachable=yes
    ==17658== 
    ==17658== For counts of detected and suppressed errors, rerun with: -v
    ==17658== Use --track-origins=yes to see where uninitialised values come from
    ==17658== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 11 from 6)
    Speicherzugriffsfehler
    

    manuzi1 schrieb:

    2. wie kann ich dem Server beibringen dass er jede einzelne Datei quasi mit \n schickt, also dass es nicht in einer Schnur geschrieben wird.

    Die Idee mit dem Newline anhängen war schon ganz gut, nur musst du dafür einen extra Speicher bereit stellen. Also zuerst den Namen dort hin kopieren und dann Newline anhängen. Den erstellen Buffer sendest du dann.

    So ganz kann ich dir da nicht folgen. Meinst du, den ersten Dateinamen nehmen und dann \n anfügen mittels

    buffer_new = strcat(buffer,"\n");
    

    ?

    Danke, dass du dir schon die Zeit genommen hast zum Antworten 😉
    Lg

    EDIT:: Sehr schön, dass mit dem Newline habe ich jetzt geschafft:

    sprintf(buffer,(*list)->d_name);
    strcat(buffer,"\n");
    send(new_socket, buffer, strlen(buffer),0);
    

    jetzt nur noch diesen blöden Speicherzugriffsfehler wegbekommen 😡



  • Hast du den Punkt mit den Compiler-Schaltern beachtet? Wie dir wahrscheinlich auffällt, gibt er dir bei den Runtime-Funktionen Quelldatei mit Zeilennummer aus. Mit Debugsymbolen macht er das auch bei deinen Quellen.



  • manuzi1 schrieb:

    2. wie kann ich dem Server beibringen dass er jede einzelne Datei quasi mit \n schickt, also dass es nicht in einer Schnur geschrieben wird.

    ich hoffe mir kann wer helfen, ich bin schon am verzweifeln! 😡

    Ahoi, versuch es mal mit strcat. Also strcat(buffer,"\n") bevor du es an den Client zurückschickst.

    $ valgrind --leak-check=yes ./programname argumente
    

    Das Programm wird vorher mit Debugsymbolen -g und ohne Optimierung -O0 compiliert.

    Weil es da Probleme gibt (ich kenne mich damit zwar nicht aus) würde es aber wie folgt verstehen:

    zuerst
    gcc -g -oo -o xxx xxx.c

    und danach
    $ valgrind --leak-check=yes ./programname argumente

    Lg



  • reinker schrieb:

    zuerst
    gcc -g -oo -o xxx xxx.c

    Nicht -oo, sonder -O0 großes O und Null, für Null Optimierung.



  • Paul Müller schrieb:

    reinker schrieb:

    zuerst
    gcc -g -oo -o xxx xxx.c

    Nicht -oo, sonder -O0 großes O und Null, für Null Optimierung.

    Paul Müller schrieb:

    reinker schrieb:

    zuerst
    gcc -g -oo -o xxx xxx.c

    Nicht -oo, sonder -O0 großes O und Null, für Null Optimierung.

    hallo, sorry für die späte antwort:

    er sagt:

    by ........: main (myserver.c:105)

    zeile 105 wäre das:

    105 sprintf(buffer,(*list)->d_name);
    106 send(new_socket, buffer, strlen(buffer),0);
    107 free (*list);
    

    nun ist die frage was daran falsch ist. da ich diese scandir funktion, die eben die Dateien des Verzeichnis ausliest vom Galileo Computing - Linux/UNIX Programmierung habe. Nur, dass eben statt dem oben genannten Code:

    printf("%s\n", (*list)->d_name);
    free(*list);
    

    steht. (da es ja nicht vom client zum server geschickt wird, sondern das programm halt nur das komplette verzeichnis ausliest.)

    mit list[i]->d_name; habe ich es auch versucht, passiert aber der selbe fehler.

    Unser Professor hat gesagt, es sei da fast nichts zu ändern aber irgendwas muss da ja falsch sein. 😡



  • manuzi1 schrieb:

    er sagt:

    by ........: main (myserver.c:105)

    Was sagt er den genau? Über dem Block steht doch eine Fehlerbeschreibung?

    manuzi1 schrieb:

    105 sprintf(buffer,(*list)->d_name);
    106 send(new_socket, buffer, strlen(buffer),0);
    

    Eigentlich arbeitet printf mit einem Formatstring. Auch wenn es keinen Sinn zu machen scheint, mach mal daraus

    sprintf(buffer, "%s\n", (*list)->d_name);
    

    Wie du siehst kann man so auch gleich dein Newline-Problem in einem Aufwasch erledigen.

    manuzi1 schrieb:

    nun ist die frage was daran falsch ist. da ich diese scandir funktion, die eben die Dateien des Verzeichnis ausliest vom Galileo Computing - Linux/UNIX Programmierung habe.

    Das heißt ja nicht, dass dem Autor keine Fehler unterlaufen können.



  • Paul Müller schrieb:

    manuzi1 schrieb:

    er sagt:

    by ........: main (myserver.c:105)

    Was sagt er den genau? Über dem Block steht doch eine Fehlerbeschreibung?

    also genau schreibt er das:

    valgrind --leak-check=yes ./server 6543 ref
    ==20220== Memcheck, a memory error detector
    ==20220== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
    ==20220== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
    ==20220== Command: ./server 6543 ref
    ==20220== 
    Verzechnis schon vorhanden
    Waiting for connections...
    Client connected from 127.0.0.1:6543...
    Message received: LIST
    
    6 Dateien im Verzeichnis: /home/me/Desktop/server/ref
    ==20220== Use of uninitialised value of size 4
    ==20220==    at 0x8048DAD: main (myserver.c:106)
    ==20220== 
    ==20220== Invalid read of size 4
    ==20220==    at 0x8048DAD: main (myserver.c:106)
    ==20220==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==20220== 
    ==20220== 
    ==20220== Process terminating with default action of signal 11 (SIGSEGV)
    ==20220==  Access not within mapped region at address 0x0
    ==20220==    at 0x8048DAD: main (myserver.c:106)
    ==20220==  If you believe this happened as a result of a stack
    ==20220==  overflow in your program's main thread (unlikely but
    ==20220==  possible), you can try to increase the size of the
    ==20220==  main thread stack using the --main-stacksize= flag.
    ==20220==  The main thread stack size used in this run was 8388608.
    ==20220== 
    ==20220== HEAP SUMMARY:
    ==20220==     in use at exit: 168 bytes in 7 blocks
    ==20220==   total heap usage: 8 allocs, 1 frees, 32,960 bytes allocated
    ==20220== 
    ==20220== LEAK SUMMARY:
    ==20220==    definitely lost: 0 bytes in 0 blocks
    ==20220==    indirectly lost: 0 bytes in 0 blocks
    ==20220==      possibly lost: 0 bytes in 0 blocks
    ==20220==    still reachable: 168 bytes in 7 blocks
    ==20220==         suppressed: 0 bytes in 0 blocks
    ==20220== Reachable blocks (those to which a pointer was found) are not shown.
    ==20220== To see them, rerun with: --leak-check=full --show-reachable=yes
    ==20220== 
    ==20220== For counts of detected and suppressed errors, rerun with: -v
    ==20220== Use --track-origins=yes to see where uninitialised values come from
    ==20220== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 11 from 6)
    Speicherzugriffsfehler
    

    manuzi1 schrieb:

    105 sprintf(buffer,(*list)->d_name);
    106 send(new_socket, buffer, strlen(buffer),0);
    

    Eigentlich arbeitet printf mit einem Formatstring. Auch wenn es keinen Sinn zu machen scheint, mach mal daraus

    sprintf(buffer, "%s\n", (*list)->d_name);
    

    Wie du siehst kann man so auch gleich dein Newline-Problem in einem Aufwasch erledigen.

    Nein, macht es leider nicht besser. Sondern leider schlechter. Dann sendet er nichts an den Client zurück



  • Ersetze zum Testen mal den Eintrag von d_name durch einen festen String.

    sprintf(buffer, "%s\n", "foo");
    

    So kannst du zumindest erstmal die dirent-Struktur als Fehlerquelle ausschließen.

    manuzi1 schrieb:

    Nein, macht es leider nicht besser. Sondern leider schlechter. Dann sendet er nichts an den Client zurück

    Dann würde ich dort mal suchen.



  • Paul Müller schrieb:

    Ersetze zum Testen mal den Eintrag von d_name durch einen festen String.

    sprintf(buffer, "%s\n", "foo");
    

    So kannst du zumindest erstmal die dirent-Struktur als Fehlerquelle ausschließen.

    ok, das funktioniert, also das dirent struct ist es mal nicht.

    manuzi1 schrieb:

    Nein, macht es leider nicht besser. Sondern leider schlechter. Dann sendet er nichts an den Client zurück

    Dann würde ich dort mal suchen.

    Was meinst du mit dort?

    Es ist ja so: Er sendet ja noch bei sprintf(buffer,(*list)->d_name); die korrekten Dateien an den Client. Das heißt der Fehler muss nachdem die for-Schleife das letzte Mal durchgeht passieren. Sprich bei free(*list)?!? Da ja alle Dateinamen am Client ankommen.

    Danke fürs helfen. Kann nie oft genug kommen 😉 👍



  • [quote="manuzi1"]
    ok, das funktioniert, also das dirent struct ist es mal nicht.

    Wenn du also "foo" anstatt dem Namen sendest, dann geht es? Dann hängt es doch mit der Struktur zusammen.

    [quote="manuzi1"]
    Was meinst du mit dort?

    Das es nicht sein kann, dass durch den Formatstring plötzlich nichts mehr geht. Da scheint mir mit deiner dirent-Struktur etwas im argen zu sein.
    Ein Debugger wäre an der Stelle keine schlechte Idee. Oder ganz klassisch printf im Code verteilen. Auch nicht schlecht wäre es, wenn du deinen aktuellen Code noch mal zeigst.



  • [quote="Paul Müller"][quote="manuzi1"]
    ok, das funktioniert, also das dirent struct ist es mal nicht.

    Wenn du also "foo" anstatt dem Namen sendest, dann geht es? Dann hängt es doch mit der Struktur zusammen.

    manuzi1 schrieb:

    Was meinst du mit dort?

    Das es nicht sein kann, dass durch den Formatstring plötzlich nichts mehr geht. Da scheint mir mit deiner dirent-Struktur etwas im argen zu sein.
    Ein Debugger wäre an der Stelle keine schlechte Idee. Oder ganz klassisch printf im Code verteilen. Auch nicht schlecht wäre es, wenn du deinen aktuellen Code noch mal zeigst.

    ich hab es mal mit der printf Methode gemacht, da schreibt der Server 1. Nicht mehr. Komisch.

    Hier mal der ganze Code:

    server:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/stat.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <dirent.h>
    #include <errno.h>
    #define BUF 1024
    #define PORT 6543
    
    int main (int argc, char **argv) {
      mode_t mode = S_IRWXU;
      int create_socket, new_socket;
      socklen_t addrlen;
      char buffer[BUF];
      char buffer1[] = "Dateiname:";
      int size;
      int err = 0;
      struct sockaddr_in address, cliaddress;
      //struct fuer Verzeichnis einlesen (scandir)
      int num_entries, i;
      struct dirent **namelist, **list;
      const char *ptr = NULL;
      char wd[BUF];
      //fuer GET
      FILE *from, *to;
    
      //Eingabe der Argumente ServerIP & Port
      if( argc < 3){
         		printf("Usage: %s Port Downloadverzeichnis\n", argv[0]);
         		exit(EXIT_FAILURE);
      	}
      //Verzeichnis anlegen
      //Zugriffsrechte erlauben
      umask(0);
    
      if((mkdir(argv[2], mode)) != -1 )
      {
      	printf("Verzeichnis %s erstellt\n",argv[2]);
    
      }
      else
      {
      	printf("Verzechnis schon vorhanden\n",argv[2]);
    
      }
    
      create_socket = socket (AF_INET, SOCK_STREAM, 0);
    
      memset(&address,0,sizeof(address));
      address.sin_family = AF_INET;
      address.sin_addr.s_addr = INADDR_ANY;strcpy(buffer,"OK");
      address.sin_port = htons (PORT);
    
      if (bind ( create_socket, (struct sockaddr *) &address, sizeof (address)) != 0) {
         perror("bind error");
         return EXIT_FAILURE;
      }
      listen (create_socket, 5);
    
      addrlen = sizeof (struct sockaddr_in);
    
      while (1) {
         printf("Waiting for connections...\n");
         new_socket = accept ( create_socket, (struct sockaddr *) &cliaddress, &addrlen );
         if (new_socket > 0)
         {
            printf ("Client connected from %s:%d...\n", inet_ntoa (cliaddress.sin_addr),ntohs(cliaddress.sin_port));
            strcpy(buffer,"Welcome to myserver, Please enter your command:\n");
            send(new_socket, buffer, strlen(buffer),0);
         }
         //Befehlsabarbeitungen bis Quit ausgeführt wird.
         do {
    	//Befehl von Client erhalten
            size = recv (new_socket, buffer, BUF-1, 0);
            if( size > 0)
            {
             	buffer[size] = '\0';
    
    		if(strncmp(buffer, "LIST",4) == 0)
    		{
    
    				printf ("Message received: %s\n", buffer);
    				ptr = argv[2];
    				if((num_entries = scandir(ptr, &namelist, 0, alphasort)) < 0)
    				{
    					fprintf (stderr, "Unerwarteter Fehler\n");
    					exit (EXIT_FAILURE);
    				}
    
    				chdir(ptr);
    				getcwd (wd, BUF);
    				printf("%d Dateien im Verzeichnis: %s\n", num_entries, wd);
    				if(num_entries > 0 )
    				{
    					for(i = 0, list = namelist ; i <= num_entries; i++, list++)
    					{
    						//printf("1\n");
    						//sprintf(buffer, "%s\n", (*list)->d_name);
    						sprintf(buffer,(*list)->d_name);
    						//printf("2\n");
    						strcat(buffer,"\n");
    						//printf("3\n");
    						send(new_socket, buffer, strlen(buffer),0);
    						//printf("4\n");
    						free (*list);
    						//printf("5\n");
    					}
    					//printf("6\n");
    					free(namelist);
    					//printf("7\n");
    					printf("\n");
    
    				}
    				else { err++; }
    				printf("\n");
    
    			//ok falls kein Fehler besteht
    			if(err==0)
    			{
    				strcpy(buffer,"OK");
    				send(new_socket, buffer, strlen(buffer),0);
    			}
    			else
    			{
    				strcpy(buffer,"ERROR");
    				send(new_socket, buffer, strlen(buffer),0);			
    			}
    		}
    		else if(strncmp(buffer, "GET",3) == 0)
    		{
    			printf ("Message received: %s\n", buffer);
    
    		}
    
            }
            else if (size == 0)
            {
               printf("Client closed remote socket\n");
               break;
            }
            else
            {
               perror("recv error");
               return EXIT_FAILURE;
            }
         } while (strncmp (buffer, "QUIT", 4)  != 0);
         close (new_socket);
      }
      close (create_socket);
      return EXIT_SUCCESS;
    }
    

    client:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #define BUF 1024
    #define PORT 6543
    
    int main (int argc, char **argv) {
      int create_socket;
      char buffer[BUF];
      struct sockaddr_in address;
      int size;
      int err = 0;
      char port_to_int[BUF]; //Umwandlung in integer (bei Porteingabe)
      int count; //variable um zum nächsten zeichen zu kommen
    
      //Eingabe der Argumente ServerIP & Port
      if( argc < 3 ){
         		printf("Usage: %s ServerAdresse Port\n", argv[0]);
         		exit(EXIT_FAILURE);
      	}
      //Port in Integer umwandeln
      	strcpy(port_to_int,argv[2]);
      	for(count=0;count<strlen(port_to_int);count++)
      	{
    		if(!isdigit(port_to_int[count]))
    		{
    			err++;
    		}
     	}
     	if(err > 0)
      	{
    		printf("Nur Zahlen beim Port eingeben\n");
    		exit(EXIT_FAILURE);
      	}
      	//PORT = atoi(port_to_int);
    
      //Socket oeffnen
      if ((create_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      {
         perror("Socket error");
         return EXIT_FAILURE;
      }
      //Serveradresse initialisieren
      memset(&address,0,sizeof(address));
      address.sin_family = AF_INET;
      address.sin_port = htons (PORT);
      inet_aton (argv[1], &address.sin_addr);
    
      //Verbinden
      if (connect ( create_socket, (struct sockaddr *) &address, sizeof (address)) == 0)
      {
         printf ("Erfolgreich mit Server %s verbunden. Port: %d\n", inet_ntoa (address.sin_addr), PORT);
         size=recv(create_socket,buffer,BUF-1, 0);
         if (size>0)
         {
            buffer[size]= '\0';
            printf("%s",buffer);
         }
      }
      else
      {
         perror("Connect error - no server available");
         return EXIT_FAILURE;
      }
    
      do {
         //printf ("Send message: ");
         fgets (buffer, BUF, stdin);
    
    	if(strcmp(buffer,"LIST\n") == 0)
    	{
    		//LIST Befehl an server übertragen
    		send(create_socket, buffer, strlen (buffer), 0);
    		//Antwort vom Server
    		size=recv(create_socket,buffer,BUF-1, 0);
    
    		if (size>0)
    		{
    			buffer[size]= '\0';
    			printf("%s\n",buffer);
    		}
         	}
    	else if(strcmp(buffer,"GET\n") == 0)
    	{
    		//GET command to the server
    		send(create_socket, buffer, strlen (buffer), 0);
    
         	}
    	else
    	{
    		printf("Es werden nur folgende Befehle erkannt: LIST, GET und QUIT\nBitte erneut versuchen\n");
    	}
      }while (strcmp (buffer, "QUIT\n") != 0);
      close (create_socket);
      return EXIT_SUCCESS;
    }
    

    Vielleicht kannst du dir das jetzt besser vorstellen. Ich gebe schon fast auf, da ich nicht mehr weiß was ich tun soll.

    Beste Grüße 😞



  • Ich kürze deinen Quote mal um das, was zu beachten ist. Leider habe ich hier keinen Roten Kringel, also gehts hoffentlich auch so:

    manuzi1 schrieb:

    valgrind --leak-check=yes ./server 6543 ref
    (...)
    ==20220== Use of uninitialised value of size 4
    ==20220==    at 0x8048DAD: main (myserver.c:106)
    ==20220== 
    ==20220== Invalid read of size 4
    ==20220==    at 0x8048DAD: main (myserver.c:106)
    ==20220==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==20220== 
    ==20220== 
    ==20220== Process terminating with default action of signal 11 (SIGSEGV)
    ==20220==  Access not within mapped region at address 0x0
    ==20220==    at 0x8048DAD: main (myserver.c:106)
    (...)
    

    Ich gehe jetzt einfach mal davon aus, dass die Fehlermeldung immernoch den gleichen Teil meint, also das sprintf aus Zeile 105, jetzt Zeile 106:

    105 sprintf(buffer,(*list)->d_name);
    
    1. Ist buffer irgendwo initialisiert? (Erste Fehlermeldung)
      Wenn ja, ist es groß genug? Wenn nein, warum nicht?
    2. Ist list initialisiert und (*list) garantiert kein Nullzeiger? (Zweite Fehlermeldung)
    3. Was soll in d_name stehen? Welchen Typ hat d_name ?
    4. Wenn buffer und list ordnungsgemäß initialisiert wurden, so kann sich die zweite Fehlermeldung auch darauf beziehen, dass d_name ein NULL-Zeiger ist. Hast du das schon überprüft?

    Gruß
    Yama



  • Yamakuzure schrieb:

    Ich kürze deinen Quote mal um das, was zu beachten ist. Leider habe ich hier keinen Roten Kringel, also gehts hoffentlich auch so:Ich gehe jetzt einfach mal davon aus, dass die Fehlermeldung immernoch den gleichen Teil meint, also das sprintf aus Zeile 105, jetzt Zeile 106:

    105 sprintf(buffer,(*list)->d_name);
    
    1. Ist buffer irgendwo initialisiert? (Erste Fehlermeldung)
      Wenn ja, ist es groß genug? Wenn nein, warum nicht?
    2. Ist list initialisiert und (*list) garantiert kein Nullzeiger? (Zweite Fehlermeldung)
    3. Was soll in d_name stehen? Welchen Typ hat d_name ?
    4. Wenn buffer und list ordnungsgemäß initialisiert wurden, so kann sich die zweite Fehlermeldung auch darauf beziehen, dass d_name ein NULL-Zeiger ist. Hast du das schon überprüft?

    Gruß
    Yama

    Hallo Yama 😉

    einen Eintrag über dir steht der Code.

    //struct fuer Verzeichnis einlesen (scandir)
      int num_entries, i;
      struct dirent **namelist, **list;
      const char *ptr = NULL;
      char wd[BUF];
    
    1. in buffer ist der Dateiname enthalten und er ist fuer die Dateinamen groß genug.

    2. list = namelist. Wie kann ich schauen ob (*list) garantiert kein Nullzeiger ist? einfach mit if davor testen? also if(list != NULL)?

    3)d_name ist im struct dirent enthalten und soweit ich es verstanden habe ein string behälter.

    4)Jawohl.

    Danke natürlich auch für deine Hilfe. Ich hoffe ich bekomme das noch hin.

    Lg



  • Mal blind ins blaue geraten handelt es sich bei der dirent-Struktur um eine verkettete Liste und mit deinem free() sägst du am Ast auf dem du sitzt. Im Beispiel in der Manpage geht man äquivalent zu deiner Vorgehensweise vor, nur mit dem Unterschied, dass man von hinten anfängt. Ich denke das wird nicht grundlos sein.
    Dein Client ist auch etwas naiv umgesetzt. Du setzt voraus, dass alle Daten auf einmal kommen. Dem muss aber nicht so sein. Schlauer wäre es zuerst die Anzahl der Einträge zu übertragen und dann alle Strings mit vorangestellter Größe zu übertragen. So brauchst du wirklich nur noch die Bytes empfangen, die auch für dich sind. Und der Server kann auch mal etwas bummeln.



  • Paul Müller schrieb:

    Schlauer wäre es zuerst die Anzahl der Einträge zu übertragen und dann alle Strings mit vorangestellter Größe zu übertragen. So brauchst du wirklich nur noch die Bytes empfangen, die auch für dich sind. Und der Server kann auch mal etwas bummeln.

    Ich will mich da ja nicht einmischen. Aber er zählt doch die Einteräge mit

    if((num_entries = scandir(ptr, &namelist, 0, alphasort)) < 0)
                    {
                        fprintf (stderr, "Unerwarteter Fehler\n");
                        exit (EXIT_FAILURE);
                    }
    

    oder? 😕

    Oder meinst du, dass er num_entries an den Client schicken soll? Also sprich, dass x Dateien am Server bzw. im Verzeichnis liegen. Aber wozu die Info?
    Muss der Client die Größe der Datei wissen? Wäre nettes Zusatzinfo:

    dazu schau dir mal die fktn stat() an oder du versuchst es so

    #include <stdio.h>
    void main()
    {
    FILE *file= fopen( "datei.xyz", "rb" ); //Datei zum Lesen öffnen.
    if (0==file)
    {   //Fehler, die Datei konnte nicht geöffnet werden
    }
    fseek( file, 0, SEEK_END );             //Dateizeiger ans Ende setzen
    size_t fileSize= ftell( file );         //Dateizeiger abfragen
    fclose( file );                         //Datei wieder schließen
    }
    

    Ich kann Paul Müller leider auch nicht ganz folgen. aber er meint (so vermute ich), dass du zuerst schaust wie viele Datein im Verzeichnis sind und die danach einzeln zu dem Client sendest.

    Wie man das hinbekommt, bin ich jetzt auf die schnelle überfragt.



  • Nein nicht die Dateigrößen. Sondern die Bytes die übertragen werden sollen, sprich die Textlänge. Damit der Client weiß, wieviel er zu empfangen hat. Momentan fordert der Client einfach mal pauschal 1024 Bytes an. Das ist schon allein deswegen schlecht, weil die Dateinamen zusammen auch länger als 1024 Zeichen sein können. Außerdem kann der Client schon vorher zurück kommen, bevor er alle Namen empfangen hat.
    Ich hab den Quelltext mal soweit angepasst und bei mir werden die Namen ohne Zugriffsfehler übertragen. Die Programme liefen beide in valgrind zur Überprüfung.

    http://pastebin.com/d2b4NEhM
    http://pastebin.com/sB7L6hBV


Anmelden zum Antworten