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



## boss3D (18. Januar 2013)

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

Hi @ all!

Folgende Aufgabe:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Dazu haben wir auch 3 virtuelle Maschinen (NET1UE-Client, NET1UE-Server, NET1UE-Router) bekommen, alle 3 mit Debian. Ich arbeite dabei mit dem VMWare Player und putty. In die Client und die Server VM muss ich dann meinen Code einfügen und dann ausführen. Dann müsste das laufen.

So sieht der Netzplan aus:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Und so natürlich eine TCP/UDP Datenübertragung:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Entsprechend der Aufgabe a habe ich jetzt erstmal die nötigen Funktionen versucht nach diesem HowTo zu programmieren, v.a. weil's da auch recht schön erklärt wird, was eigentlich wo passiert. 

Hier mein aktueller Code:

```
#include <stdio.h>
#include <errno.h>
#include <string>
#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

int main(int argc, char *argv[]) {
    [COLOR=seagreen]/* Client: */
   [COLOR=seagreen] /* socket() - Socket anfordern */    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
    }

    [COLOR=seagreen]/* connect() - Verbindung aufbauen */    sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(80);
    serv_addr.sin_addr.s_addr = inet_addr("192.168.3.1/24");
    servent* serviceinfo = getservbyname ("http", "tcp");
    serv_addr.sin_port = serviceinfo->s_port;
    if (connect(sockfd, (sockaddr *) &serv_addr, sizeof(sockaddr)) == -1) {
        perror ("connect()");
    }

    [COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */    char *msg = "Test-Nachricht.\n";
    int len = strlen (msg);
    if (send (sockfd, msg, len, 0) == -1) {
        perror ("send()");
    }

    char buf[1024];
    if (recv (sockfd, buf, 1024, 0) == -1) {
        perror ("recv()");
    }

    [COLOR=seagreen]/* sendto() und recvfrom() - Senden und Empfangen mit UDP */    [COLOR=red][B]XXX[/B]

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int fd); [COLOR=seagreen]/* closesocket() für Windows */
    [COLOR=seagreen]/*-----------------------------------------------------------------*/    [COLOR=seagreen]/* Server: */
    [COLOR=seagreen]/* bind() - Den eigenen Port festlegen */    sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(5000);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1) {
        perror ("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    [B][COLOR=red]socklen_t[/B] len;
    getsockname(sockfd, (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 */    [COLOR=red][B]socklen_t[/B] sin_size = sizeof (sockaddr_in);
    sockaddr_in remote_host;
    int sock2 = accept (sockfd, (sockaddr *) &remote_host, &sin_size);
    if (sock2 == -1) {
        perror ("accept()");
    }

    return 0;
}
```
^^ Nicht wundern wegen der vielen Bibliotheksfunktionen. Da ich im Visual Studio programmiere, musste alles für Windows rein und weil's dann aber später unter Debian laufen soll, auch alles für Linux/Unix. Durch's if/else kann der Compiler eh schön unterscheiden und sich das holen, was er braucht.

So, und jetzt zu meinen Fragen:

1.) Wo die drei roten fetten XXX sind, was genau muss dahin? Das ist das einzige, was ich aus dem HowTo nicht wirklich herauslesen konnte. Da stand nur irgendwas von wegen so ähnlich wie's normale send() und recv(), aber mit ein paar zusätzlichen Zeilen?!

2.) socklen_t wird mir im Visual Studio rot unterwellt und als undefined beschrieben. In welcher Bibliotheksfunktion, die ich noch nicht eingebunden habe, soll das denn drinnen sein? Durch googeln bin ich auch nicht schlauer geworden. Wenn's allerdings nur unter Windows nicht gefunden wird, unter Linux dann aber schon, wäre es eh halb so wild. 

3.) Was ich dann noch bräuchte, wäre irgendwas, wo der User über Parameter, die direkt an die main übergeben werden, auswählen kann, ob er Client oder Server sein will und ob ein beliebiger Text (ebenfalls als Parameter) per TCP oder UDP übertragen werden soll. Auch der entsprechende Port soll beim Server mitübergeben werden. Eben so, wie's in der Angabe steht. Da weiß ich noch nicht so recht, wie ich das machen soll ...

Irgendwie so vielleicht:

```
int main(int argc, char *argv[]) {
    if (argv[1]=="Client") {
        if (argv[2]=="TCP") {
            [COLOR=seagreen]// Client-TCP Code        } else if (argv[2]=="UDP"){
            [COLOR=seagreen]// Client UDP-Code        }
    } else if (argv[1]=="Server") {
        if (argv[2]=="TCP") {
            [COLOR=seagreen]// Server-TCP Code        } else if (argv[2]=="UDP"){
            [COLOR=seagreen]// Server-UDP Code        }
    }
    
    return 0;
}
```
^^ Nur, dass das so enorm viel Code werden würde, weil ich ja fast alles dann mindestens doppelt drinne hätte. Das kann's ja nicht sein?!

4.) Der Lehrer hat gemeint, einen wirklich minimalen Code für diese Aufgabe könnte man auch mit ~ 40 Zeilen schreiben, sodass der immer noch die Aufgabenstellung erfüllt. Ergo muss ich ja jede Menge "unnützes" Zeug drinnen haben?! Kann mir da jemand bitte beim "Ausmisten" helfen?! Was brauche ich denn alles eigentlich gar nicht? Im Übrigen ist der Code aus dem HowTo wahrscheinlich eh nicht 1:1 für meine Aufgabenstellung brauchbar. Hier und da (z.B. bei den IP-Adressen --> siehe Netzplan oben) bräuchte ich auch noch ein Bisschen Hilfe beim Anpassen, bitte.

Danke für baldige Antworten!


----------



## Battl3inSeattle (18. Januar 2013)

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

1. Ich würde in die main() eine Art Menü machen, dass die ganzen Eingaben erwartet. Je Nach Eingabe (TCP oder UDP? Client oder Server?) würde ich dann eine Funktion starten. Also zum Beispiel TcpServer(int Port). So ist alles schön getrennt.

Das gehört in sendto():
-Parameter 1: Socket über den wir die Daten senden wollen
-Parameter 2: Pointer auf einen Buffer der die zu sendenden Daten enthält
-Parameter 3: Wieviele Zeichen von buf gesendet werden sollen
-Parameter 4: benötigen wir nicht, auf 0 setzten
-Parameter 5: in unserem Falle ein Pointer auf eine SOCKADDR_IN Struktur die Informationen über den Zielrechner enthält
-Parameter 6: länge von to, in userem Fall sizeof(SOCKADDR_IN)

(Quelle: Winsock Tutorial: UDP)

2. Weiß ich leider nicht.

3. Ich wiederhole nochmal meinen Vorschlag, mach' es mit verschiedenen Funktionen. Das ist auch effizienter. So fallen die ganzen if() weg.

4. Ja, wenn man Schleifen Beispielsweise so schreibt (also ohne { bzw. } - Liest nur die erste Nachfolgende Zeile in einer Schleife):

for(int WasWeißIch; WasWeißIch < 0; WasWeißIch++)
Anweisung;

Mach's lieber lang und übersichtlich, scheiß drauf wie viele Zeilen du schreibst, du musst es verstehen, es muss effizient sein und du solltest es auch in einigen Monaten noch verstehen können (Kommentare!).


----------



## boss3D (20. Januar 2013)

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

Ok, danke schon mal für die Antwort! Ich bin mir nicht sicher, ob ich alles kapiert habe, und da ich gerade in der Klausurwoche bin, kann ich mich im Moment auch nicht mit der Aufgabe beschäftigen. Ich hab's nur jetzt schon reingestellt, damit vielleicht mehrere Leute was hilfreiches posten bis ich dann Zeit habe, das fertig zu machen. 

Sobald ich mich wieder darum kümmee, tauchen sicher noch genug Fragen auf ...

^^ Ich melde mich dann wieder.


----------



## Skysnake (21. Januar 2013)

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

Zu 2.

Du programmierst auf Windows, und hast damit nicht zwingend die Linux Sourcen. Ich weiß jetzt nicht 100%, ob das in den Linux-kerner-Sourcen drin ist, bin mir da aber relativ sicher. 

PS:
Ich hab mal google gefragt. Direkt der erste Link <sys/socket.h>

Wenn du irgendwas "xy_t" findest, dann ist das eigentlich immer ein Datentype. Meist/Immer sind das portable Datentypen, die dafür sorgen, das es egal ist, ob man auf einer 32 oder 64Bit Maschine das Zeug laufen lässt.

Du musst also "nur" die <sys/socket.h> includieren. Die wirst du unter Windows aber nicht haben, es sei denn du lädst dir die Kernel-Sourcen runter.

Wenn du für Linux entwickelst, solltest du auch UNTER/AUF Linux entwickeln. Das macht es sehr viel einfacher, zumal man die Sachen auch gleich testen kann. In dem Zuge kannst du dir auch mal gleich "Makefiles" durchlesen, das ist am Anfang zwar etwas seltsam, macht die Arbeit aber VIEL einfacher und schneller, wenn man mal weiß, wie Makefiles zu bauen sind.


----------



## boss3D (4. Februar 2013)

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

Ich habe das Ganze jetzt auf 4 Funktionen verteilt. Ein paar Fragen hätte ich erst einmal zum TCP Server ...

```
#include <stdio.h>
#include <errno.h>
#include <string>
#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 */    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, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    [COLOR=royalblue][B]socklen_t len;
    getsockname(sockfd, (sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));[/B]
    [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(sockaddr_in);
    sockaddr_in remote_host;
    int sock2 = accept(sockfd, (sockaddr *)&remote_host, &sin_size);
    if (sock2 == -1) {
        perror("accept()");
    }

    [COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */   [COLOR=royalblue][B] char *msg = "Testmessage.\n";[/B]    int len = strlen(msg);
    if (send(sockfd, msg, len, 0) == -1) {
        perror("send()");
    }
    char buf[1024];
    if (recv (sockfd, buf, 1024, 0) == -1) {
        perror("recv()");
    }

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

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Textnachricht, Server-IPv4-Adresse, Port */[COLOR=seagreen]/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int port;

    if (argv[1]=="TCP" && argv[2]=="Server") {
        port = *argv[3];
        tcp_server(port);
    } else if (argv[1]=="TCP" && argv[2]=="Client") {
        tcp_client();
    } else if (argv[1]=="UDP" && argv[2]=="Server") {
        udp_server();
    } else if (argv[1]=="UDP" && argv[2]=="Client") {
        udp_client();
    }

    return 0;
}
```
1.) Bei den ersten 3 fetten blauen Zeilen: Brauche ich das eigentlich, wenn ich eh den Port als Parameter an main und danach an die Funktion tcp_sever() übergebe? Oder ist das der port, den bind() festlegt und nicht der, den ich übergebe?

2.) Laut Aufgabe a (siehe Startposting) soll ja der TCP Sever eine Textnachricht vom Client erhalten und diese ausgeben. Wo genau muss ich die Ausgabe reinbasteln? Ich vermute mal, in send() und recv()?! Dann brauche ich ja dort die fette blaue Zeile nicht, oder? Bzw. ich müsste char *msg die übertragene Textnachricht zuweisen und dann msg ausgeben lassen?! Wie genau mache ich das?


----------



## -Phoenix- (4. Februar 2013)

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

Moin,
die Ausgabe musst du nach recv machen (bedenke aber das es sich um eine Bytestream Übertragung handelt) . Ich sehe aber gerad einen ganz anderen Fehler bei dir Send und Recv müssen mit deinem neuen Socketdesktriptor (der von Accept zurückgegeben wird ) arbeiten nicht mit dem alten.

Deine erste Frage versteht ich nicht ganz. Den Port setzt du ja in deinem Struct und das übergibst du an Bind, danach lässt sich der Port auf den die Nachrichten empfangen werden sollen nicht mehr ändern. Aber mir sagt jetzt auch die Funktion getsockname() nichts, die habe ich selber bei meinen TCP/ UDP Programmen fürs Studium nicht benötigt. Btw. Studierst du auch AI ? Die Aufgabenstellung ist aufjedenfall fast so wie bei mir 

Lg.


----------



## boss3D (4. Februar 2013)

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

Ah, du meinst sock2 statt sockfd?! Gut, und für die Ausgabe muss ich vermutlich den Inhalt des Buffers ausgeben, oder? Was mache ich dann mit diesem msg? Das brauche ich dann ja für nichts mehr, oder?

