[C] Socket für TCP/UDP Übertragung programmieren

AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Siehe mein EDIT. Ich habe für alle mit malloc reservierten Daten ein free() im Code. Die free()s ganz an das Ende des Codes (vor return 0) setzen, ändert übrigens nichts, bevor mir das einer empfiehlt ...
 
Zum Ermitteln von segfaults ist valgrind eine schlechte Idee. Nimm den ddd zum Debuggen, setz einen Breakpoint und starte dein Programm mit den gewünschten Parametern und gehe Zeile für Zeile durch und schau dir die Werte der Variablen an. So erkennt man bei einfachen Programmen segfaults.

Valgrind würde ich persönlich erst dann nutzen, wenn ich Speicherlecks oder Race Conditions im Multithreading finden möchte.

Gruß
crusherd

Edit:
Beim Programmieren ist das Debug-Flag "-g" unter Linux Pflicht. Erst wenn das Programm veröffentlicht werden soll, macht man das raus. ;-)
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Danke @ Dragonix! :) So hat's jetzt geklappt, dass zumindest laut valgrind keine memory leaks mehr durch den Code entstehen können:
Code:
[COLOR=seagreen]/* Parameter: UDP/TCP Client Server-IPv4-Adresse Port */
/* Parameter: UDP/TCP Server Port */int main(int argc, char *argv[]) {
    int port, size1=4096, size2=1024;
    char *data = (char*)malloc(size1 * sizeof(char));
    char *server_ip = (char*)malloc(size2 * sizeof(char));
    
    if (data==NULL || server_ip==NULL) { 
        printf("Memory allocation failed!\n"); 
        return -1; 
    }
    
    if (argc==4) {
        if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Server")==0)) {
            port = atoi(argv[3]);
            tcp_server(port);
        } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
            port = atoi(argv[3]);
            udp_server(port);
        }
    } else if (argc==5) {
        if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Client")==0)) {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            tcp_client(data, port, server_ip);
        } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Client")==0)) {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            udp_client(data, port, server_ip);;
        }
    } else if (argc<4 || argc>5) {
        printf("Missing or too many parameters!\n");
        [COLOR=royalblue][B]free(data);
        free(server_ip);[/B]        return -1;
    }
    
    [COLOR=royalblue][B]free(data);
    free(server_ip);[/B]
    return 0;
}
Capture.JPG

Ich gehe jetzt mal schauen, ob das "Segmentation fault" immer noch kommt ...

@ crusherd
Wenn's "Segmentation fault" immer noch da ist, werde ich mir deinen Vorschlag mal näher durchdenken. Aber erst mal schauen ...

[EDIT]
Damn! Es kommt immer noch:

Capture.JPG
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Zum Ermitteln von segfaults ist valgrind eine schlechte Idee. Nimm den ddd zum Debuggen, setz einen Breakpoint und starte dein Programm mit den gewünschten Parametern und gehe Zeile für Zeile durch und schau dir die Werte der Variablen an. So erkennt man bei einfachen Programmen segfaults.
Für die Fehler die hier drin sind, ist valgrind m.e. optimal (bzw. ist valgrind überflüssig - gründliches Durchgehen Zeile für Zeile des Codes wäre auch nicht verkehrt...).

Edit:
Beim Programmieren ist das Debug-Flag "-g" unter Linux Pflicht. Erst wenn das Programm veröffentlicht werden soll, macht man das raus. ;-)
:daumen:

dass zumindest laut valgrind keine memory leaks mehr durch den Code entstehen können
NEIN! NEEEIIIN! In dem Teil deines Programms, der von valgrind Durchlaufen wurde, können keine Lecks mehr sein. Aber dein Programmtext kann ja auch irgendwo eine Endlosschleife enthalten. Solang du diese niemals betrittst, endet dein Programm trotzdem (dadurch klar geworden?).
Und ja, der segfault ist immernoch da...


Edit:
Code:
==5655== Invalid free() / delete / delete[] / realloc()
==5655==    at 0x4C2B32C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==5655==    by 0x401486: main (test.c:191)
==5655==  Address 0x7fefffdde is on thread 1's stack

