UDP-Server



  • re342 schrieb:

    Hat jemand eine Idee, wo der Fehler liegt?

    Fehler?
    Welcher Fehler?

    Die Compiler geben mit iher Fehlermeldungen durchaus Hinweise darauf, was sie stört.
    Darum ist die genaue Fehlermeldung wichtig.



  • Wäre halt cool gewesen wenn du die Fehlermeldungen mitgeliefert hättest.
    Wenn ich das mit einem gcc 4.8.2 übersetze sagt der mir eigentlich schon ziemlich eindeutig was nicht stimmt.
    Was man übrigens bei Benutzung der ebenfalls oft schon installierten man pages selbst hätte herausfinden können.

    test.c: In function 'main':
    test.c:24:5: warning: passing argument 2 of 'getsockname' from incompatible pointer type [enabled by default]
         if(getsockname(newSocket, &myaddr, &q) < 0){
         ^
    In file included from test.c:5:0:
    /usr/include/sys/socket.h:128:12: note: expected 'struct sockaddr * __restrict__' but argument is of type 'struct sockaddr_in *'
     extern int getsockname (int __fd, __SOCKADDR_ARG __addr,
                ^
    test.c:24:5: warning: pointer targets in passing argument 3 of 'getsockname' differ in signedness [-Wpointer-sign]
         if(getsockname(newSocket, &myaddr, &q) < 0){
         ^
    In file included from test.c:5:0:
    /usr/include/sys/socket.h:128:12: note: expected 'socklen_t * __restrict__' but argument is of type 'int *'
     extern int getsockname (int __fd, __SOCKADDR_ARG __addr,
                ^
    test.c:41:62: warning: pointer targets in passing argument 6 of 'recvfrom' differ in signedness [-Wpointer-sign]
         length = recvfrom(newSocket, msg, sizeof(msg), 0,(struct sockaddr*) &from, &fromlength);
                                                                  ^
    In file included from test.c:5:0:
    /usr/include/sys/socket.h:175:16: note: expected 'socklen_t * __restrict__' but argument is of type 'int *'
     extern ssize_t recvfrom (int __fd, void *__restrict __buf, size_t __n,
                    ^
    test.c:50:1: warning: control reaches end of non-void function [-Wreturn-type]
     }
     ^
    

    Benute im ersten Fall struct sockaddr anstatt struct sockaddr_in dann wirds wohl gehen.

    Das gleiche gilt für das recvfrom. Auch da einfach mal die Fehlermeldung lesen und dann den richtigen Datentypen benutzen.

    Dann klappts auch.



  • Danke für den Hinweis. Die Warnungen und Fehlermeldungen habe ich nun behoben.

    So sieht der Code nun aus :

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <netinet/in.h>
    
    int main(){
    	int newSocket;
    	struct sockaddr_in myaddr;			/* Adresse erstellen */
    	newSocket = socket(AF_INET, SOCK_DGRAM, 0);	/* Socket mit IPv4 und UDP erstellen */
    	if(newSocket < 0){ 
    		printf("Fehler beim erstellen des Sockets\n");
    		return EXIT_FAILURE;
    	}
    	myaddr.sin_family = AF_INET;
    	myaddr.sin_port = htons(0); 			/* 0 -> Betriebssystem legt Port fest (Host to Network Byte Order) */
    	myaddr.sin_addr.s_addr = htonl(INADDR_ANY);	/* INADDR_ANY verwendet IP des eigenen Rechners */
    
    	int q = sizeof(struct sockaddr_in);
    
    	if(getsockname(newSocket, (struct sockaddr *)&myaddr, (socklen_t*)&q) < 0){
    		printf("Fehler bei getsockname\n");
    		return EXIT_FAILURE;
    	}
    
    	printf("Port : %i\n", (int) myaddr.sin_port);
    
    	if(bind(newSocket, (struct sockaddr *) &myaddr, sizeof(struct sockaddr_in)) < 0){	/* Socket an Adresse binden */
    		printf("Fehler beim erstellen des Sockets\n");
    		return EXIT_FAILURE;
    	}
    	/* * Daten empfangen * */
    	char msg[64];
    	int length;
    	int fromlength;
    	struct sockaddr_in from;
    	fromlength = sizeof(struct sockaddr_in);
    	length = recvfrom(newSocket, msg, sizeof(msg), 0,(struct sockaddr*) &from, (socklen_t*)&fromlength);
    
    	if (length<0) { 
    		printf("Fehler beim Empfangen\n");
    	}
    
    	printf("%d Bytes empfangen.\tHost : %s\tPort : %d\nNachricht : %s\n", length,inet_ntoa(from.sin_addr), ntohs(from.sin_port), msg);
    	/* * Ende Daten empfangen * */
    	if(close(newSocket)<0) printf("Fehler beim Schließen des Sockets\n");	/* Schließt den Socket */
    	return 0;
    }
    


  • Ein letztes Problem gibt es noch :

    Beim Port wird mir nicht der zugewiesene Port (auch wenn ich selber einen festlege), sondern Port 0 zurückgegeben. Hat einer von euch eine Idee wie ich das Programm ändern könnte, dass der richtige Port ausgegeben wird?


  • Mod

    Ist das nicht ziemlich eindeutig? Da steht, ein struct sockaddr* wird erwartet. Du uebergibst ein struct sockaddr_in* . Also ganz was anderes. Ein Cast hilft dir vielleicht, den Compiler ruhig zu stellen, das macht den Code aber nicht richtig.



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C (alle ISO-Standards) in das Forum Linux/Unix verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Danke, jetzt hab ich endlich verstanden wo da das Problem ist.

    Wenn ich von Anfang an struct sockaddr* nutze ist halt das Problem, dass mir wichtige Komponenten wie z.B. der Port in dem Struct fehlen. Darum würde ich schon gerne struct sockaddr_in* verwenden. Aber das scheint ja mit getsockname und recvfrom nicht direkt kompartibel zu sein.

    Gibt es denn echt keine Möglichkeit den Server über struct sockaddr_in zum Laufen zu bekommen?



  • bind
    listen
    getsockname



  • Das ist überhaupt kein Problem.
    struct sockaddr und struct sockaddr_in können problemlos ineinander ge-casted werden. Hintergrund dazu ist das sockets ja nicht nur mit TCP/IP und UDP funktionieren sondern auch mit allen möglichen anderen Protokollen.
    Wenn du mal in sys/socket.h schaust dann findest du dort

    __SOCKADDR_ONETYPE (sockaddr) \
      __SOCKADDR_ONETYPE (sockaddr_at) \
      __SOCKADDR_ONETYPE (sockaddr_ax25) \
      __SOCKADDR_ONETYPE (sockaddr_dl) \
      __SOCKADDR_ONETYPE (sockaddr_eon) \
      __SOCKADDR_ONETYPE (sockaddr_in) \
      __SOCKADDR_ONETYPE (sockaddr_in6) \
      __SOCKADDR_ONETYPE (sockaddr_inarp) \
      __SOCKADDR_ONETYPE (sockaddr_ipx) \
      __SOCKADDR_ONETYPE (sockaddr_iso) \
      __SOCKADDR_ONETYPE (sockaddr_ns) \
      __SOCKADDR_ONETYPE (sockaddr_un) \
      __SOCKADDR_ONETYPE (sockaddr_x25)
    

    Für all diese Protokolle ist, wie man sieht jeweils eine andere Struktur als sockaddr definiert. getsockname und recvfrom sollen aber für alle Protokolle funktionieren.



  • Vielen Dank. Am Casten hat es wirklich nicht gelegen. Ich habe listen() und memset() verwendet und nun klappt es (es wird ein gültiger Port zugewiesen).

    Liebe Grüße,
    re342



  • Wo der Server jetzt funktioniert, wäre es natürlich schön, wenn er durchgehend Daten empfangen könnte und der Socket beim Drücken einer bestimmten oder einer beliebigen Taste geschlossen werden könnte.

    Eine nicht besonders elegante Möglichkeit gibt es ja dafür, und zwar den Daten-Empfangen-Teil in eine Endlosschleife zu packen und das Programm mit Strg+C zu beenden. Eine andere unschöne Variante wäre noch nach jedem mal Daten empfangen ein scanf einzubauen, und je nach Eingabe die Schleife zu verlassen oder nicht.

    Unter Windows gibt es ja eine elegante Möglichkeit über while (!kbhit()).... Gibt es soetwas unter Linux auch?

    Also ich meine etwas in der Art :

    while(Taste nicht gedrückt){
      // bereit Daten zu empfangen
    }
    // Socket schließen über close()
    

    Hat da jemand eine Idee?
    lg re342



  • select



  • Ok danke.



  • myaddr.sin_port = htons(0);

    .... statt "0" muss du da dein port eintragen 🙂

    Beispiel:

    uint16_t port = 4011;
    
    struct sockaddr_in server, client;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(port);
    

    Edit: achso ist ja schon gelöst, das problem...


Anmelden zum Antworten