```
[COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */    char *msg = "Testmessage.\n";
    int len = strlen(msg);
    if (send(sock2, msg, len, 0) == -1) {
        perror("send()");
    }
    char buf[1024];
    if (recv(sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int x=0;
    while (x!=1024) {
        printf("%c", buf[x]);
        x++;
    }
```
^^ Oder muss ich die übertragene Nachricht in msg speichern und dann msg ausgeben?

BTW: Was ist AI? Ich studiere IT Security. 
*
[EDIT]*
Ein Problem bleibt noch: Beim Compilieren unter Linux (gcc -o tcpserver tcpserver.c) werden jede Menge Syntax-Fehler gefunden, die Visual Studio unter Windows nicht findet. 


Spoiler





```
#include <stdio.h>
#include <errno.h>
#include <string>
#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 */    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, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1) {
        perror("bind()");
    }
    [COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    socklen_t len;
    getsockname(sockfd, (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(sockaddr_in);
    sockaddr_in remote_host;
    int sock2 = accept(sockfd, (sockaddr *)&remote_host, &sin_size);
    if (sock2 == -1) {
        perror("accept()");
    }

    [COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */    char *msg = "Testmessage.\n";
    int len = strlen(msg);
    if (send(sock2, msg, len, 0) == -1) {
        perror("send()");
    }
    char buf[1024];
    if (recv (sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int x=0;
    while (x!=1024) {
        printf("%c", buf[x]);
        x++;
    }

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

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Textnachricht, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int port;

    if (argv[1]=="TCP" && argv[2]=="Server") {
        port = *argv[3];
        tcp_server(port);
    } 

    return 0;
}
```






			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Wie bringe ich die weg? Ich sehe da selbst gar keine Fehler in den Zeilen wo gcc meint, da würde was nicht passen. 

Und bevor wieder einer meint, ich solls gleich unter Linux programmieren: Ich habe hier nur eine Debian VM ohne grafische Oberfläche. Geht daher irgendwie schlecht.


----------



## Olstyle (4. Februar 2013)

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

Mit nano kann man durchaus brauchbar coden .
Davon abgesehen ist eine VM mit nem Linux inklusive grafischer Oberfläche schnell aufgesetzt.(bzw. mit ein apt-get install "gewünsche Oberfläche" sollte nach ner kleine Installationsorgie auch auf der vorhandene VM eine GUI auftauchen).

Zu deinen Problemen: _sockaddr_in_ ist ein struct, also muss das da auch stehen . Die anderen Fehler beziehen sich in erster Linie auf die Folgen von der falschen Initialisierung an der Stelle.


----------



## boss3D (4. Februar 2013)

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

^^ So ungefähr bin ich eh bis jetzt auch schon vorgegangen: Mit putty drauf auf die VM, dann mit nano ein leeres C file erstellen und über putty den Code aus dem Visual Studio da rein kopieren ...

Ich habe auch vor 3 Tagen Debian mit GUI in einer VM installiert, weil ich mir gedacht hatte, gut, da dann noch Eclipse drauf und es kann los gehen, aber ich hab's um's Verrecken nicht hingebracht, das nötige C-Plugin zu installieren, sodass ich Eclipse überhaupt für C Code hätte nutzen können.

*[EDIT]*
Die fehlenden struct Wörter habe ich noch hinzugefügt. Das hat schon mal viele Fehler behoben. Nur 4 sind mir geblieben, wo ich nicht weiß, was da jetzt wieder nicht passt:


Spoiler





```
#include <stdio.h>
#include <errno.h>
#include <string>
#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: */    struct 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 */    struct 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]/* send() und recv() - Senden und Empfangen mit TCP */    char *msg = "Testmessage.\n";
    int len = strlen(msg);
    if (send(sock2, msg, len, 0) == -1) {
        perror("send()");
    }
    char buf[1024];
    if (recv (sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int x=0;
    while (x!=1024) {
        printf("%c", buf[x]);
        x++;
    }

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

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Textnachricht, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int port;

    if (argv[1]=="TCP" && argv[2]=="Server") {
        port = *argv[3];
        tcp_server(port);
    } 

    return 0;
}
```






			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Und wenn wir die noch wegbringen, bleibt noch das mit der Ausgabe des empfangenen Texts zu klären. Dann müsste zumindest der TCP-Server Teil mal fertig sein?!


----------



## Olstyle (5. Februar 2013)

Ich programmier in der Regel mit Geany. Das kann alles was ich brauch, Eclipse ist nur überladen.

Falls du es nicht schon getan hast kann ich dir noch empfehlen hier nach zu lesen:
http://openbook.galileocomputing.de/linux_unix_programmierung/

(Wenn die Fehler noch da sind wenn ich wieder mit nem PC online bin sag ich vielleicht noch was dazu.)


----------



## -Phoenix- (5. Februar 2013)

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

Moin,
AI Ist Angewandte Informatik.

```
[COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */     
char *msg = "Testmessage.\n";     
int len = strlen(msg);     
if (send(sock2, msg, len, 0) == -1) {         
perror("send()");     }     
char buf[1024];     
if (recv(sock2, buf, 1024, 0) == -1) {         
perror("recv()");     }     
int x=0;     
while (x!=1024) {         
printf("%c", buf[x]);         
x++;     
}
```
vor send muss die Nachricht in msg stehen und nach recv steht die empfangene Nachricht in buf.

Zu deinen Fehlern:
Wegen dem strlen versuchs mal mit #include <string.h> anstatt #include <string>.
Änder vll mal den Typ von len nach  size_t .
Zu sin_size du musst sin_size = sizeof(remote_host).


> The _addrlen_  argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by _addr_;  on return it will contain the actual size of the peer address.


 Linux Howtos: manpages: accept(2)


Lg.


----------



## Skysnake (5. Februar 2013)

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



boss3D schrieb:


> Ein Problem bleibt noch: Beim Compilieren unter Linux (gcc -o tcpserver tcpserver.c) werden jede Menge Syntax-Fehler gefunden, die Visual Studio unter Windows nicht findet.


Ja, weil da auch Syntaxfehler SIND! Visual Studio ist nur EXTREM umgänglich, was eigentlich falschen Code anbelangt... Das heißt aber nicht, das in größeren Projekten dann auch VS die Sachen nicht mehr packt und scheise baut. Genau so, das nicht irgend ein Mist während der Laufzeit passiert...

Deswegen soll man auch nicht den VS benutzen, wenn man anfängt, und in der Uni schon gleich 10 mal nicht... Dein Programmierstiel wird da einfach verdorben....




> ^^ Wie bringe ich die weg? Ich sehe da selbst gar keine Fehler in den Zeilen wo gcc meint, da würde was nicht passen.


Indem du den ersten Fehler suchst, und dann google bemühst... Und nein, das ist kein Scherz. Das muss man lernen, wie man nach Fehlermeldungen googeld. Mit der Zeit weißt du dann auch so ~10 Seiten, die die Standardanlaufstellen für gewisse Fehler sind. Das soll jetzt nicht heisen, das man nicht fragen darf, aber das hier sind keine wirklich schweren Fehler, UND du studierst, also solltest du solche Fehler selbst finden können. Ich seh da aber schon negative Einflüsse von VS...



> Und bevor wieder einer meint, ich solls gleich unter Linux programmieren: Ich habe hier nur eine Debian VM ohne grafische Oberfläche. Geht daher irgendwie schlecht.


 Für was braucht man bitte ne grafische Oberfäche zum programmieren? Klar, die Syntaxvervollständigung unter VS ist cool, aber bei den kleinen Projekten, die du hast, ist das voll fürn Arsch. Das kann man sich noch merken. Unter Linux entweder nano, oder vim verwenden. Ich nutze ja vim, und das kann man auch dazu bringen, einem die möglichen Variablennamen anzuzeigen. Ist zwar etwas Aufwand ein zu richten, weshalb ich es noch nie gemacht habe, da es sich für mich nie gelohnt hat, man kann es aber machen.

Entwickel einfach gleich auf Linux, dann hast du viele Probleme weniger. Von Windows -> Linux ist oft nicht einfach zu portieren, weil man "dank" VS geschlampt hat. Linux -> Windows ist die portierung SEHR einfach. Das geht meist ohne jegliches Problem.


----------



## bingo88 (5. Februar 2013)

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

Bei dem Ansatz, den du da verfolgst (In VS schreiben, dann "nach gcc kopieren") hast du das Problem, dass Visual Studio von Haus aus im C++ Modus arbeitet, während gcc C erwartet (g++ ist für C++). Und in C geht einiges nicht, was in C++ geht  Ein paar Beispiele:

```
// In C++ (und C neueren Datums; C99?) ok, in C nicht.
for (int i = 0; i < count; ++i)
{
    ...
}

/* Valider C Code */
/* (Variablen müssen vor allen anderen Instruktionen deklariert werden) */
int i;
for (i = 0; i < count; ++i)
{
    ...
}


typedef struct Bla
{
    int foo;
    int bar;
} Bla_t;


void func1()
{
    struct Bla meinBla; /* In C und C++ ok */
    Blat_t meinBla2; /* Auch in C und C++ ok, da typedef */
    Bla meinBla3; /* Ok in C++, C mag das so nicht */
}
```
Wie gesagt, einige Dinge funktionieren in C wenn man einen neueren Standard auswählt (bspw. C99), aber da muss man halt auch dran denken. Abgesehen davon ist, wie Skysnake schon sagte, VS auch äußerst gnädig was Fehler angeht. Linux + Texteditor + gcc ist zum Verständnis wesentlich besser geeignet


----------



## Skysnake (5. Februar 2013)

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

Hey, ich hab ja auch gemeint mit VS anfangen zu müssen.... VOR dem Studium halt...

Die Quittung dafür habe ich im Studium bekommen, wo ich dann knapp ein Jahr gebraucht habe, um die Schnitzer aus VS aus meinem Kopf raus zu bekommen... Das hätte ich mir wirklich sparen können...


----------



## boss3D (5. Februar 2013)

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



-Phoenix- schrieb:


> ```
> [COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */
> char *msg = "Testmessage.\n";
> int len = strlen(msg);
> ...


Ok, nur wo nehme ich die Nachricht für msg her? Ich programmiere ja jetzt erstmal den Server und der weiß ja nicht, was ihm der Client schicken wird?! Irgendwas anderes muss auf jeden Fall statt "Testmessage.\n" hin, nur habe ich noch nicht ganz durchschaut, was. Die Textnachricht vom Client muss irgendwie in char *msg rein ...


-Phoenix- schrieb:


> Zu deinen Fehlern:
> Wegen dem strlen versuchs mal mit #include <string.h> anstatt #include <string>.


Ok, das hat das warning und einen error weggebracht.


-Phoenix- schrieb:


> Änder vll mal den Typ von len nach  size_t .


Dann kommt die gleiche Meldung, nur diesmal eben für size_t:



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




-Phoenix- schrieb:


> Zu sin_size du musst sin_size = sizeof(remote_host).


Damit kommen nur noch mehr Fehlermeldungen:



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




Skysnake schrieb:


> Deswegen soll man auch nicht den VS benutzen,  wenn man anfängt, und in der Uni schon gleich 10 mal nicht... Dein  Programmierstiel wird da einfach verdorben....


Mag ja sein, dass du recht hast, aber wir haben Visual Studio sogar von der Uni bekommen und ein ganzes Semester lange damit Programmieren gelernt. 


Skysnake schrieb:


> Indem du den ersten Fehler suchst, und dann  google bemühst... Und nein, das ist kein Scherz. Das muss man lernen,  wie man nach Fehlermeldungen googeld.


Ich hab gegoogelt bevor ich gepostet habe. Hätte ich die Fehler dadurch beheben können, würde ich ja hier nicht schreiben.


bingo88 schrieb:


> Bei dem Ansatz, den du da verfolgst (In VS  schreiben, dann "nach gcc kopieren") hast du das Problem, dass Visual  Studio von Haus aus im C++ Modus arbeitet, während gcc C erwartet (g++  ist für C++). Und in C geht einiges nicht, was in C++ geht


So schlau bin ich schon! Ich habe natürlich bei Compiler im VS "C" eingestellt und auch an den Filenamen ein .c angehängt. 

Außerdem schreibe ich jetzt den Code eh nur mehr im Notepad++ und kopiere Änderungen via putty in mein nano file in der VM rein ... oder mache kleinere Änderungen gleich dort.


----------



## Skysnake (5. Februar 2013)

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

GZ, du hast nicht verstanden, was er meinte...

Es gibt mehrere C Standards. Der GCC nimmt im normalfall der restregtivsten. Du darst da z.B. Variablen nur am Anfang definieren usw usw. 

Ein 

```
for(int i=0; i<10; i++)
```
funktioniert da z.B. gar nicht zwingend. Du musst vorher C99 (oder wie das auch noch immer heisen mag) aktivieren. Erst dann sind solche Sachen auch mit dem GCC möglich.


----------



## bingo88 (5. Februar 2013)

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

Ja, das vermute ich momentan auch. Du musst deine Variablen am Anfang der Funktion deklarieren, mittendrin geht bei klassischem C nicht.

```
void foo()
{
    ...
    size_t len; /* das geht in klassischem C nicht! */
    ...
}