Und jetzt schau mal (wenn du willst mit ddd/gdb, eine sinnvolle Übung wär es ja...), was du hier versuchst freizugeben... d.h. schau auch mal, worauf der Zeiger (mittlerweile) zeigt...

ddd ist (nur) ein graphisches Frontend. Kannst gleich den gdb nehmen. Aber wie gesagt,
Ich schau jetzt mal den ganzen Code langsam Zeile für Zeile durch.
Ist durchaus sinnvoll.
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Schleifen habe ich nur 2 drinnen und das sind sehr sicher keine Endlosschleifen (ich weiß, dass du das nur als Beispiel gesagt hast). Jetzt bin ich echt am Ende mit meinen Ideen, wo der Segfault noch herkommen könnte ...

ddd geht scheinbar nur mit grafischer Oberfläche (?) und die habe ich nicht (und sollte ich in der VM auch nicht installieren).

Ich schau jetzt mal den ganzen Code langsam Zeile für Zeile durch. Vielleicht fällt mir was auf. Wenn nicht, muss ich's bald so lassen. Immhin die Datenübertragung funktioniert.
 
Wenn's ohne grafische Oberfläche sein muss, empfehle ich den gdb. Der ist komplett konsolenbasiert. Damit habe ich im Studium beispielsweise das os161 gedebuggt. ;-)

Warum verwendest du in einer Vm keine grafische Oberfläche? Ist das so vorgeschrieben oder willst du nur mit Konsole arbeiten?

Gruß
crusherd
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Ja, die VMs, die wir von der Uni bekommen haben, sollten auch genau so verwendet werde, wie wir sie bekommen haben ... ohne grafische Oberfläche.

Dann schaue ich mir noch gdb an ...
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Und wenn dann irgendwas nicht mehr geht, wo nehme ich dann neue VMs her? :schief:

Glaub mir, bei diesen VMs reichen Kleinigkeiten, dass nichts mehr geht. Habe das erst letzte Woche erlebt gehabt. Da konnte ich es gerade noch einmal retten. Noch einmal brauche ich den Nervenkrieg nicht.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Dann
a) leg dir ein Backup der VM an.
b) nehm einfach gdb.
c) nehm valgrind und schau dir die angebene Stelle an (reicht hier mehr als dicke)
d) schau einfach selber nochmal den Code durch (das schadet auf keinen Fall etwas).
e) Mach deine eigene VM mit nem Linux
f) Installier dir Linux richtig auf den Rechner
g) Installier dir unter Windows eine POSIX Kompatibilitätsschicht
h) Erstell dir ein Linux Live Medium und entwickle von da.
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Okay ... die Fehlerquelle war ja mit gdb leicht zu ermitteln:

Capture.JPG

^^ Jetzt muss ich mir überlegen, was denn hier eigentlich der Fehler ist. In Zeile 205 ist jedenfalls das free(server_ip); ... mich wunderts nur gerade, dass gdb den Segfault nur beim Testen des UDP Clients gefunden hat, aber nicht bei den anderen 3 Funktionen. Beim TCP Client wird aber genauso malloc/free verwendet.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Ich glaube, ich hab es gefunden. Ist ein ziemlich banaler Fehler :ugly: Wenn es das wirklich sein sollte, dann liegt der Fehler allein in deiner main.

Edit: Japp, ohne meine Änderungen gibt es ein SIGABORT/SIGSEGV, nach meinen Änderungen läuft es durch :)
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Das Entfernen des genannten free(server_ip); hat den Segfault tatsächlich beseitigt. Ich verstehe nur noch nicht, warum ...
Code:
[COLOR=seagreen]/* Parameter: UDP/TCP Client Server-IPv4-Adresse Port */
/* Parameter: UDP/TCP Server Port */int main(int argc, char *argv[]) {
    int port, size1=4096, size2=1024;
    char *data = (char*)malloc(size1 * sizeof(char));
    char *server_ip = (char*)malloc(size2 * sizeof(char));
    
    if (data==NULL || server_ip==NULL) { 
        printf("Memory allocation failed!\n"); 
        return -1; 
    }
    
    if (argc==4) {
        if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Server")==0)) {
            port = atoi(argv[3]);
            tcp_server(port);
        } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
            port = atoi(argv[3]);
            udp_server(port);
        }
    } else if (argc==5) {
        if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Client")==0)) {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            tcp_client(data, port, server_ip);
        } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Client")==0)) {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            udp_client(data, port, server_ip);;
        }
    } else if (argc<4 || argc>5) {
        printf("Missing or too many parameters!\n");
        free(data);
        free(server_ip);
        return -1;
    }
    
    free(data);

    return 0;
}
^^ So läuft der Code einwand- und fehlerfrei. :)

