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

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

Ähm... die Frage ist jetzt nicht wirklich dein Ernst :ugly:

Du arbeitest ja mit Zeigern. Da musst du IMMER selbst schauen, was du da machst...

Bitte bitte bitte beschäftige dich mal grundlegend mit Zeigerarithmetik... Das brauchst du immer.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Glaubst du, dass das "Segmentation fault" von einem Zeigerfehler kommt? Wieso compiliert der Code dann aber mit all den Parametern, die du am Screenshot siehst? Als ich noch offensichtliche Zeigerfehler drinnen hatte, wurden die ja auch sofort gefunden ...

[EDIT]
So, mit fgets klappt das jetzt wirklich gut:
Code:
fgets(data, size1, stdin);
Capture.JPG

Ich gehe jetzt mal UDP testen ... :)

[EDIT2]
Bei UDP bleibt beim Server das Problem, das ich bei einem ersten Test schon mal gesehen habe:

Capture.JPG

^^ Die Fehlermeldung kommt mir nur gerade insofern komisch vor, weil ich mir das wenn dann vom Client erwarten würde. Der Server ist doch der "transportation end point"?! Mal schauen, vielleicht bin ich damit eh schon auf der richtigen Spur.

!! Hier auch mal der ganze aktuelle Code zum Mitschauen !!
Code:
#define _GNU_SOURCE

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#endif

void tcp_server(int port) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
    }

    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    socklen_t len;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

    [COLOR=seagreen]/* listen() - Auf eingehende Verbindungen warten */    if (listen(sockfd, 5) == -1) {
        perror("listen()");
    }

    [COLOR=seagreen]/* accept() - Die eingehende Verbindung annehmen */     socklen_t sin_size = sizeof(struct sockaddr_in);
    struct sockaddr_in remote_host;
    int sock2 = accept(sockfd, (struct sockaddr *)&remote_host, &sin_size);
    if (sock2 == -1) {
        perror("accept()");
    }

    [COLOR=seagreen]/* recv() - Empfangen mit TCP */    ssize_t msg_length;
    char buf[1024];
    if ((msg_length = recv(sock2, buf, 1024, 0)) == -1) {
        perror("recv()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));

   [COLOR=seagreen] /* close() - Socket freigeben */    int close(int sockfd); 
}

void tcp_client(char *data, int port, char *server_ip) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
    }

    [COLOR=seagreen]/* connect() - Verbindung aufbauen */    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); 
    inet_aton(server_ip, &serv_addr.sin_addr);
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }

    [COLOR=seagreen]/* send() - Senden mit TCP */    char *msg = data;
    int len = strlen(msg);
    if (send(sockfd, msg, len, 0) == -1) {
        perror("send()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void udp_server(int port) {    
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
    }

    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    socklen_t len;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

    [COLOR=seagreen]/* recvfrom() - Empfangen mit UDP */    ssize_t msg_length;
    struct sockaddr_in remote_host;
    socklen_t clientlen;
    clientlen = sizeof(remote_host);
    char buf[1024];
    if ((msg_length = [COLOR=royalblue][B]recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &clientlen)[/B]) == -1) {
        perror("recvfrom()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void udp_client(char *data, int port, char *server_ip) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
    }

    [COLOR=seagreen]/* sendto() - Senden mit UDP */    char *msg = data;
    int len = strlen(msg);
    struct sockaddr_in serv_addr;
    if (sendto(sockfd, msg, len, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
        perror("sendto()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

[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 ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Server")==0)) {
        if (argc!=4) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            port = atoi(argv[3]);
            tcp_server(port);
        }
    } else if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Client")==0)) {
        if (argc!=5) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            tcp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
        if (argc!=4) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            port = atoi(argv[3]);
            udp_server(port);
        }
    } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Client")==0)) {
        if (argc!=5) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            udp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

1. Hatte ich fgets geschrieben ;)
2. Sei nochmal explizit auf valgrind verwiesen.
3. Nur weil's mit -pedantic -Wall kompiliert, heißt das noch lange nicht, dass da keine Fehler mehr drin sind. Aber in der Regel ist die Codequalität doch etwas höher (ebenso bei valgrind: Nur weil valgrind keinen Speicherleck anzeigt, heißt es nicht, das in deinem Programm keins drin ist). Das erleichtert anderen das Helfen mitunter ungemein.
4. Ein Programm, das sich -- wann auch immer -- mit einem Segfault beendet, ist (zumindest in meinen Augen) kaputt; selbst wenn es scheinbar das tut was es soll - würde mich nicht wundern, wenn das dein Lehrer das genauso sieht. Aber wie gesagt, ich hab den Überblick verloren was jetzt wie geändert wurde...