void foo()
{
    size_t len; /* Variablen müssen vor allen Instruktionen deklariert werden */
    ...
}
```
Da du die Variablen im laufenden Code deklarierst, kann es sein, dass er die deshalb nicht findet. Die Fehlermeldungen bei C/C++ sind manchmal nicht ganz so aussagekräftig, wie man das vielleicht gern hätte.


----------



## Skysnake (5. Februar 2013)

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

und deswegen meinte ich ja "man muss lernen Fehlermeldungen zu googlen". Ich sitz auch oft genug vorm PC und frag mich, was denn jetzt wieder mal in die Hosen geht...

Geil wirds vor allem, wenn man MB weise Fehlermeldungen bekommt  DAS ist lustig zu debuggen... Und teilweise ist es dann nur nen popel Fehler in irgend einer Libary oder so


----------



## bingo88 (5. Februar 2013)

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



Skysnake schrieb:


> und deswegen meinte ich ja "man muss lernen Fehlermeldungen zu googlen". Ich sitz auch oft genug vorm PC und frag mich, was denn jetzt wieder mal in die Hosen geht...


 Ich bin mir ziemlich sicher, dass es die Meldung genau so gibt, wenn man vergisst, einen Header einzubinden. Schön sind dann auch die von Visual Studio ins Deutsche übersetzten Fehlermeldungen *hust*



Skysnake schrieb:


> Geil wirds  vor allem, wenn man MB weise Fehlermeldungen bekommt  DAS ist  lustig zu debuggen... Und teilweise ist es dann nur nen popel Fehler in  irgend einer Libary oder so


 Japp, fehlendes Include(-verzeichnis) oder ne Library vergessen und 15.687 Fehlermeldungen bestaunden


----------



## Skysnake (5. Februar 2013)

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

Ne, ich mein schon ECHTE Fehler in ner Libary 

DAS ist ein Spaß bei MPI Programmen


----------



## boss3D (5. Februar 2013)

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



bingo88 schrieb:


> Du musst deine Variablen am Anfang der Funktion deklarieren, mittendrin geht bei klassischem C nicht. Da du die Variablen im laufenden Code deklarierst, kann es sein, dass er die deshalb nicht findet.


Nein, das hat auch nichts gebracht. Außerdem müsste er dann auch bei anderen Variablen Fehlermeldungen bringen, nicht nur bei diesem struct socklen_t len. Dann dürfte ihm z.B. das int len ein Bisschen weiter unten auch nicht recht sein ...

Und das mit dem sin_size habe ich auch noch nicht weggebracht.

*[EDIT]*
Bin schon am Überlegen, ob ich den Teil, also diese 3 Zeilen, die einen zugewiesenen Port ermitteln sollen, überhaupt brauche ...

```
[COLOR=seagreen]/* Zugewiesenen Port ermitteln: */    struct socklen_t len;
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));
```


----------



## bingo88 (5. Februar 2013)

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



boss3D schrieb:


> Nein, das hat auch nichts gebracht. Außerdem müsste er dann auch bei anderen Variablen Fehlermeldungen bringen, nicht nur bei diesem struct socklen_t len. Dann dürfte ihm z.B. das int len ein Bisschen weiter unten auch nicht recht sein ...


Nicht wenn der Compiler vorher abbricht. War ein Versuch wert ^^

Ich habe das mal eben auf meiner Linux Box ausprobiert:

```
#include <stdio.h>
#include <errno.h>
#include <string[B].h[/B]>
#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) {
    /* socket() - Socket anfordern */
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket()");
    }

    /* 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()");
    }
    /* Zugewiesenen Port ermitteln: */
    [STRIKE]struct[/STRIKE] socklen_t len; [B]/* das ist kein struct */[/B]
    getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
    printf("Port: %d\n", ntohs(my_addr.sin_port));

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

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

    /* send() und recv() - Senden und Empfangen mit TCP */
    char *msg = "Testmessage.\n";
    int len[B]2[/B] = strlen(msg); [B]/* du hast schon eine Variable mit dem Namen len */[/B]
    if (send(sock2, msg, len[B]2[/B], 0) == -1) {
        perror("send()");
    }
    char buf[1024];
    if (recv (sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int x=0;
    while (x!=1024) {
        printf("%c", buf[x]);
        x++;
    }

    /* close() - Socket freigeben */
    [STRIKE]int close(int fd);[/STRIKE]
[B]     close(sockfd);[/B]
}

/* Parameter: UDP/TCP, Client, Textnachricht, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */
int main(int argc, char *argv[]) { 
    int port;

    if (argv[1]=="TCP" && argv[2]=="Server") {
        port = *argv[3]; [B]/*nee, guck dir mal atoi() an. Hier weist du den int-Wert des ersten Characters als Port zu */[/B]
        tcp_server(port);
    } 

    return 0;
}
```
bei mir kompiliert das (GCC 4.7.2)


----------



## -Phoenix- (5. Februar 2013)

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



> Ok, nur wo nehme ich die Nachricht für msg her? Ich programmiere ja  jetzt erstmal den Server und der weiß ja nicht, was ihm der Client  schicken wird?! Irgendwas anderes muss auf jeden Fall statt  "Testmessage.\n" hin, nur habe ich noch nicht ganz durchschaut, was. Die  Textnachricht vom Client muss irgendwie in char *msg rein ...



Du kannst ja eine Anmeldebestätigung in Form einer Textnachricht an den Client schicken. Bsp. Client 127.0.0.1 hat sich Erfolgreich beim Server angemeldet. Oder du machst gar keine Ausgabe bei Server und wartest erst mal auf eine Nachricht des Clients und antwortest dann darauf.

Lg.


----------



## boss3D (5. Februar 2013)

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

@ bingo88
Ok, danke, bis auf ein warning, das wir ignorieren können, kompiliert das jetzt auch bei mir. Ich überlege mir das jetzt mit atoi(), damit auch tatsächlich der als Parameter an main übergebene Port an die Funktion übergeben wird.

@ -Phoenix-
Ich kann mir das alles nicht so einfach aussuchen. Die Aufgabenstellung gibt da ja einiges vor. Vielleicht habe ich aber auch den zweiten Punkt der Aufgabe a falsch verstanden?! Ich dachte, eine übertragene Nachricht, die IPv4-Adresse des Clients und der Port des Clients sollen ausgegeben werden?! An ersterem arbeite ich gerade ... das mit der Adresse und dem Port überlege ich mir dann ...


----------



## bingo88 (5. Februar 2013)

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



boss3D schrieb:


> @ bingo88
> Ok, danke, bis auf ein warning, das wir ignorieren können, kompiliert das jetzt auch bei mir. Ich überlege mir das jetzt mit atoi(), damit auch tatsächlich der als Parameter an main übergebene Port an die Funktion übergeben wird.


 Schön 
Komischerweise waren die später deklarierten Variablen auch kein Problem, vor einem halben Jahr oder so ging das noch nicht bei meiner Maschine. Allerdings hatte ich da auch eine ältere GCC Version installiert. Auf dem Cluster den wir für einen Kurs nutzen geht es definitiv nicht, allerdings weiß ich nicht, welche Version die da drauf haben. Tendenziell wird die was älter sein


----------



## -Phoenix- (5. Februar 2013)

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

Dann brauchst ja im Server eingentlich nur ein recv, du sollst ja laut Aufgabenstellung vom Server aus nur Daten Empfangen und keine Senden. Die Daten bekommst du über recv, Ip+Port über return by reference von *accept.

*Lg.


----------



## Skysnake (5. Februar 2013)

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

hast du auch die entsprechenden header für size_t includiert?

Soweit ich das sehe, hast du die stddef.h nicht includiert. Die und die stdio.h sollte man eigentlich immer includieren.


----------



## bingo88 (5. Februar 2013)

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



Skysnake schrieb:


> hast du auch die entsprechenden header für size_t includiert?
> 
> Soweit ich das sehe, hast du die stddef.h nicht includiert. Die und die stdio.h sollte man eigentlich immer includieren.


 Wir haben das Problem gelöst. struct size_t bla gibt es nich, das struct musste da weg. Hatte ich jetzt auch erst beim selber kompilieren gesehen


----------



## Skysnake (5. Februar 2013)

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

Oh, das hatte ich jetzt gar nicht gesehen, dass da ein struct dabei stand


----------



## bingo88 (5. Februar 2013)

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



Skysnake schrieb:


> Oh, das hatte ich jetzt gar nicht gesehen, dass da ein struct dabei stand


 Mir hat auch erst das Syntax Highlighting von nano geholfen


----------



## boss3D (5. Februar 2013)

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



-Phoenix- schrieb:


> Dann brauchst ja im Server eingentlich nur ein recv, du sollst ja laut Aufgabenstellung vom Server aus nur Daten Empfangen und keine Senden. Die Daten bekommst du über recv, Ip+Port über return by reference von *accept.
> 
> *Lg.


Hm, ja ich hab's mir eh schon gedacht, dass ich das msg Zeugs, also den send() Teil, nicht brauche. Die Schleife für die Ausgabe des Buffer-Inhalts müsste schon stimmen:

```
[COLOR=seagreen]/* recv() - Senden und Empfangen mit TCP */    char buf[1024];
    if (recv (sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int x=0;
    while (x!=1024) {
        printf("%c", buf[x]);
        x++;
    }
```
Jetzt muss ich mir nur noch das mit der IP-Adresse und dem Port überlegen. Für die IP hätte ich das hier gefunden, aber es passt natürlich nicht 1:1 für mein Beispiel. Zumindest das printf sollte ich übernehmen können:

```
int i=0;
    while (hptr->h_addr_list[i]) {
          addr.s_addr = *((long*)hptr->h_addr_list[i++]);
          printf ("IPv4 address: %s\n", inet_ntoa(addr));
    }
```
Und den Port muss ich aus accept() rausbekommen?! 

Ist das dann das, was in int sock2 gespeichert ist?

```
[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()");
    }
```
*
[EDIT]*
Ich habe es jetzt mal so probiert, aber das addr ist offensichtlich noch falsch ...

```
[COLOR=seagreen]/* recv() - Senden und Empfangen mit TCP */
   [COLOR=black] char buf[1024];
    if (recv (sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int x=0;
    printf("message: ");
    while (x!=1024) {
        printf("%c", buf[x]);
        x++;
    }
    printf("\naccepted connection from [%s:%d]\n", inet_ntoa(addr), ntohs(remote_host.sin_port));
```
*[EDIT2]*
So würde ich beim Compilieren keine Fehlermeldung mehr bekommen, aber ob das stimmt?

```
printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));
```
Wenn mir wer bestätigen könnte, dass das so hinkommt (auch semantisch!), dann könnte ich mir jetzt noch den tcp_client überlegen und dann könnten wir das Ganze mal testen  :


Spoiler





```
#include <stdio.h>
#include <errno.h>
#include <string.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() - Senden und Empfangen mit TCP */    char buf[1024];
    if (recv (sock2, buf, 1024, 0) == -1) {
        perror("recv()");
    }
    int i=0;
    printf("message: ");
    while (i<1024) {
        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(sockfd); 
}

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Textnachricht, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int port;

    if (argv[1]=="TCP" && argv[2]=="Server") {
        port = atoi(argv[3];
        tcp_server(port);
    } 

    return 0;
}
```


----------



## -Phoenix- (5. Februar 2013)

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

Moin,

sieht gut aus hab jetzt keine Fehler finden können. Wenn du mehrere Clients hats musst du halt accept +recv noch in eine Schleife packen.
Du Empfängst jetzt nur 1*1024 Byte, falls es aber mehr Nutzdaten sind werden nicht alle Empfangen. Und du gibst immer 1024 Byte aus, anstatt die Anzahl tatsächlich empfangener Bytes.


```
ssize_t msg_lenght;
char buf[1024];
if ((msg_lenght=recv (sock2, buf, 1024, 0)) == -1) {
    perror("recv()");
    }

int i=0;
printf("message: ");
while (i<msg_lenght;) {
    printf("%c", buf[i]);
    i++;
    }
printf("\naccepted connection from [%s:%d]\n", inet_ntoa(remote_host.sin_addr), ntohs(remote_host.sin_port));
```


----------



## boss3D (5. Februar 2013)

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

Ich habe nur einen Client, aber der könnte auch mehr Nutzdaten senden, insofern danke für deinen Tipp!

Mein vorläufiger Client-Code sieht so aus:

```
#include <stdio.h>
#include <errno.h>
#include <string.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_client(void) {
    [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;
    [COLOR=darkorange][B]serv_addr.sin_port = htons(80);[/B]    serv_addr.sin_addr.s_addr = inet_addr("192.168.3.1");
   [COLOR=darkorange][B] struct[/B] [COLOR=darkorange][B]servent* serviceinfo = getservbyname("http", "tcp");[/B]    serv_addr.sin_port = serviceinfo->s_port;
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }

    [COLOR=seagreen]/* send() und recv() - Senden und Empfangen mit TCP */   [B][COLOR=purple] char *msg = "Test-Nachricht.\n";[/B]
    int len = strlen(msg);
    if (send(sockfd, msg, len, 0) == -1) {
        perror("send()");
    }
   [COLOR=royalblue][B] char buf[1024];
    if (recv(sockfd, buf, 1024, 0) == -1) {
        perror("recv()");
    }[/B]
    [COLOR=seagreen]/* close() - Socket freigeben */    int close(sockfd); 
}

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Texteingabe, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 

    if (argv[1]=="TCP" && argv[2]=="Client") {
        tcp_client();
    }

    return 0;
}
```
Dazu hätte ich vorerst folgende Fragen:

1.) Der Client soll ja laut Aufgabenstellung nur versenden, also kann ich die blauen Zeilen gleich mal löschen?!

2.) In der violetten Zeile muss die Nachricht hin, die ich an den Server senden will, aber das kann ja jedes Mal eine andere sein, also kann ich die nicht fix definieren. Wie sollte ich das geschickt lösen? Meine Idee wäre, in der main den Textstring (der ja als Parameter rein kommt) in einem char Feld zu speichern (kann ein char Feld überhaupt eine variable Größe haben?) und dieses an die Funktion tcp_client() zu übergeben und dort dann eben in der violetten Zeile als msg zu speichern. Nur ob das so geht?!

3.) In den orangen Zeilen ist "http" und der entsprechende Port "80" angegeben. Ich habe den Teil einfach übernommen, aber brauche ich das http-Zeug überhaupt? Ich hab's mal testweise "http" rausgelöscht gehabt aus der Funktion, sodass nur noch "tcp" dastand, aber da hat der gcc Compiler gleich gemeint zu wenige Parameter ... ???

*[EDIT]*
Nochmal kurz zu dem msg_length in tcpserver:
Mit ssize_t msg_length geht das mal wieder nicht. Ich hab's dann noch mit int probiert, ging aber auch nicht. Da hat's schon wieder irgendwas mit dem Datentyp:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




Spoiler





```
#include <stdio.h>
#include <errno.h>
#include <string.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() - Senden und Empfangen mit TCP */    [COLOR=royalblue][B]ssize_t msg_lenght;[/B]    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(sockfd); 
}

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Textnachricht, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int port;

    [COLOR=royalblue][B]if (argv[1]=="TCP" && argv[2]=="Server") {
        port = atoi(argv[3]);
        tcp_server(port);
    } [/B]
    return 0;
}
```



^^ Das will ich noch lösen bevor ich mir den tcpclient vornehme ...


----------



## -Phoenix- (5. Februar 2013)

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

1.) Ja kannst du löschen
2.) Dynamische länge geht wenn du den Speicher auch dynamisch mit malloc, calloc allokiert. Du kannst ja auch einfach eine Nachricht von der STDIN einlesen.
3.) keine Ahnung


----------



## boss3D (5. Februar 2013)

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

Ok, danke! malloc/calloc kenne ich, allerdings habe ich es noch nie für ein char Feld verwendet. Wenn's aber geht, passt's. Ich seh' auch gerade, dass ich da scheinbar was falsch verstanden habe in  der Aufgabenstellung: Die Textnachricht soll nicht als Parameter an main übergeben werden, sondern wohl per scanf() eingelesen werden?! Muss ich mal ausprobieren wie sich das machen lassen könnte, hab' da aber schon eine Idee ... 

3.) Gut, solange es nicht nichts "böses" macht, kann das http von mir aus da bleiben.

Wegen meinem EDIT aus dem vorigen Posting muss ich mir auch noch was überlegen. Dein ssize_t funktioniert wohl leider nicht?!

*[EDIT]*
Mit scanf und malloc sieht das dann wohl so aus:

```
#include <stdio.h>
#include <errno.h>
#include <string.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_client([COLOR=royalblue][B]char *data[/B]) {
    [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;
    [COLOR=darkorange][B]serv_addr.sin_port = htons(80);[/B]    serv_addr.sin_addr.s_addr = inet_addr("192.168.3.1");
    [B][COLOR=purple]struct servent* serviceinfo = getservbyname("http", "tcp");[/B]
    [COLOR=purple][B]serv_addr.sin_port = serviceinfo->s_port;[/B]    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }

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

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

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    [COLOR=royalblue][B]int size;
    char *data = (char*)malloc(size * sizeof(char));[/B]    
    if (argv[1]=="TCP" && argv[2]=="Client") {
        [COLOR=royalblue][B]printf("Please enter message: ");
        scanf("%s", &data);
        tcp_client(data);[/B]    }

    return 0;
}
```
^^ Aber ich muss ja trotzdem irgendeinen Wert für size angeben, oder? Blöd nur, dass ich erst nach dem scanf weiß, wieviele Zeichen wirklich eingegeben wurden.

*[EDIT2]*
Ich habe gerade irgendwie die Vermutung, dass ich die beiden violetten Zeilen komplett löschen kann und in die orange gehört der Port, den ich als Parameter an main und dann an tcp_client übergebe. Auch die IP des Servers soll nicht fix definiert, sondern übergeben werden. Muss ich mir noch überlegen.


----------



## boss3D (6. Februar 2013)

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

Kann mir bitte irgendwer mal in verständlichen Worten zu erklären versuchen, wie das programmiertechnisch geht, eine eingelesene IPv4-Adresse (In dotted-decimal-notation) in "einen Wert" umzuwandeln, mit dem ich dann weiterarbeiten kann?! Ich weiß nur, dass ich dafür irgendwie inet_aton() brauche, aber nicht, wie das genau geht. Jedenfalls muss ich die IPv4 Adresse als Parameter an die main übergeben, dort umwandeln und den umgewandelten Wert an die Funktion tcp_client() übergeben, oder?

So irgendwie wahrscheinlich: 

```
server_ip = inet_aton(argv[3]);
```
Nur, von welchem Datentyp sollte "server_ip" sein? Und inet_aton() braucht laut Compiler mehr Parameter, nur was soll ich da noch reinhängen? Habe ja hier geschaut, nur sagt mir das nicht viel. const char *cp ist wohl die eingegeben IP Adresse, nur was ist der Rest? So klappt's jedenfalls nicht:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Wenn ich mit meiner Vermutung, siehe Vorposting, richtig liege, müsste sich so jedenfalls der tcp_client machen lassen:

```
#include <stdio.h>
#include <errno.h>
#include <string.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_client(char *data, int port) {
    [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); 
    [COLOR=royalblue][B]serv_addr.sin_addr.s_addr = xxx;[/B] [COLOR=seagreen]// IP Adresse an Funktion übergeben und hier einfügen    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(sockfd); 
}

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int size, port;
    char *data = (char*)malloc(size * sizeof(char));
    
    if (argv[1]=="TCP" && argv[2]=="Client") {
        port = atoi(argv[4]);
        printf("Please enter message: ");
        scanf("%s", &data);
        tcp_client(data, port);
    }

    return 0;
}
```
^^ Dann müsste ich mir nur noch irgendwas schlaues für das int size in der main einfallen lassen. Ohne irgendeinen Größenwert wird das so eher nicht gehen?!


----------



## Skysnake (6. Februar 2013)

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

Na du liest es als Char array ein, und machst dann ne Typeumwandlung. Was sonst?


----------



## boss3D (6. Februar 2013)

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

^^ Habe oben noch ein Bisschen rumeditiert. Bin ich der Sache näher gekommen? Siehe mein Code (im Bild) ...

*[EDIT]*
So würde ich mir den Client vorstellen. Kann wer was dazu sagen, ob die blau markierten Teile (und natürlich der Rest) stimmen:

```
#include <stdio.h>
#include <errno.h>
#include <string.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_client([COLOR=royalblue][B]char *data[/B], [COLOR=royalblue][B]int port[/B], [COLOR=royalblue][B]int server_ip[/B]) {
    [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 = [COLOR=royalblue][B]htons(port)[/B]; 
    serv_addr.sin_addr.s_addr = [COLOR=royalblue][B]server_ip[/B];
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }

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

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

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    [COLOR=royalblue][B]int size, port, server_ip[/B][B];[/B]    char *data = (char*)malloc(size * sizeof(char));
    
    if (argv[1]=="TCP" && argv[2]=="Client") {
        [COLOR=royalblue][B]server_ip = inet_aton(argv[3], struct in_addr *s_addr);[/B]        [COLOR=royalblue][B]port = atoi(argv[4]);[/B]        printf("Please enter message: ");
        scanf("%s", &data);
        tcp_client(data, port, server_ip);
    }

    return 0;
}
```
^^ Beim Compilieren schaut's jedenfalls nicht so schlecht aus. Nur 1 Fehler, weil irgendwas mit dem struct in der main noch nicht passt:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## -Phoenix- (6. Februar 2013)

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

Du deklarierst ein Struct in einem Funktionsaufruf 


```
[COLOR=royalblue][B]server_ip = inet_aton(argv[3], struct in_addr *s_addr);[/B]
```
es gibt ja zig Versionen von inet_aton inet_aton - Linux Command - Unix Command
entweder du machst inet_aton(argv[3], serv_addr.sin_addr); in main, da du aber serv_addr in main nicht hast würde ich einfach argv[3] an tcp_client() übergeben und in tcp_client() dann die zuweisung inet_aton(argv[3], serv_addr.sin_addr); machen.

Wegen Size nimm einfach eine feste Größ, hast ja genug Arbeitsspeicher  einfach mal 4096 Byte oder so allokieren.
Oder du machst das so Dynamic String Input - The GNU C Library das ist aber halt kein ANSI C Standard


```
char *data;   scanf ("%as",&data);
```


----------



## Skysnake (6. Februar 2013)

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

LOL. inet_aton ist ja mal nett 

Ich hätte jetzt nicht erwartet, das es hierfür direkt nen bib gibt. So was würde ich kurz selbst runter hacken, aber gut, wenn man sich die Arbeit sparen kann


----------



## bingo88 (6. Februar 2013)

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

Mir ist grade noch was anderes aufgefallen:

```
/* Parameter: UDP/TCP, Client, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */
int main(int argc, char *argv[]) { 
    [B]int size, port, server_ip;
    char *data = (char*)malloc(size * sizeof(char));[/B] [B]/* 1 */[/B]
    
[B]    if (argv[1]=="TCP" && argv[2]=="Client")[/B] { [B]/* 2 */[/B]
        server_ip = inet_aton(argv[3], [B]struct in_addr *s_addr[/B]); [B]/* 3 */[/B]
        port = atoi(argv[4]);
        printf("Please enter message: ");
        scanf("%s", &data);
        tcp_client(data, port, server_ip);
    }

    return 0;
}
```
Beim ersten Teil ist size nicht initialisiert (kompilier mal mit dem Argument -Wall, das zeigt alle Warnungen an, u. a. nichtinitialsierte Variablen).

Beim zweiten Teil ist die if-Abfrage falsch. Du kannst in C Strings nicht mit "==" vergleichen. Du musst dafür z. B. die strcmp aus der string.h nutzen

```
if (strcmp(argv[1], "TCP") == 0)
{
    /* argv[1] = TCP */
}
```
Beim dritten Teil kommt mir das "struct in_addr *s_addr" komisch vor. Das muss sicher "inet_aton(argv[3], &server_ip)" heißen.
*Edit: Ah, wurde schon entdeckt ^^*

Abgesehen davon, wenn du mit argv arbeitest, solltest du besser argc vorher kontrollieren, ob du überhaupt genügend Argumente hast, beispielsweise

```
if (argc < 3)
{
    printf("Fehler: Zu wenig Argumente.\n");
    return -1; /* exit */
}
```


----------



## boss3D (6. Februar 2013)

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

^^ Ok, vielen Dank an alle! Habe das jetzt alles noch so umgebastelt:

```
#include <stdio.h>
#include <errno.h>
#include <string.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_client(char *data, int port, [COLOR=royalblue][B]char *server_ip[/B]) {
    [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); 
    serv_addr.sin_addr.s_addr = [COLOR=royalblue][B]inet_aton(server_ip, serv_addr.sin_addr);[/B]    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(sockfd); 
}

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) { 
    int size1=4096, [COLOR=royalblue][B]size2=1024[/B], port;
    char *data = (char*)malloc(size1 * sizeof(char));
    [COLOR=royalblue][B]char *server_ip = (char*)malloc(size2 * sizeof(char));[/B]    
    if ((strcmp(argv[1], "TCP")==0) && (strcmp(argv[2], "Client")==0)) {
        if (argc!=5) {
            printf("Parameters missing of too many parameters!\n");
            return -1;
        } else {
            [COLOR=royalblue][B]server_ip = argv[3];[/B]            port = atoi(argv[4]);
            printf("Please enter message: ");
            scanf("%s", &data);
            tcp_client(data, port, [COLOR=royalblue][B]server_ip[/B]);
        }
    }

    return 0;
}
```
^^ Nur ein Problem mit dem inet_aton() ist geblieben. Irgendwas stimmt mit dem zweiten Parameter immer noch nicht. Wenn ich siese Variante nehme ...
	
	



```
inet_aton(server_ip, &server_ip);
```
... dann kommt das:



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Und wenn ich diese Variante nehme ...
	
	



```
inet_aton(server_ip, serv_addr.sin_addr);
```
... dann das:



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## bingo88 (6. Februar 2013)

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

Für malloc/free (das man nicht vergessen sollte ) musst do noch die stdlib.h includen.

Versuch mal das hier:

```
/* die Funktion erwartet einen Zeiger auf die inet_addr, also musst du auch einen Zeiger liefern */
inet_aton(server_ip, [B]&[/B]serv_addr.sin_addr);
```


----------



## boss3D (6. Februar 2013)

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

^^ Ok, so klappt das schon ganz gut! Ich hab's auch schon in ein File zusammengefügt, weil's ja so gelöst werden soll:

```
#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 */    [COLOR=royalblue][B]ssize_t msg_lenght;[/B]    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(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); 
    serv_addr.sin_addr.s_addr = 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(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 of 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 of too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            scanf("%s", &data);
            tcp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
```
Nur das ssize_t msg_length passt noch nicht:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Ich hätte ja spontan int dafür genommen?! Wieso muss das wieder von irgendeinem Struktur-Datentyp sein?


----------



## bingo88 (6. Februar 2013)

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

Heißt das nicht size_t? ssize_t ist mir zumindest noch nicht untergekommen :D
Edit: ssize_t gibt es ja wirklich, wieder was gelernt ^^

Und das muss keine Struktur sein, sondern ist ein typedef (bei size_t kann z. B. ein unsigned int dahinter stecken). Ein typedef macht einen Datentyp nur unter anderem Namen verfügbar.


----------



## boss3D (6. Februar 2013)

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

Was typedef macht, weiß ich, aber size_t löst das Problem auch nicht ...  




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Langsam fällt mir kein passender Datentyp mehr dafür ein. socklen_t kann ich ja schon gar nicht nehmen, ein simples int eher auch nicht?!


----------



## bingo88 (6. Februar 2013)

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

Rechtschreibfehler: du hast das th bei length vertauscht, das ssize_t ist aber ok ^^
Und bei der If-Abfrage danach fehlt auch noch ne Klammer: if ((msg_length = ...()) == -1) {...}.
Wobei ich mir jetzt, ohne es auszuprobieren, nicht sicher bin, ob die wirklich fehlt.


----------



## boss3D (6. Februar 2013)

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

^^ Ah ja ... *facepalm*

Danke, so compiliert jetzt mal alles fehlerfrei. Jetzt muss ich das Ganze mal in den VMs testen, ob der Datentransfer per TCP funktioniert. Bin mir nur noch nicht ganz sicher, wie das gehen soll. Das C file in die Client- UND die Server-VM einfügen? Dann nur am Client mit den entsprechenden Parametern aufrufen? Mal ausprobieren ...


----------



## DarkMo (6. Februar 2013)

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

wollt nur mal anmerken: sehr intressant das alles  weiter so, sonen krempel wollt ich mir auch ma irgendwann beibringen >< klingt ja alles urst verwurschtelt xD da kannst du mir dann mal helfen boss ^^


----------



## Olstyle (6. Februar 2013)

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

Das Zusammenwurschteln von verschiedenen Konzepten und Beispielprogrammen ist was die Diskussion hier kompliziert erscheinen lässt. Da will jemand erst einmal eine funktionierende TCP-Kommunikation zum laufen bekommen und ihm wird direkt dynamische Speicheradressierung vorgeschlagen .

Eine gute Quelle(hab ich vorne schon mal verlinkt) nehmen und das mal gewissenhaft durcharbeiten sorgt imo für deutlich mehr Durchblick als sich von Anderen die Compilerfehler erklären zu lassen.


boss3D schrieb:


> Danke, so compiliert jetzt mal alles fehlerfrei. Jetzt muss ich das Ganze mal in den VMs testen, ob der Datentransfer per TCP funktioniert. Bin mir nur noch nicht ganz sicher, wie das gehen soll. Das C file in die Client- UND die Server-VM einfügen? Dann nur am Client mit den entsprechenden Parametern aufrufen? Mal ausprobieren ...


 Musst es halt auf der Client VM mit den Argumenten zum Start als Client und auf der Server VM mit den Server Argumenten füttern.

Wobei ein Rechner mit mehreren Terminals zum testen völlig ausreicht. Ob das TCP-Paket quer durchs Internet oder nur über den loopback geht ist deinem Programm eh egal.


----------



## Skysnake (6. Februar 2013)

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

Kann mich dem auch anschließen. An sich ist das kein großes Ding. Hab ich auch schon als Aufgabe gehabt in nem Übungszettel, und hatte das an nem WE gelöst. Hier haperts aber schon an gewissen Basics, nicht am eigentlichen Problem.


----------



## boss3D (6. Februar 2013)

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



DarkMo schrieb:


> wollt nur mal anmerken: sehr intressant das alles  weiter so, sonen krempel wollt ich mir auch ma irgendwann beibringen >< klingt ja alles urst verwurschtelt xD da kannst du mir dann mal helfen boss ^^


"Verwurschtelt" finde ich das jetzt eigentlich gar nicht, zumindest soweit der Code jetzt ist. Gerade dadurch, dass jetzt alles in Funktionen unterteilt ist (kommen noch 2 dazu) und man über die Parameter an main recht gut steuern kann, was passieren soll, finde ich's relativ übersichtlich. Was das alles hier wahrscheinlich "verwurschtelt" erscheinen lässt, ist, dass wir mehr Programmieren als Netzwerktechnik diskutieren ... 

Ich muss mir jedenfalls noch gut anschauen, was eigentlich in den structs, auf die ständig irgendwie verlinkt/zugegriffen wird, drinnen steht. Der Rest ist mir schon halbwegs klar. Und viele der Variablen kann man sich ja mehr oder weniger frei benennen, damit man weiß, was das Zeug alles ist. Sieht man ja auch, dass das Ganze in fast jedem Tutorial anders heißt. Und darum orientiere ich mich auch an EINEM und baue keine Mischung aus mehreren. 


Olstyle schrieb:


> Musst es halt auf der Client VM mit den  Argumenten zum Start als Client und auf der Server VM mit den Server  Argumenten füttern.
> 
> Wobei ein Rechner mit mehreren Terminals zum testen völlig ausreicht.


Ja, genauso habe ich das eh vor. Im Moment bin ich noch damit beschäftigt, das C File irgendwie in die Server VM reinzukriegen. Habe dazu ein Interface eth1 ins lokale Netzwerk geöffnet, aber dieses Interface will ums Verrecken keine IPv4 Adresse annehmen. Habe den Befehl schon zig mal probiert (sudo dhclient -4 eth1), rebootet, resettet ... immer wieder keine Adresse. Bin da noch am googeln ...


----------



## Skysnake (6. Februar 2013)

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



boss3D schrieb:


> Was das alles hier wahrscheinlich "verwurschtelt" erscheinen lässt, ist, dass wir mehr Programmieren als Netzwerktechnik diskutieren ...


Genau das. Dir fehlen einfach einige Basics bzgl programmieren. Bitte nicht falsch verstehen, aber du machst am laufenden Band ziemlich heftige Fehler, die man so nicht machen sollte. Man merkt einfach, dass du absolut keine Erfahrung mit Linux Systemen hast, und auch ansonsten nicht viel mit C/C++ bisher scheinbar gemacht hast. Und dann kommen halt noch die VS-Anfänger Unzulänglichkeiten mit dazu. VS ist ne tolle Sache, aber doch bitte erst nachdem man die Basics kann...

Dazu machst du es dir noch unnötig kompliziert mit der VM. Mach dir nen Dualboot, das ist nen Aufwand von ner halben Stunde und gut ist....

Ansonsten kann ich nur sagen, dass Programmieren nicht etwas abtippen ist, sondern verstehen von Konzepten. Du willst einfach etwas nur reproduzieren. Es gibt aber imme eine millionen Wege wie man etwas lösen kann. Das ist ja das spannende an Programmierend. Man kann verdammt kreativ sein. Vorallem, wenn man etwas performant machen will. Darum gehts bei dir aber gar nicht. Du solltest erstmal das Konzept eines Sende-/Empfangsbuffers verstehen. Das hast du nämlich bis jetzt noch nicht, wie mir scheint auf Grund deiner Fragen.


----------



## boss3D (6. Februar 2013)

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



Skysnake schrieb:


> Dazu machst du es dir noch unnötig kompliziert mit der VM. Mach dir nen Dualboot, das ist nen Aufwand von ner halben Stunde und gut ist....


Ich muss mit den VMs arbeiten, so, wie wir sie auf der Uni bekommen haben. Und obwohl ich jetzt schon alles manuell eingetragen habe auf der Server VM kann sich putty immer noch nicht hinverbinden. Ich habe keine Ahnung, wie ich as C File da sonst rein bekommen soll (abgesehen von alles händisch tippen) ... 




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## Olstyle (6. Februar 2013)

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

Je nach VM Software solltest du über die Laufwerke, USB Sticks etc. weiter reichen können. Die musst du dann nur in der VM mounten.


----------



## boss3D (6. Februar 2013)

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

^^ Auch alles schon probiert. Nur der Stick wird dann nicht gefunden, trotz mounten ... ich komme auf keinem Weg in diese verdammt VM rein ... 




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Wenn putty nicht geht, geht natürlich winSCP auch nicht. Network Bridge hat nichts gebracht. Shared Folders werden dann unter Linux in der VM wieder nicht gefunden. Und den USB-Stick mounten war jetzt auch meine letzte Idee, nur der wird auch nicht gefunden.

*[EDIT]*
Hab's gerade noch einmal probiert mit dem Stick. Da kommt dann sowas und da bleibt die VM hängen, bis ich das ganze mit Strg+c abbreche:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[EDIT2]*
Habe noch ein Bisschen herumprobiert: Scheinbar kann der Stick nicht gemounted werden?!




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[EDIT3]*
Habe den Stick jetzt unter Windows auf FAT32 formatiert und jetzt kann er auch in Debian gemountet werden. Da muss man auch erst einmal draufkommen ...  

Allerdings wird jetzt das C File als leeres File ohne Inhalt angezeigt.


----------



## boss3D (6. Februar 2013)

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

Auf den Client kann ich mich ja mit putty hinverbinden. Kann ich nicht irgendwie über die Client VM das C File an die Server VM schicken?
*
[EDIT]*
Vergessen wir die VMs vorerst. Ich habe jetzt noch das ganze für UDP gemacht:

```
#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 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;
    char buf[1024];
    if (msg_length = [COLOR=royalblue][B]recvfrom[/B](sock2, buf, 1024, 0, [COLOR=royalblue][B](struct sockaddr *)&serv_addr, sizeof(struct sockaddr)[/B]) == -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(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);
    if ([COLOR=royalblue][B]sendto[/B](sockfd, msg, len, 0,[COLOR=royalblue][B] (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)[/B]) == -1) {
        perror("send()");
    }

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

[COLOR=seagreen]/* Parameter: UDP/TCP, Client, Texteingabe, Server-IPv4-Adresse, Port */
/* Parameter: UDP/TCP, Server, Port */int main(int argc, char *argv[]) {
    int port;

    if ((strcmp(argv[1], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
        if (argc!=4) {
            printf("Parameters missing of 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 of too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            scanf("%s", &data);
            udp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
```
^^ Bei recvfrom() und sendto() kommen ja gegenüber recv() und send() noch 2 Parameter dazu: Adresse des Verbindungspartners und Größe der Struktur sockaddr?!

Beide Male wird's aber nicht &serv_addr sein, oder? Muss ich beim Server &remote_host schreiben?


----------



## boss3D (7. Februar 2013)

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

Habe jetzt alles in den VMs drinnen und das Ganze mit TCP auch gleich mal getestet. Beim Server-Part scheint alles soweit in Ordnung, nur der Client bleibt bei connect() hängen:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




Spoiler





```
#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_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); 
    serv_addr.sin_addr.s_addr = inet_aton(server_ip, &serv_addr.sin_addr);
    [COLOR=royalblue][B]if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        perror("connect()");
    }[/B]
    [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(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: ");
            scanf("%s", &data);
            tcp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
```



^^ Normal heißt ja Segmentation Fault, dass versucht wird, auf einen Speicher zuzugreifen, auf den physikalisch kein Zufriff besteht, aber wo soll denn das bei mir der Fall sein? An den mallocs kann's doch nicht liegen?! Und die Größen von size1 und size2 müssten doch auch locker reichen?!

_PS: Server-VM und Client-VM können sich ganz normal pingen._


----------



## boss3D (8. Februar 2013)

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

@ Mods
Sorry für die vielen Posts hintereinander, aber sonst sieht keiner, dass im Thread was weitergeht. 

@ Topic
Habe jetzt sowohl aus dem TCP- als auch dem UPD-Code sämtliche Syntaxfehler raus. Bin auch schon die ganze Zeit am Testen, ob die Übertragungen klappen, aber zur Zeit kämpfe ich noch mit folgenden Problemen:

*TCP:*
- Server scheint in Ordnung
- Client scheitert bei connect()




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




Spoiler





```
#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() - Senden und 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(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); 
    serv_addr.sin_addr.s_addr = 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(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 of 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 of too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            scanf("%s", &data);
            tcp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
```



*UDP:*
- Server scheitert an recvfrom()
- Client meint wie bei TCP "Segmentation fault"




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




Spoiler





```
#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 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;
    char buf[1024];
    if (msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &len)) == -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(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, &len) == -1) {
        perror("sendto()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(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], "UDP")==0) && (strcmp(argv[2], "Server")==0)) {
        if (argc!=4) {
            printf("Parameters missing of 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 of too many parameters!\n");
            return -1;
        } else {
            server_ip = argv[3];
            port = atoi(argv[4]);
            printf("Please enter message: ");
            scanf("%s", &data);
            udp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
```



^^ Wenn mir bitte wer helfen könnte, diese Fehler im Code zu beheben, wäre ich echt sehr dankbar! Dann könnte ich nämlich den TCP- und den UDP-Code in ein C File zusammenfügen und endlich mit der Aufzeichnung der Übertragung beginnen ...

Ich bin eh selbst auch schon den ganzen Tag am googeln bezüglich dieser Fehler, aber ich komme dabei nicht so recht weiter. Wo komme ich denn bitte auf ein Speichersegment, auf das kein physikalischer Zugriff besteht? Das soll "Segmentation fault" doch bedeuten?!


----------



## DarkMo (8. Februar 2013)

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

wieso machste das eigentlich in ner vm? vllt liegt da ja der hase begraben. oder es liegt am linux. hatte mal sone rettungs-heft-dvd nutzen wollen, da konnte die pfeiffe nichma auf die laufwerke zugreifen. aber wie ich da irgendwelche berechtigungen geb hatte sich mir auch ned erschlossen. naja, ich steh mit linux eh auf kriegsfuss >< bin einfach zu sehr an windows gewöhnt um komm ums verrecken ned damit klar.

jedenfalls meine laienhaften vermutungen:
- linux hat zugriffsprobs/fehlende rechte auf irgendwas
- die vm hat zugriffsprobs/fehlende rechte auf irgendwas

da auch meine fragen: geht das nur unter linux dann oder? wäre ganz kuhl, wenn das auch unter windoof laufen würde ^^ und: gibts bei sowas unterschiede zw xp und win7 als bsp? also halt die verschiedenen versionen von winblöd. oder is das vereinheitlicht? was nich verkehrt wäre, aus meiner bedürfnis-sicht  und noch ne frage: bei älteren games gabs ja ne exe für dedicated server. da hab ich auch öfter ma nen server aufm eignen rechner gestartet und bin mit der (zweiten exe) client exe dann drauf gejoined - und andre mittels hamachi hinterher usw. is das hiermit auch möglich?

weil die ganze problematik würd ich ja gern für mein ogl projekt adaptieren. soll ja auch ma irgendwann nen server/client programm werden.


----------



## Dragonix (8. Februar 2013)

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

1. Tu dir bitte einen gefallen und fang endlich an *Fehlermeldungen und Man-Pages* zu lesen! Dich juckt kein bisschen was der Compiler bzw die einzelnen Programme generell ausgeben (siehe deine mount-Versuche - der sagt dir doch klipp und klar wo der Fehler liegt).
2. Solange sowas

```
/* close() - Socket freigeben */
    int close(sockfd);
```
, fehlende Klammern und Zeiger-wo-keine-Zeiger hingehören (allerbestets Beispiel wo es schon fast schmerzt: scanf) im Code sind, wundert es mich im Prinzip erstmal, dass das überhaupt Übersetzt wird (bei mir tut's das nicht). Das es nicht funktioniert, wundert mich hingegen kein Stück weit. Und bevor die Fehler nicht aus dem Code draußen sind, macht es meiner Meinung nach auch keinen Sinn, den Fehler bei Linux oder irgendeiner VM Lösung zu suchen...

Also, drei Dinge die du hoffentlich tust:
1. Fehlermeldungen lesen und interpretieren (die erste Zahl sagt die Zeile, die zweite Zahl gibt das Zeichen an wo der Fehler bemerkt wurde - die Zeile ist OFT hilfreich!).
2. Man Pages und deren Posix Varianten (Linux ist in der Regel *nicht* vollständig Posix konform, wenn auch zum allergrößten Teil) anschauen. Posix Varianten findest du auch, wenn du nach "opengroup $funktion", also z.b. "opengroup posix" suchst.
3. Bei Speicherfehlern und auch sonst generell und immer und überhaupt: *Valgrind verwenden*.

Ich (und vermutlich auch andere) wären dir auch dankbar, wenn der Code mit folgenden Optionen kompiliert:
-Wall -Werror -pedantic -std=c99
DANN hast du nämlich schon einen ganzen Haufen "C" Fehler ausgebessert, und wir können uns dem Kern Problem zuwenden...


----------



## boss3D (8. Februar 2013)

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



DarkMo schrieb:


> wieso machste das eigentlich in ner vm? vllt liegt da ja der hase begraben.


Ich muss mit diesen VMs arbeiten. Siehe Angabe im Starposting. Ich glaube aber eher nicht, dass die Fehler daher kommen. Wenn man googelt, sieht man, dass genug andere Leute, die nicht mit VMs arbeiten, die Fehler auch haben. Ich vermute schon stark, dass es am Code liegt.

Zu deinen anderen Fragen kann ich leider nichts sagen. Ich beschäftige mich zum allerersten Mal mit solchen Sachen.

@ Dragonix
Von welcher Version meines Codes redest du? Schau dir die an, die ich in meinem letzten Posting vor diesem gepostet habe, das ist nämlich die aktuelle. Dabei bekomme ich nur noch 2 errors raus:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Bin auch schon die ganze Zeit dabei, diese man durchzuforsten, aber noch konnte ich die beiden Fehler nicht beheben. In den close() Funktionen habe ich jetzt BTW int close(int sockfd); stehen.

Im Code müssen noch 2 od. 3 semantische Fehler drinnen stecken, die keine Datenübertragung über das VM-Netzwerk zulassen. Siehe Fehlermeldungen, die ich im vorigen Posting beschrieben habe ...

*[EDIT]*
Das wäre jetzt der Code in einem Stück:


Spoiler





```
#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 [COLOR=purple][B]tcp_server[/B](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 [COLOR=purple][B]tcp_client[/B](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); 
    serv_addr.sin_addr.s_addr = 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 [COLOR=purple][B]udp_server[/B](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;
    char buf[1024];
    if (msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &len) == -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 [COLOR=purple][B]udp_client[/B](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, &len) == -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: ");
            scanf("%s", data);
            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: ");
            scanf("%s", data);
            udp_client(data, port, server_ip);
            free(data);
            free(server_ip);
        }
    }

    return 0;
}
```



^^ Bei den scanfs hast du doch gemeint, dass das & vor data weg müsste?!

Hier noch einmal die verbliebenen Fehler in einem:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## Dragonix (8. Februar 2013)

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

das -o muss direkt vor dem Wunschnamen der Ausgabe Binärdatei stehen, also "-o tcpserver".
Les dir in der man page durch, was inet_aton zurückgibt und denk dann mal drüber nach, ob das hier überhaupt passt so wie du das hast (aber das bemängelt er hier nichtmal).
Was er bemängelt (s. manpage):

```
inet_aton() is not specified in POSIX.1-2001, but is available on most
       systems.
```
Auf deutsch: Nicht wirklich gebräuchlich diese Funktion (das die Übersetzung *sehr* frei ist und durchaus Interpretation enthält, ist mir bewusst ). Ich hab die hier auch das erste mal gesehen...
Aber gucken wir mal in den angebenen Header (idr zu finden unter /usr/include/arpa/inet.h). Da steht:

```
/* The following functions are not part of XNS 5.2.  */
#ifdef __USE_MISC
/* Convert Internet host address from numbers-and-dots notation in CP
   into binary data and store the result in the structure INP.  */
extern int inet_aton (const char *__cp, struct in_addr *__inp) __THROW;
```
Dann schauen wir in die /usr/include/features.h (die wird hier nämlich inkludiert und "features" und "functions are not part" passt doch schonmal gut zusammen, und dann auch noch ein #ifdef - verdächtig!) und da steht (bzgl. __USE_MISC, viel zu lesen ich weiß): Definiere z.B. _BSD_SOURCE oder gleich _GNU_SOURCE (also entweder per #define oben in die Datei vor dem entsprechenden #include oder per Anweisung an den Kompilierer -D_GNU_SOURCE).
Da sehen wir ein ifdef, der ganze Abschnitt (also auch unser inet_aton) gibt's also nur geliefert, wenn wir __USE_MISC definieren.

Alternativ: Anders machen (wie gesagt, wüsste nicht, wann ich die Funktion jemals verwendet hätte).

Bei deinem anderen Fehler sollte dir die manpage helfen (er meint wirklich das 6. Argument, zähls ruhig durch und schau auf die Datentypen).

Und was ist mit dem scanf? Das wundert er mich, dass er dir das bei dir nicht anprangert, aber probiers mal mit der richtig sortierten Befehlszeile (dein -o verschluckt das -Wall).

Grüße und viel Erfolg
Matthias

Edit:
Und was

```
/* close() - Socket freigeben */
    int close(int sockfd);
```
soll, hast du mir immernochnicht erklärt. Natürlich durchaus möglich, dass ich's einfach nicht kenne, aber der Sinn davon erschließt sich mir in keinster Weise...


----------



## boss3D (8. Februar 2013)

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


```
gcc -Wall -Werror -pedantic -std=c99 -o socket socket.c
```
Ok, das bringt mich soweit:



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



```
#define __USE_MISC
```
^^ Das scheint jedenfalls nicht viel gebracht zu haben. Ich hätte es ja auch noch so probiert gehabt:

```
#if defined _BSD_SOURCE || defined _SVID_SOURCE 
#define __USE_MISC     1 
#endif
```


----------



## Dragonix (8. Februar 2013)

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

Ich bin mir nicht ganz sicher wie du das meinst:
Wenn du direkt #define __USE_MISC gemacht hast, dann schau mal an den Anfang der features.h


```
/* Undefine everything, so we get a clean slate.  */
...
#undef  __USE_MISC
...
```
(#undef ist klar? Wenn irgendwo vorher ein #define __USE_MISC war, dann wird das hier an dieser Stelle "gelöscht").

Du sollst nicht __USE_MISC direkt verwenden, sondern (das viel Aussagekräftigere) _BSD_SOURCE oder eben _GNU_SOURCE (Zitat features.h "All of the above, plus GNU extensions.", und _BSD_SOURCE steth drüber, also aktiviert _GNU_SOURCE auch _BSD_SOURCE).

Wichtig ist natürlich auch, dass du das schon VOR dem Inkludieren des Headers machst. Alternativ eben wie bereits geschrieben einfach "-D_GNU_SOURCE" (ohne die "") an cc übergeben, siehe dazu auch man gcc, bzw.:

```
-D name=definition
           The contents of definition are tokenized and processed as if they
           appeared during translation phase three in a #define directive.
           In particular, the definition will be truncated by embedded
           newline characters.
```

Und noch ein edit (falls du es jemals liest, ich hab's erst jetzt bemerkt ):


> ^^ Bei den scanfs hast du doch gemeint, dass das & vor data weg müsste?!


Jep.

Noch ein edit: Wenn du's per #define machst, füge das #define am besten in der ersten Zeile ein. Kann sonst durchaus zu unliebsamen Querverbindungen kommen (d.h. kann durchaus auf mehrere #includes haben).

Noch ein edit: Der letzte Fehler geht aber am schnellsten...


----------



## boss3D (8. Februar 2013)

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

^^ Habe oben noch ein Bisschen rumeditiert. Bitte siehe voriges Posting für aktuellen Stand.

Ich probiere jetzt noch das Makro mit _GNU_SOURCE. Mal schauen, ob inet_aton dann ordentlich erkannt wird ...

*[EDIT]*
Nein, #define _GNU_SOURCE hat auch nichts gebracht. Die Fehlermeldung mit inet_aton (siehe Screenshot im vorigen Posting) bleibt nach wie vor.

*[EDIT2]*
Ok, das "vor dem Inkludieren des Headers" habe ich zu spät gelesen. Jetzt, wo das #define _GNU_SOURCE ganz am Anfang über allen Headern steht, funktioniert das mit dem inet_aton scheinbar.  Und wir sind beim letzten Fehler angekommen:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Jetzt erst mal Mittagessen, dann überlege ich mir das mit dem pointer. Schon mal vielen Dank bis hierher!


----------



## bingo88 (8. Februar 2013)

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

Wenn ich mir die man für sendto ansehe und die Fehlermeldung im Kopf habe, schließe ich folgendes:


```
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, [B]socklen_t addrlen[/B]);
```
Der fett markierte Teil muss die Größe der sockaddr-Struktur enthalten, also bspw. _sizeof(serv_addr)_ bei dir. Die Fehlermeldung sagt dir in dem Fall sogar haargenau, was da nicht passt.


----------



## Dragonix (8. Februar 2013)

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



bingo88 schrieb:


> Wenn ich mir die man für sendto ansehe und die Fehlermeldung im Kopf habe, schließe ich folgendes:
> 
> 
> ```
> ...


 
Jetzt verrat ihm halt nicht alles, das soll er doch selber lernen  

Ich warte übrigens immer noch auf die Erklärung von

```
/* close() - Socket freigeben */
    int close(int sockfd);
```


----------



## boss3D (8. Februar 2013)

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

^^ Auf das sizeof wäre ich eh selbst auch schon gekommen (steht das nicht in irgendeinem meiner vorigen Postings?! K.A. ich gehe das jetzt auch nicht suchen, egal ) ... das Problem scheinen hier viel mehr die Werte (fett/blau) selbst zu sein. Zumindest das remote_host kommt mir noch leicht Spanisch vor ...

```
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;
    char buf[1024];
    if ((msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&[COLOR=royalblue][B]remote_host[/B], sizeof([COLOR=royalblue][B]remote_host[/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 *)&[COLOR=royalblue][B]serv_addr[/B], sizeof([COLOR=royalblue][B]serv_addr[/B])) == -1) {
        perror("sendto()");
    }

    [COLOR=seagreen]/* close() - Socket freigeben */    int close(int sockfd); 
}
```
Nur durch das sizeof verschwindet das Problem jedenfalls noch nicht:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## Skysnake (8. Februar 2013)

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

Ja, das inet_aton war mir auch absolut kein Begriff. Jetzt weiß ich auch warum  Das macht man dann doch gleich lieber selbst bei so nem kleinen Projekt.

Noch was am Rande.

Gewöhn dir doch bitte solche Aktionen ab:


```
if (msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, &len)) == -1)
```
Das ist nicht gerade sehr hilfreich bzgl Lesbarkeit des Codes.

Und zu den ersten beiden Fehlern.
Da steht doch drin, was du falsch machst. Du machst aus einem Pointer einfach nen Integer, ohne einen Typecast zu machen. Das ist doch klar, dass das nicht funktionieren kann 

Kann es sein, das dir das Konzept von Pointern, und wie man damit umgeht noch nicht wirklich klar geworden? Wenn ja, mach dir an ganz einfachen Beispielen nochmal klar, was beim (de)referenzieren passiert, und was passiert, wenn man einem Pointer einen Wert zuweist, und dann diesen Wert ändert usw.


----------



## boss3D (8. Februar 2013)

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

^^ Dass der Typecast fehlt, kann sogar ich aus der Fehlermeldung rauslesen, nur ich sehe den int einfach nicht (remote_host ist doch kein int?!) ...

Das hier ist das struct:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Nur auf was soll ich da jetzt casten? Die ersten beiden sind benutzerdefinierte Datentypen, so wie ich das verstehe, und das dritte ist ja ein Verweis auf ein anderes struct. Und was mich gerade besonders wundert: Wieso klappt's mit dem simplen sizeof bei sendto(), aber nicht bei recvfrom()? Da ist ja nichts anders?!  

^^ Ich probiere jetzt noch was mit den 3 Dingen aus dem Screenshost. Mal sehen, ob ich noch auf was drauf komme ...


----------



## boss3D (8. Februar 2013)

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

Geschafft!!! 

Habe aber ein Bisschen um das Problem herum gebastelt (wahrscheinlich wäre es auch direkt in der einen recvfrom Zeile gegangen):

```
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;
    [COLOR=royalblue][B]socklen_t clientlen;
    clientlen = sizeof(remote_host);[/B]    char buf[1024];
    if ((msg_length = recvfrom(sockfd, buf, 1024, 0, (struct sockaddr *)&remote_host, [COLOR=royalblue][B]&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); 
}
```
Jetzt sind auf jeden Fall mal sämtliche syntaktischen Fehler beseitigt. Das C File kann ohne errors und warnings compiliert werden:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Jetzt muss sich zeigen, ob das Ganze netzwerktechnisch funktioniert. Ich melde mich dann noch einmal ... 

*[EDIT]*
Ok, jetzt kommen die Netzwerkfehler. Bei TCP scheitert der Client an connect():




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Oberer Fensterausschnitt = Client. Unterer = Server. Die Client- und die Server-VM können sich problemlos pingen, also muss es sich hier um einen Code-Fehler in tcp_client bei connect() handeln ...

```
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); 
    serv_addr.sin_addr.s_addr = inet_aton(server_ip, &serv_addr.sin_addr);
    if ([COLOR=royalblue][B]connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))[/B] == -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); 
}
```


----------



## Dragonix (8. Februar 2013)

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



Dragonix schrieb:


> Les dir in der man page durch, was inet_aton zurückgibt und denk dann mal drüber nach, ob das hier überhaupt passt so wie du das hast (aber das bemängelt er hier nichtmal).






			
				man page schrieb:
			
		

> int inet_aton(const char *cp, struct in_addr *inp);
> [...]
> inet_aton() converts the Internet host address *cp* from the  IPv4  num‐
> bers-and-dots  notation  into  binary form (in network byte order) *and
> ...


(Sämtliche Hervorhebungen von mir eingefügt).

serv_addr.sin_addr.s_addr = inet_aton(server_ip, &serv_addr.sin_addr); << d.h. wenn das funktionieren würde wäre es Dus(s)el, aber in keinster weise vom Standard garantiert.

Edit: Um sämtliche Kommunikationsprobleme zwischen den VMs ausschließen zu können, würde ich dir - wie dir bereits schon mehrfach nahegelegt wurde - auch empfehlen, das ganze erstmal in *einer* VM zu testen...


----------



## boss3D (8. Februar 2013)

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

^^ Wie soll ich das Ganze in einer einzigen VM testen? Ich muss ja zuerst den Server starten und solange der dann darauf wartet, dass was passiert, kann ich ja keinen weiteren Befehl eingeben (und damit nicht auch den Client starten) ... ?! 

Ich überlege mir jetzt Mal, was du mit dem Code-bezogenen Satz meinen könntest ...


----------



## Dragonix (8. Februar 2013)

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



boss3D schrieb:


> ^^ Wie soll ich das Ganze in einer einzigen VM testen? Ich muss ja zuerst den Server starten und solange der dann darauf wartet, dass was passiert, kann ich ja keinen weiteren Befehl eingeben (und damit nicht auch den Client starten) ... ?!
> 
> Ich überlege mir jetzt Mal, was du mit dem Code-bezogenen Satz meinen könntest ...


 
Du hast mehrere virtuelle Terminals (Alt + F1, Alt + F2, ...), du könntest einen Befehl gleich in den Hintergrund schieben ("programm &", dann den angegebenen Pid wieder abschießen). Siehe dazu auch z.B. http://de.linwiki.org/wiki/Linuxfibel_-_Erste_Schritte_-_Virtuelle_Konsole .

Dann denk mal drüber nach . Tip: Du weißt deiner Adresse *irgendeinen* Wert zu, der von deiner inet_aton zurückkommt.. obwohl inet_aton doch gerade einen korrekten Wert über den Pointer reingeschrieben hat... hm... denk mal nach


----------



## bingo88 (8. Februar 2013)

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

Du kannst mit screen mehrere "Sessions" gleichzeitig verwenden und zwischen diesen umherschalten (man screen gibt Infos)


----------



## boss3D (8. Februar 2013)

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

@ me --> 
Natürlich nur:

```
inet_aton(server_ip, &serv_addr.sin_addr);
```
 

Damit kommt die TCP Kommunikation schon einen Schritt weiter. Immerhin das erste Wort des von mir eingegebenen Teststrings wird schon erfolgreich übertragen und am Server wird auch die IP des Clients erkannt, wo's herkommt ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Damit erübrigt sich zumindest die Frage, ob die Kommunikation zwischen den VMs grundsätzlich funktioniert. Trotzdem danke für die Tipps diesbezüglich!

Allerdings darf ich mir schon wieder überlegen, wo das "Segmentation fault" herkommt ... 
Ich habe ja doch nicht eine zu kleine Größe für das char Feld data gewählt?!


----------



## Dragonix (8. Februar 2013)

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

Lass dir mal den vom Client eingelesenen String ausgeben, du wirst merken, dass auch hier schon nach (bzw. vor) dem Leerzeichen schluss ist.

Nehm alternativ z.b. fgets (mit stream auf stdin gesetzt, achtung, liest auch das newline mit, aber das merkste schon); ist eh sicherer als scanf, da du hier die Puffergröße angibst...

Bezüglich dem Segfault: Kann sein, dass das irgendwo daher kommt, aber ich hab mittlerweile den Überblick über die Code Änderungen doch etwas verloren . Ansonsten sei nochmal ausdrücklichst auf valgrind verwiesen (valgrind nimmt dir aber nicht die Pflicht, ordentlichen Code zu schreiben - valgrind ist blos ein äußerst praktisches Progrämmchen...)


----------



## Skysnake (8. Februar 2013)

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

Es gibt auch die Möglichkeit ein Programm mit "&" im Hintergrund zu starten 

Also Linux bietet da SEHR viele Möglichkeiten


----------



## boss3D (9. Februar 2013)

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

@ Dragonix
Mit gets funktioniert die komplette TCP-Übertragung, allerdings wird gets vom Linux gcc Compiler offenbar als unsicher erachtet. Ich werde deswegen noch probieren, das Einlesen auf fgets umzuschreiben:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Das "Segmentation fault" scheint allerdings nicht am scanf gelegen zu haben, wenn's auch mit anderen Einlese-Funktionen auftaucht. Ich frage mich nur gerade, ob ich's nicht einfach ignorieren kann?! Der zweite Teil der Aufgabenstellung sieht vor, dass ich mit tcpdump die Übertragung aufzeichne und das müsste ja jetzt möglich sein, wo der vollständige Text übertragen wird?!  Klar, professionellerweise würde man da jetzt mit valgrind den Code durchchecken, aber ich glaube, wenn ich damit anfange, werde ich mit der Aufgabe bis zur Abgabefrist nicht mehr fertig. Ich wüsste offengestanden nicht einmal, wie ich dieses valgrind Zeugs überhaupt starten müsste, habe mich aber auch noch nicht wirklich eingelesen. 

Wie gesagt: Ich probiere jetzt noch fgets und wenn das dann soweit klappt, schauen wir, ob mein UDP-Code funktioniert. Wenn ich bei TCP und UDP eine funktionierende Übertragung habe, dann bin ich gerne bereit, mir das "Segmentation fault" noch einmal anzuschauen.


----------



## Skysnake (9. Februar 2013)

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

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

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.


----------



## boss3D (9. Februar 2013)

*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:

```
fgets(data, size1, stdin);
```



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Ich gehe jetzt mal UDP testen ... 

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




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ 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 !!*

```
#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;
}
```


----------



## Dragonix (9. Februar 2013)

*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..


----------



## boss3D (9. Februar 2013)

*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:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ So, wie ich das verstehe, liegt's irgendwie an dem strcmp, aber wie genau, muss ich mir noch überlegen ...


----------



## Dragonix (9. Februar 2013)

*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:

```
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!


----------



## boss3D (9. Februar 2013)

*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:

```
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 ...


----------



## Skysnake (9. Februar 2013)

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



boss3D schrieb:


> ^^ 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..


----------



## boss3D (9. Februar 2013)

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

@ Dragonix
Habe den Code mal entsprechend erweitert:

```
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }
```


```
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 ...

```
[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():

```
[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.


----------



## Dragonix (9. Februar 2013)

*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).


----------



## boss3D (10. Februar 2013)

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



Dragonix schrieb:


> 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 ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Netzwerktechnisch funktioniert jetzt alles einwandfrei ():

```
#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 ...


----------



## boss3D (10. Februar 2013)

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



Dragonix schrieb:


> 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:

```
int i=0;

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


```
if (argc!=4 && argv!=5) {
    printf("Missing or too many parameters!\n");
    return -1;
}
```
^^ Mal schauen, ob mir sonst noch was einfällt ...


----------



## Skysnake (10. Februar 2013)

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

Mach dir bitte nochmal klar, was argc und argv eigentlich sind...


----------



## boss3D (10. Februar 2013)

*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 ...


----------



## Skysnake (10. Februar 2013)

*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.


----------



## bingo88 (10. Februar 2013)

*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?


boss3D schrieb:


> ```
> int i=0;
> 
> while (argv[i]!=NULL) {
> ...



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.


```
/* 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.


----------



## Skysnake (10. Februar 2013)

*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.


----------



## boss3D (10. Februar 2013)

*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?!


----------



## Dragonix (10. Februar 2013)

*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...


----------



## boss3D (10. Februar 2013)

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

Ich hab's jetzt mal so gemacht:



Spoiler





```
#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:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



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




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Wieso sagt der eigentlich "0 frees"? Ich habe ja extra 2 Mal free() im Code?!


----------



## Dragonix (10. Februar 2013)

*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.

```
==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:

```
==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:

```
==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...


----------



## boss3D (10. Februar 2013)

*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 ...


----------



## crusherd (10. Februar 2013)

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.


----------



## boss3D (10. Februar 2013)

*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:

```
[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;
}
```



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



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:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## Dragonix (10. Februar 2013)

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



crusherd schrieb:


> 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.






> 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:

```
==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.


----------



## boss3D (10. Februar 2013)

*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.


----------



## crusherd (11. Februar 2013)

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


----------



## boss3D (11. Februar 2013)

*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 ...


----------



## Skysnake (11. Februar 2013)

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

Weil das auch jemand prüfen kann


----------



## boss3D (11. Februar 2013)

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

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

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.


----------



## Dragonix (11. Februar 2013)

*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.


----------



## boss3D (11. Februar 2013)

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

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




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ 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.


----------



## bingo88 (11. Februar 2013)

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

Ich glaube, ich hab es gefunden. Ist ein ziemlich banaler Fehler  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


----------



## boss3D (11. Februar 2013)

*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 ...

```
[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.


----------



## bingo88 (11. Februar 2013)

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

Diese Zeile hier ist das Problem:

```
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!


----------



## Skysnake (11. Februar 2013)

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

Das ist wirklich ein banaler Fehler


----------



## boss3D (11. Februar 2013)

*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? ...

```
[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.


----------



## bingo88 (11. Februar 2013)

*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.



Skysnake schrieb:


> Das ist wirklich ein banaler Fehler


 Hat trotzdem lange gedauert, bis ich das gefunden hatte


----------



## boss3D (11. Februar 2013)

*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:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## Skysnake (11. Februar 2013)

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



bingo88 schrieb:


> Hat trotzdem lange gedauert, bis ich das gefunden hatte


 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.


----------



## boss3D (11. Februar 2013)

*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:

```
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:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



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




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



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 ... 

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




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Den Befehle zum Hinzufügen von Routen kenne ich BTW (hier nur ein Beispiel):

```
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 ... 

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?!


----------



## crusherd (11. Februar 2013)

Ich vermute mal, dass der Server auf dem die VMs laufen, entweder keine Verbindung zum Internet hat oder er diese auf den VMs blockiert. In beiden Fällen kann man da nix machen.

Gruß
crusherd


----------



## boss3D (11. Februar 2013)

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

Das ist echt komisch. Habe jetzt mal _apt-cache policy tcpdump_ eingegeben und da heißt es, dass tcpdump bereits auf beiden VMs installiert sei ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Wenn ich's dann aber genau so benutzen will, wie's in der Übungsangabe steht, wird's nicht erkannt ...  




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Ich muss schon tcpdump starten, bevor ich meine Client-Server-Übertragung mache, oder verstehe ich hier was falsch? tcpdump macht ja die Aufzeichnung währenddessen?!

*[EDIT]*
Als root funktioniert tcpdump. Gut, soll mir auch recht sein. Aber sobald der im "Aufzeichnungsmodus" ist, kann ich meinen Server bzw. Client nicht mehr starten, weil ich ja dann keine Befehl eingeben kann. Und ich muss ja zuerst tcpdump starten?!


----------



## Dragonix (11. Februar 2013)

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

Als root ausführen...


----------



## boss3D (12. Februar 2013)

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

^^ Ja, siehe EDIT. Auf die Idee bin ich schon gekommen; das Problem ist nur, dass ich tcpdump VOR dem Starten des Servers/Clients starten muss. Nur, wenn ich das mache, geht tcpdump sofort in eine Art "Aufzeichnungsmodus" und ich kann keine weiteren Befehle eingeben ...

Eigentlich müsste es so sein:

1.) tcpdump -s 0 -w client.cap tcp and port 31337
2.) ./socket TCP Client 192.168.3.1 31337

^^ Nur 2tens geht nicht mehr, wenn ich 1tens gemacht habe ... 




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## Dragonix (12. Februar 2013)

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



boss3D schrieb:


> ^^ Ja, siehe EDIT. Auf die Idee bin ich schon gekommen; das Problem ist nur, dass ich tcpdump VOR dem Starten des Servers/Clients starten muss. Nur, wenn ich das mache, geht tcpdump sofort in eine Art "Aufzeichnungsmodus" und ich kann keine weiteren Befehle eingeben ...
> 
> Eigentlich müsste es so sein:
> 
> ...



Langsam beschleicht mich auch das Gefühl, dass du manchmal doch etwas lern-/leseresistent bist.



			
				http://extreme.pcgameshardware.de/programmierung-und-webdesign/256278-c-socket-fuer-tcp-udp-ubertragung-programmieren-8.html#post4974622 schrieb:
			
		

> Du hast mehrere virtuelle Terminals (Alt + F1, Alt + F2, ...), du  könntest einen Befehl gleich in den Hintergrund schieben ("programm  &", dann den angegebenen Pid wieder abschießen). Siehe dazu auch  z.B. http://de.linwiki.org/wiki/Linuxfibe...tuelle_Konsole .





			
				http://extreme.pcgameshardware.de/programmierung-und-webdesign/256278-c-socket-fuer-tcp-udp-ubertragung-programmieren-8.html#post4974624 schrieb:
			
		

> Du kannst mit screen mehrere "Sessions" gleichzeitig verwenden und zwischen diesen umherschalten (man screen gibt Infos)



Insbesondere das von bingo88 genannte screen ist wirklich einen (oder zwei) Blicke wert.

Und Skysnakes Lösung sollte man eigentlich auch kennen, wenn man mal was mit Linux zu tun hat...


			
				http://extreme.pcgameshardware.de/programmierung-und-webdesign/256278-c-socket-fuer-tcp-udp-ubertragung-programmieren-8.html#post4974720 schrieb:
			
		

> Es gibt auch die Möglichkeit ein Programm mit "&" im Hintergrund zu starten


----------



## Skysnake (12. Februar 2013)

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

Ich sag ja, da fehlen einfach basics. Sowohl was C/C++ als auch be linux. 

Nen Dual-Boot mal einrichten, und bischen rumspielen, hilft da 

"Linux auf einem Blatt" ist auch ganz hilfreich


----------



## boss3D (12. Februar 2013)

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

Ich hab's jetzt mal so probiert:

```
tcpdump -s 0 -w client.cap tcp and port 31337 [COLOR=royalblue][B]&[/B]./socket TCP Client 192.168.3.1 31337
```
So kann ich auch nach dem ersten Befehl noch den zweiten eingeben und die Übertragung kann durchgeführt werden. Aber ich bekomme ständig nur leere capture files raus (0 Bytes) ... 




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Woran kann das jetzt wieder liegen?

Die Parameter sollten jedenfalls stimmen. mit -s 0 wird alles aufgezeichnet und mit -w sollte es ins capture file geschrieben werden?!


----------



## DarkMo (1. März 2013)

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

ich hab mir jetz auch mal nen tutorial angeschaut und drauf losgebastelt. funzt bisher super, also server und client reden fleissig hin und her. nun ne konzeptionelle frage:

ich wollte mal sone arty mini-chat programm/irc gedöhns bauen. also man schreibt was und alle anderen bekommens gesendet usw. funzt theoretisch auch schon, nur ist der client halt grad so aufgebaut, dass in ner endlosschleife immer nen string vom user eingelesen und an den server gesendet wird. also das man halt schreiben und schreiben und schreiben kann ^^

blöd is halt nur, dass er ja solange nix macht, wie man nix sendet. wenn also client 2 nun was schreibt, erfahre ich das erst, wenn ich selber wieder was schreib und sende, da dann erst wieder der nächste check kommt -> muss ich hier schon multithreading machen, oder gibts da simplere lösungen?


----------



## Skysnake (1. März 2013)

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

Du nutzt "einfach" Threads 

Ansonsten fällt mir grad auch keine andere Möglichkeit auf Anhieb ein.


----------



## DarkMo (1. März 2013)

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

alles klaro, da werd ich mal in dieser richtung weiterforschen. das wollt ich zwar eh auch schonmal üben (wird ja irgendwann mal alles in my opengl ding einfließen ^^), hätte aber noch ned beim chat (server/client) dran gedacht ^^


----------