Wenn eine gültige Parameteranzahl an main übergeben wird und somit eine der Funktionen ausgeführt wird, wird am Ende nur der Speicher von data wieder freigegeben?! Der von server_ip jetzt nicht mehr, so wie ich das sehe. Und gerade das widerspricht meiner Logik.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Diese Zeile hier ist das Problem:
Code:
server_ip = argv[3];
Du ersetzt hier den Zeiger auf deinen selbst allozierten Speicher durch einen Zeiger auf einen vom OS allozierten Speicherbereich - und den versuchst du dann mittels free freizugeben! Du brauchst für server_ip eigentlich überhaupt kein malloc (das if (... == NULL) anpassen nicht vergessen), wenn du das mit dem Zeigen auf argv[3] machst!
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Ganz komme ich da noch nicht mit. Wieso brauche ich dann bei data ein malloc? Bei data und server_ip wird ein char string übergeben. Außerdem muss ich ja server_ip irgendwo zumindest deklarieren.

Hast du so gemeint? ...
Code:
[COLOR=seagreen]/* Parameter: UDP/TCP Client Server-IPv4-Adresse Port */
/* Parameter: UDP/TCP Server Port */int main(int argc, char *argv[]) {
    int port, size1=4096;
    [COLOR=royalblue][B]char[/B] *data = (char*)malloc(size1 * sizeof(char)), [COLOR=royalblue][B]*server_ip[/B];
    
    if (data==NULL) { 
        printf("Memory allocation failed!\n"); 
        return -1; 
    }
    
    if (argc==4) {
        if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Server")==0)) {
            port = atoi(argv[3]);
            tcp_server(port);
        } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
            port = atoi(argv[3]);
            udp_server(port);
        }
    } else if (argc==5) {
        if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Client")==0)) {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            tcp_client(data, port, server_ip);
        } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Client")==0)) {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            udp_client(data, port, server_ip);;
        }
    } else if (argc<4 || argc>5) {
        printf("Missing or too many parameters!\n");
        free(data);
        return -1;
    }
    
    free(data);

    return 0;
}
[EDIT]
Ah, data wird ja nicht über einen argv[]-Zeiger initialisiert. Ok, macht schon Sinn so. Außerdem könnte ich data auch mit einer festen Größe initialisieren. Dann müsste ich nur eine wirklich große erwischen, wo jede halbwegs wahrscheinliche Usereingabe reinpasst.
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Data benutzt du ja, um die Nachricht einzulesen, das muss also Speicher haben. Ich hätte das jetzt allerdings auch mit einem festen Array gelöst und nicht mit malloc/free. Und server_ip deklarierst du ja, in dem du es in der Form char *server_ip angibst - du brauchst dafür nur keinen Speicher, da du einfach den Zeiger auf das Argument setzt (und für das wurde schon Speicher vom OS reserviert). So wie du in C mit stringA == stringB keinen Stringvergleich machen kannst, kopiert stringA = stringB nicht den Inhalt von stringA nach stringB, sondern setzt den Zeiger von stringA auf den Zeiger von stringB. Du hast also zwei Zeiger, die dann auf den selben Speicherbereich zeigen.

Das ist wirklich ein banaler Fehler :ugly:
Hat trotzdem lange gedauert, bis ich das gefunden hatte :D
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Ok, danke! Ja, ist mir eh selbst schon gekommen ... siehe EDIT oben ;)

Jetzt kann ich mir endlich den Teil hier überlegen:

Capture.JPG
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Hat trotzdem lange gedauert, bis ich das gefunden hatte :D
Ja, und genau deswegen hab ICH mich auch nicht intensiv mit dem Code beschäftigt. Der Threadstarter muss sich einfach, wie jetzt schon mehrfach, mit Zeigern intensiver beschäftigen, sonst passiert genau so etwas immer wieder. Da ist auch keinem geholfen bei, ihm jetzt bei der Fehlersuche zu helfen. Da fehlen einfach noch ein paar Grundlagen.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Das hat jetzt nichts mehr mit Programmieren zu tun, aber da ihr euch scheinbar auch mit Linux ziemlich gut auskennt, frage ich trotzdem hier: tcpdump ist auf den beiden VMs nichts installiert und die VMs haben auch keinen Internetzugang.

Um tcpdump trotzdem installieren zu können, bin ich daher wie folgt vorgegangen:
Code:
1.) nötige files besorgen:

1.1) flex als .tar.gz downloaden: http://flex.sourceforge.net/
1.2) m4 als .tar.gz downloaden: http://ftp.gnu.org/gnu/m4/
1.3) tcpdump als .tar.gz downloaden: http://www.tcpdump.org/#latest-release
1.4) libpcap als .tar.gz downloaden: http://www.tcpdump.org/#latest-release
1.5) Mit WinSCP (http://sourceforge.net/projects/winscp/) auf die Client-VM verbinden und alle 4 files einfach aus dem Windows-(Download)-Verzeichnis ins Linux-Verzeichnis rüberziehen ("copy" bestätigen), dann alles in die Server-VM rein

2.) m4 installieren:

2.1) m4 entpacken: tar -zxvf m4-1.4.1.tar.gz
2.2) cd m4-1.4.1
2.3) m4 konfigurieren: ./configure --prefix=/usr/local/m4
2.4) m4 compilieren: make
2.5) m4 installieren: sudo make install

3.) flex installieren:

3.1) flex entpacken: tar -zxvf flex-2.5.37.tar.gz
3.2) cd flex-2.5.37
3.3) PATH=$PATH:/usr/local/m4/bin/
3.4) flex konfigurieren: ./configure --prefix=/usr/local/flex
3.5) flex compilieren: make
3.6) flex installieren: sudo make install

4.) libpcap und tcpdump:

4.1) libpcap entpacken: tar –zxvf libpcap-1.3.0.tar.gz
4.2) tcpdump entpacken: tar –zxvf tcpdump-4.3.0.tar.gz
4.3) cd libpcap-1.3.0
4.4) sh ./configure
4.5) sh ./make
4.6) sh ./make install
4.7) cd tcpdump-4.3.0
4.8) sh ./configure
4.9) sh ./make
4.10) sh ./make install
Allerdings komme ich nur bis 4.4) ... dann kommt folgende Fehlermeldung:

Capture.JPG

^^ Ganz offenbar wurde also flex nicht installiert und wenn ich dpkg-query -l 'flex' eingebe, bestätigt sich dies:

Capture.JPG

m4 wurde scheinbar auch nicht installiert. Ich habe keine Ahnung, was da schief gegangen ist, v.a. weil während der Installation von m4 und flex keine Fehlermeldungen gekommen sind. Jedenfalls kann flex nicht ohne m4 und libpcap/tcpdump nicht ohne flex installiert werden ... :ugly:

Ich sehe jetzt 2 Möglichkeiten:
1.) Irgendwer von euch kennt sich mit dem Zeug aus und kann mir bitte verraten, woran das hier scheitert
2.) Ihr helft mir bitte, in den Routing Tabellen der beiden VMs die nötige Route hinzuzufügen, sodass ich ins Internet komme und dann flex ganz normal aus der Debian Paketverwaltung heraus installieren kann

client.JPG server.JPG

^^ Den Befehle zum Hinzufügen von Routen kenne ich BTW (hier nur ein Beispiel):
Code:
route add -net [COLOR=#000000]192.168[COLOR=#000000].1[COLOR=#000000].0 netmask [COLOR=#000000]255.255[COLOR=#000000].255[COLOR=#000000].0 gw [COLOR=#000000]192.168[COLOR=#000000].1[COLOR=#000000].254
Allerdings kenne ich mich nicht so gut aus, dass ich jetzt wüsste, wie eine Route ins Internet ausschauen muss ... :huh:

0.0.0.0 wahrscheinlich als Destination und bei der Netmask würde ich auch 0.0.0.0 vermuten?! Aber dann wäre ja die dritte Route schon ins Internet?! Das Gateway ist ja der Router?!
 
Zurück