So, eben mal valgrind auf dem neuen Code getestet: Ich wette, mit valgrind findest du den Fehler fürs segfault innerhalb von Sekunden. Das aber auch anders ein offensichtlicher Fehler... Und wenn du den Fehler hast, dann schaust du dir das restliche Programm nochmal auf ähnliche Fehler durch..
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Haben wir gleichzeitig gepostet/editiert?! ;)

fgets ist längst drinnen im Code. Der aktuellste Code ist jetzt auch im Vorposting zu sehen. Ich überlege mir jetzt mal, wie das valgrind wirklich funktioniert ...

Zurzeit bin ich gerade am googeln bzgl. der UPD-Server Fehlermeldung.

[EDIT]
Ok, valgrind ist wirklich total easy zu benutzen, wenn man mal kapiert hat, wie's geht. Habe auch schon den entsprechenden Output:

Capture.JPG

^^ So, wie ich das verstehe, liegt's irgendwie an dem strcmp, aber wie genau, muss ich mir noch überlegen ...
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Spontan gesagt: Dein ganzes UDP Zeug sollteste nochmal überarbeiten. Damit geht's schon los, UDP <<==>> Stream?
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

Und bei sendto gehts weiter, woher soll er wissen wo er das hinschicken soll (hier zeigt dir valgrind sogar an, dass dein Empfänger eine unitialisierte Variable ist)?


--

Edit:
Code:
 if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Server")==0)) {
Du greifst hier auf das 1. bzw 2. Argument zu - blos blöd, wenn du das Programm mit weniger Argumenten aufrufst - dann sind das bestenfalls Nullzeiger. Auf deutsch: Du prürfst die Anzahl der übergebenen Argumente zu spät. Aber da ist noch mehr drinnen ;)

--
Nochn Edit: Grad mal Aufgabe überflogen: Fehlerbehandlung nicht vergessen - auch malloc kann fehlschlagen, dass sollte man prüfen. Deswegen und auch wegen "free" würd ich (generell) versuchen, so viel wie möglich auf dem Stack zu lassen und nur wo nötig Speicher vom Heap zu holen. Heutzutage sollte malloc zwar nicht wegen fehlendem Speicher fehlschlagen, aber wenn eine Fehlerbehandlung gewünscht ist, ist's in meinen Augen Pflicht. Auch seltsam: Wenn kein Socket erstellt werden kann, rufst du perror auf (gut!), aber danach läufst du einfach - mit einem "kaputten" Socket weiter; willst du das wirklich? exit(EXIT_FAILURE), wenn keine anderweitige sinnvolle Behandlung möglich ist!
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Habe jetzt mal SOCK_STREAM in SOCK_DGRAM geändert. Was du in deinem Edit meinst, weiß ich, nur wie ich's codemäßig lösen soll, da ist mir noch keine brauchbare Idee gekommen. Je nach dem, ob der Anwender einen Server oder einen Client starten will, muss er 4 oder 5 Parameter (inkl. Programmaufruf) eingeben. Ich kann also nicht gleich von Anfang an sagen:
Code:
if (argv[1]!=NULL && argv[2]!=NULL && argv[3]!=NULL && argv[4]!=NULL) {
... restlicher main Code ...
eben weil ich nicht weiß, wie viele Parameter der User eingeben wird ... da muss ich mir noch was überlegen.

Ich schaue jetzt erst einmal, dass ich die restlichen netzwerktechnischen Fehler im UDP Code-Teil anfinde und rausbekomme ...
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Glaubst du, dass das "Segmentation fault" von einem Zeigerfehler kommt? Wieso compiliert der Code dann aber mit all den Parametern, die du am Screenshot siehst? Als ich noch offensichtliche Zeigerfehler drinnen hatte, wurden die ja auch sofort gefunden ...

Weißt du, und durch genau SOLCHE Aussagen zeigst du einem, dass du von Zeigern, und wie man Sie richtig verwendet einfach keinen Schimmer hast. Dir ist das gesamte Konzept von Buffern und Zeigern komplett unklar. Du wurstelst halt irgendwas vor dich hin, ohne zu verstehen, wa du da eigentlich machst....

Der Compiler prüft nur ob es Syntaktische Fehler gibt. Aber kein Compiler dieser Welt erkennt Logikfehler im Code...

Du bist z.B. immer selbst dafür verantwortlich, das du mit dem richtigen Datentype einen Zeiger verwendest, richtig referenzierst und dereferenzierst, und dir eben klar bist, wie groß denn deine Buffer sind. DU musst als Programmierer immer selbst dafür sorgen, dass du mit Zeigern nicht in unerlaubte Bereiche kommst... Auch musst DU wissen, was da jetzt für Daten drin stehen, und wie die zu interpretieren sind...

Und ein Segfault hat man nur, wenn man mit Zeigern scheise baut...

Also nochmal, arbeite dich bitte mal in RUHE durch Zeigerarithmetik durch, und was beim zuweisen von Zeigern und refrenzieren/dereferenzieren, sowie Typecasts denn genau passiert. Das hast du in ner halben Stunde bis Stunde gemacht. Dann wirst du auch deine Fehler finden, wenn dir noch klar ist, wie man buffer verwendet. Ansonsten wirste noch in 10 Jahren an dem Ding rumdoktoren, und einfach auf gut Glück irgendwas machen, bis es scheinbar funktioniert...

Und zum Segfault mal soviel... Wenn bei uns einer nen Programm mit nem Segfault abgegeben hat, dann hat sich der Tutor das meist gar nicht mehr angeschaut, sondern direkt 0 Punkte vergeben, oder wenn er gut drauf war geschaut was alles scheinbar funktioniert und dann dafür noch paar Gnadenpunkte verteilt... Nur mal so..
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

@ Dragonix
Habe den Code mal entsprechend erweitert:
Code:
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }
Code:
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; 
    }
...
Nur den netzwerktechnischen Fehler in sendto() sehe ich noch nicht ...
Code:
[COLOR=seagreen]/* sendto() - Senden mit UDP */    char *msg = data;
    int len = strlen(msg);
    struct sockaddr_in serv_addr;
    if (sendto(sockfd, msg, len, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
        perror("sendto()");
    }
Ich habe ja hier genau angegeben, dass die Nachricht an die Sever-IP gehen soll?! Im Übrigen habe ich auf dem Client auch (noch) keine Fehlermeldung bekommen. Nur am Server wegen dem recvfrom():
Code:
[COLOR=seagreen]/* recvfrom() - Empfangen mit UDP */    ssize_t msg_length;
    struct sockaddr_in remote_host;
    socklen_t clientlen;
    clientlen = sizeof(remote_host);
    char buf[1024];
    if ((msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &clientlen)) == -1) {
        perror("recvfrom()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));
^^ Von der Logik her würde ich, wie gesagt, auch meinen, dass der Client nicht die IP vom Server hat, aber wieso beschwert sich dann recvfrom()?

@ Skysnake
Dank valgrind ist ja mittlerweile bekannt, dass das Segfault daher kommt, weil ich nicht überprüfe, ob strcmp eh keinen Null-Pointer bekommt. Nur wie ich den Code entsprechend umbasteln soll, muss ich mir noch überlegen.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Schuss ins blaue: Du hast SOCK_STREAM nur beim Client ausgebessert.

Kleines bischen Theorie: UDP ist verbindungslos, d.h. dein Socket kannst du (theoretisch) ohne es zu ändern für die Kommunikation mit mehreren Ports/Rechnern verwenden. D.h. nur die Angabe eines Sockets an sendto *reicht nicht* (bei TCP hast du ja nur "send", ohne "to" verwendet - hier ist das Socket auch mit dem "gegenüberliegenden" Socket "verschweißt"). Du übergibst sendto aber eine nicht initialisierte Datenstruktur - d.h. dein sendto schickt das ganze (bestenfalls) irgendwo hin (wer weiß was intern passiert). Lange rede kurzer Sinn:
Ich habe ja hier genau angegeben, dass die Nachricht an die Sever-IP gehen soll?!
DAS hast du eben genau NICHT gemacht, dein remote_host ist herrlich uninitialisiert. Schau dir deine udp_send ruhig noch mal Zeile für Zeile durch - du arbeitest hier *niergendwo* mit Adresse/Port (anders als bei TCP gibt's hier kein connect(); das Ziel stellst du hier beim/vorm Aufruf von sendto. Mehr Hinweise gibt's dazu vorerst aber nicht ;), das sollte aber auch erstmal reichen...

Und bezüglich der Anzahl der Parameter: Die steht in argc. Also z.B. einfach prüfen, wie viel Argumente der Nutzer dir übergeben hat. Oder du schaust ob der Nutzer dir mindestens 1 (argc==2) Argument übergeben hat und vergleichst dann das. Oder du schreibst dir gleich nen richtig fetten Parser oder oder oder, da gibt's viele Möglichkeiten...

Dank valgrind ist ja mittlerweile bekannt, dass das Segfault daher kommt, weil ich nicht überprüfe, ob strcmp eh keinen Null-Pointer bekommt. Nur wie ich den Code entsprechend umbasteln soll, muss ich mir noch überlegen.
Wie ich schon geschrieben hatte: Valgrind ist nicht allmächtig. Valgrind kann die Fehlersuche unheimlich erleichtern, vielmehr aber auch nicht, insbesondere bzgl. dem Stack ist valgrind auch nicht besonders hilfreich. (Und der ursprüngliche segfault kommt wo anders her, du hast blos, indem du dein Programm ohne Parameter gestartet hast, einen weiteren segfault gefunden - womit wir auch schon wieder bei der Beschränktheit von valgrind angekommen sind). Folglich: Kein Programm der Welt nimmt dir die Pflicht ab, ordentlichen, sauberen und durchdachten Code zu schreiben (so in etwa).
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Schuss ins blaue: Du hast SOCK_STREAM nur beim Client ausgebessert.
Nö, bei beiden. Du hast es aber im obig zitierten Code nur im Client gesehen?! Egal ...

Capture.JPG

^^ Netzwerktechnisch funktioniert jetzt alles einwandfrei (:daumen:):
Code:
#define _GNU_SOURCE

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#endif

void tcp_server(int port) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    socklen_t len;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

    [COLOR=seagreen]/* listen() - Auf eingehende Verbindungen warten */    if (listen(sockfd, 5) == -1) {
        perror("listen()");
    }

    [COLOR=seagreen]/* accept() - Die eingehende Verbindung annehmen */     socklen_t sin_size = sizeof(struct sockaddr_in);
    struct sockaddr_in remote_host;
    int sock2 = accept(sockfd, (struct sockaddr *)&remote_host, &sin_size);
    if (sock2 == -1) {
        perror("accept()");
    }

    [COLOR=seagreen]/* recv() - Empfangen mit TCP */    ssize_t msg_length;
    char buf[1024];
    if ((msg_length = recv(sock2, buf, 1024, 0)) == -1) {
        perror("recv()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));

   [COLOR=seagreen] /* close() - Socket freigeben */    int close(int sockfd); 
}

void tcp_client(char *data, int port, char *server_ip) {
   [COLOR=seagreen] /* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* connect() - Verbindung aufbauen */    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); 
    inet_aton(server_ip, &serv_addr.sin_addr);
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }

    [COLOR=seagreen]/* send() - Senden mit TCP */    char *msg = data;
    int len = strlen(msg);
    if (send(sockfd, msg, len, 0) == -1) {
        perror("send()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void udp_server(int port) {    
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind()");
    }
   [COLOR=seagreen] /* Zugewiesenen Port ermitteln: */    socklen_t len;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

    [COLOR=seagreen]/* recvfrom() - Empfangen mit UDP */    ssize_t msg_length;
    struct sockaddr_in remote_host;
    socklen_t clientlen;
    clientlen = sizeof(remote_host);
    char buf[1024];
    if ((msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &clientlen)) == -1) {
        perror("recvfrom()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void udp_client(char *data, int port, char *server_ip) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* sendto() - Senden mit UDP */    char *msg = data;
    int len = strlen(msg);
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); 
    inet_aton(server_ip, &serv_addr.sin_addr);
    if (sendto(sockfd, msg, len, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
        perror("sendto()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

[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 ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Server")==0)) {
        if (argc!=4) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            port = atoi(argv[3]);
            tcp_server(port);
        }
    } else if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Client")==0)) {
        if (argc!=5) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            tcp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
        if (argc!=4) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            port = atoi(argv[3]);
            udp_server(port);
        }
    } else if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Client")==0)) {
        if (argc!=5) {
            printf("Parameters missing or too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            fgets(data, size1, stdin);
            udp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
Jetzt will ich mich voll dem Segmentation fault widmen ... :)
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Und bezüglich der Anzahl der Parameter: Die steht in argc. Also z.B. einfach prüfen, wie viel Argumente der Nutzer dir übergeben hat. Oder du schaust ob der Nutzer dir mindestens 1 (argc==2) Argument übergeben hat und vergleichst dann das.
Habe bereits folgende beiden Varianten probiert. Hat aber beides nichts geändert:
Code:
int i=0;

while (argv[i]!=NULL) {
    i++;
}
if (i!=4 && i!=5) {
    printf("Missing or too many parameters!\n");
    return -1;
}
Code:
if (argc!=4 && argv!=5) {
    printf("Missing or too many parameters!\n");
    return -1;
}
^^ Mal schauen, ob mir sonst noch was einfällt ...
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Mach dir bitte nochmal klar, was argc und argv eigentlich sind...
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

^^ Das weiß ich ...

argc = Anzahl der Parameter
argv[x] = der x-te Parameter (bzw. Zeiger auf den x-ten Parameter)
*argv[] = Feld von Zeigern auf Zeichenketten

Bei mir scheitert's hier an der Idee, die Überprüfung, ob eh kein Parameter ein NULL-Pointer ist, VOR der Verwendung von strcmp durchzuführen ...
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Dann überleg mal, was nen Nullpointer ist, und was du von einem nicht initialisierten Speicherbereich erwarten darfst...

Und beim zweiten Code-Anschnitt würde ich mir mal die if-Bedingung anschauen, und überlegen, was ich da eigenltich mache. Da wolltest du nämlich garantiert was anderes machen.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

argc = Anzahl Parameter
Warum prüfst du dann nicht damit sondern versuchst dich an so komischen (und falschen!) Konstrukten wie dem hier?
Code:
int i=0;

while (argv[i]!=NULL) {
    i++;
}
if (i!=4 && i!=5) {
    printf("Missing or too many parameters!\n");
    return -1;
}
Code:
if (argc!=4 && argv!=5) {
    printf("Missing or too many parameters!\n");
    return -1;
}

Ziel: Prüfen, ob weniger als 4 oder mehr als 5 Parameter übergeben worden sind.
Gegeben: Anzahl übergebener Parameter in argc, Parameterliste in argv

In der Regel ist argc mindestens 1, da in argv[0] meist der Programmpfad/-name übergeben wird, d. h. der Prüfbereich erhöht sich um 1.

Code:
/* Falls weniger als 5 Argumente oder mehr als 6 breche das Programm ab */
if (argc < 5 || argc > 6)
{
    ...
}
Edit: Ich weiß jetzt nicht mehr, ob du schon den Offset für die richtige Anzahl Argumente drinnen hattest. Falls ja, zieh bei meinem Code wieder 1 ab.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

Das Problem ist einfach, das er immer irgendwas vor sich hinwurschtelt, ohne sich einmalig intensiv mit den Grundlagen beschäftigt zu haben.

Deswegen bin ich hier auch raus, weil das bringt einfach nichts.
 
AW: [C] Socket für TCP/UDP Übertragung programmieren

@ bingo88
Das löst aber das Problem immer noch nicht, weil ich VOR der Abfrage, ob der User einen Client od. einen Server gestartet hat, nicht weiß, ob eben 5 od. 4 Parameter benötigt werden. Wenn ich also 4 UND 5 Parameter als gültig zulasse und nur alles kleiner 4 und größer 5 ausschließe, dann könnte es aber beim Server immer noch passieren, dass ein Parameter ein Zeiger auf NULL ist, oder?

Ich weiß nicht, wie ich's noch anders beschreiben soll, aber man müsste irgendwie wissen, ob ein Server gestartet wird, dann könnte man auf argc==4 überprüfen, oder, wenn man wüsste, dass ein Client gestartet wird, auf argc==5 ...

Ich überlege noch weiter ... vielleicht könnte man das Segmentation fault auch umgehen, wenn man statt strcmp eine andere Lsg finden würde?!
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Wie wär's denn damit:

Wurde das Programm mit 4 Parametern aufgerufen? Falls ja, ist das dritte Argument denn "Server"? Falls nein, Tschüss...
Sonst: Wurde das Programm mit 5 Parametern aufgerufen? Falls ja, ist das dritte Argument denn "Client"? Falls nein, Tschüss...

(Das ist quasi dein
Ich weiß nicht, wie ich's noch anders beschreiben soll, aber man müsste irgendwie wissen, ob ein Server gestartet wird, dann könnte man auf argc==4 überprüfen, oder, wenn man wüsste, dass ein Client gestartet wird, auf argc==5 ...
, bloß umgekehrt - ich schau erst, ob argc==4, und DANN schau ich ob's ein Server werden soll - liegt ein Fehler vor, tschüss..)


Alternativ (so wie bingo88 angefangen hat) kannst du natürlich erstmal prüfen ob die Argumentzahl irgendwie hinhaut, und dann noch weiter verschachteln.

Bin mir grad bei der Reihenfolge der Argumente nicht sicher, also evtl nochmal durchzählen, aber das Grundprinzip sollte klar sein. Die Fallunterscheidungen lassen sich natürlich beliebig komplex umformulieren...

Und bzgl. des Prüfens, ob argv[X] == NULL: Ich hab sowas eigentlich noch nie gesehen, natürlich durchaus möglich, dass das geht, aber warum so eine "tolle" Lösung nehmen, wenn man doch argc hat...
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Ich hab's jetzt mal so gemacht:
Code:
#define _GNU_SOURCE

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#endif

void tcp_server(int port) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    socklen_t len=0;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

    [COLOR=seagreen]/* listen() - Auf eingehende Verbindungen warten */    if (listen(sockfd, 5) == -1) {
        perror("listen()");
    }

    [COLOR=seagreen]/* accept() - Die eingehende Verbindung annehmen */     socklen_t sin_size = sizeof(struct sockaddr_in);
    struct sockaddr_in remote_host;
    int sock2 = accept(sockfd, (struct sockaddr *)&remote_host, &sin_size);
    if (sock2 == -1) {
        perror("accept()");
    }

    [COLOR=seagreen]/* recv() - Empfangen mit TCP */    ssize_t msg_length;
    char buf[1024];
    if ((msg_length = recv(sock2, buf, 1024, 0)) == -1) {
        perror("recv()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void tcp_client(char *data, int port, char *server_ip) {
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* connect() - Verbindung aufbauen */    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); 
    inet_aton(server_ip, &serv_addr.sin_addr);
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }

    [COLOR=seagreen]/* send() - Senden mit TCP */    char *msg = data;
    int len = strlen(msg);
    if (send(sockfd, msg, len, 0) == -1) {
        perror("send()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void udp_server(int port) {    
    [COLOR=seagreen]/* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    socklen_t len=0;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

    [COLOR=seagreen]/* recvfrom() - Empfangen mit UDP */    ssize_t msg_length;
    struct sockaddr_in remote_host;
    socklen_t clientlen;
    clientlen = sizeof(remote_host);
    char buf[1024];
    if ((msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &clientlen)) == -1) {
        perror("recvfrom()");
    }
    int i=0;
    printf("message: ");
    while (i<msg_length) {
        printf("%c", buf[i]);
        i++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

void udp_client(char *data, int port, char *server_ip) {
   [COLOR=seagreen] /* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    [COLOR=seagreen]/* sendto() - Senden mit UDP */    char *msg = data;
    int len = strlen(msg);
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); 
    inet_aton(server_ip, &serv_addr.sin_addr);
    if (sendto(sockfd, msg, len, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
        perror("sendto()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}

[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);
            [COLOR=royalblue][B]free(data);
            free(server_ip);[/B]        } 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);
            [COLOR=royalblue][B]free(data);
            free(server_ip);[/B]        }
    } else if (argc<4 || argc>5) {
        printf("Missing or too many parameters!\n");
        return -1;
    }

    return 0;
}
Das "Segmentation fault" kommt allerdings immer noch. Nur geht aus valgrind nicht mehr hervor, ob's nach wie vor am strcmp liegt, oder an was anderem:

Capture.JPG

[EDIT]
Scheinbar liegt's jetzt am malloc ...

Capture.JPG

^^ Wieso sagt der eigentlich "0 frees"? Ich habe ja extra 2 Mal free() im Code?!
 
Zuletzt bearbeitet:
AW: [C] Socket für TCP/UDP Übertragung programmieren

Der Segfault der hier Auftritt ist kein Segfault. Valgrind sagt dir hier schlicht und ergreifend, dass du nicht allen Speicher den du mit {m,c,re,...}alloc geholt hast, auch wieder freigegeben hast.
Code:
==5630== HEAP SUMMARY:
==5630==     [b]in use at exit[/b]: 5,120 bytes in 2 blocks
==5630==   total heap usage: 2 allocs, [b]0 frees[/b], 5,120 bytes allocated
==5630== 
==5630== LEAK SUMMARY:
==5630==    [b]definitely lost: 5,120 bytes in 2 blocks[/b]

Es gehört sich eigentlich, jeglichen Speicher den man allokiert, auch wieder freigibt.

Wenn du jetzt, wie vorgeschlagen, --leak-check=full setzt, kommen wir schon weiter:
Code:
==5631== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 2
==5631==    at 0x4C2C63B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==5631==    by 0x401244: main (in /home/matthias/a.out)                                                                                                     
==5631==                                                                                                                                                    
==5631== 4,096 bytes in 1 blocks are definitely lost in loss record 2 of 2
==5631==    at 0x4C2C63B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==5631==    by 0x401233: main (in /home/matthias/a.out)
.

Jetzt stellen wir fest, dass das noch reichlich ungenau ist. Also sagen wir unserem Compiler mit "-g", dass er doch bitte Debugging Informationen in die Binärdatei packen soll.
Nach einem erneuten Valgrind lauf sehen wir:
Code:
==5637== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 2
==5637==    at 0x4C2C63B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==5637==    by 0x401244: main (test.c:168)
==5637== 
==5637== 4,096 bytes in 1 blocks are definitely lost in loss record 2 of 2
==5637==    at 0x4C2C63B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==5637==    by 0x401233: main (test.c:167)
Hier sehen wir die Zeilen in denen wir Speicher angefordert haben, den wir nie wieder freigeben. Über sowas sollte man sich aber eigentlich schon beim Schreiben des Programmes gedanken machen.

Wieso sagt der eigentlich "0 frees"? Ich habe ja extra 2 Mal free() im Code?!
Und das nützt dir genau wie viel, wenn du diese Stellen durch gekonntes Platzieren von "if" umgehst? Womit wir auch mal wieder beim Thema wären: Warum legst du die beiden Speicherbereiche nicht einfach auf den Heap? Also char data[4096]; << kein free mehr notwendig. Wenn du später noch dynamische Feldgrößen brauchst, dann ok, aber sonst...
 
Zuletzt bearbeitet:
Zurück