IPV6 Server Client Verbindung



  • Hallo Zusammen,

    ich muss gerade für ein kleines Projekt eine TCP Server Client Verbindung programmieren in C unter Linux.
    Mit IPV4 hatte ich da bisher grundsätzlich Erfolg, für IPv6 klappt es leider nicht mehr.
    Bei connect() bekommt er keine Verbindung.
    Grundsätzlich soll die IP vom Sever mit in6addr_any festgelegt werden und bei Start angezeigt.
    Dazu nutze ich inet_ntop um diese in einen String umzuwandeln. Hier zeigt er aber jedes mal, selbst wenn ich eine fest IP vorgebe, das gleich an (a00:4d2:: )
    Auf Client Seite soll die IP dann als String eingegeben werden und mit inet_pton umgewandelt werden.
    Diese lasse ich nach dem connect versuch nochmals zurück umwandeln mit inet_ntop, hier kommt, egal welchen String ich anfangs eingebe, bzw auch wenn ich eine feste IP vorgebe immer 200:4d2:: zurück.
    Daher vermute ich mal, dass zum einen bei der Umwandlung auf Serverseite ein Fehler vorliegt und auf der Clientseite beim Einlesen und hin und her Umwandeln.

    Hat jemand eine Idee? Bitte etwas Umsicht mit mir, bin noch Anfänger beim Programmieren.

    Server

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    #define PORT 1234
    int x;
    char Y[10];
    
    
    int main()
    {
        char DataIN[1024];
        char DataOUT[1024];
        
        printf("Server startet!\n");    
        
        /***** Socket erzeugen *****/
        int ServerSocket = socket(AF_INET6, SOCK_STREAM, 0);
        if (ServerSocket < 0){printf("Erzeugen des Socket fehlgeschlagen!\n"); return EXIT_SUCCESS;}
        else {printf("Socket erzeugt...\n");}
           
        /***** Verbindung herstellen *****/
        struct sockaddr_in6 ServerAddr;
    
        memset(&ServerAddr, 0, sizeof(ServerAddr));
    
        ServerAddr.sin6_family = AF_INET6;
        ServerAddr.sin6_port = htons(PORT);
        ServerAddr.sin6_addr = in6addr_any;      
    
        char ServerIP[16];
        inet_ntop(AF_INET6, &ServerAddr, ServerIP, 16);
    
        if(bind(ServerSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == -1){
            printf("Fehler beim Binden des Socket!\n"); return EXIT_SUCCESS;}
        else{
            printf("Server bereit!\n IP Adresse = %s Port = %d \n", ServerIP ,PORT);  
            //printf("Server bereit...\n");
            }
            
        if(listen(ServerSocket, 5) == 0){printf("Warte auf Client...\n");}    
    
        /***** Verbindung mit Client *****/
        struct sockaddr_in6 ClientAddr;
        int addr_size = sizeof(ClientAddr);
           
        int ClientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &addr_size);
        if (ClientSocket == -1) {printf("Clientanfrage nicht akzeptiert!\n"); return EXIT_SUCCESS;}
            
        printf("Client Anfrage akzeptiert!\n");    
        strcpy(DataOUT, "[SERVER] Anfrage akzeptiert bitte Zahl eingeben!");
        send(ClientSocket, DataOUT, strlen(DataOUT), 0);
        
        recv(ClientSocket, &x, 1024, 0); 
        printf("[Client] %d \n", x);
    
        close(ClientSocket);
        close(ServerSocket);
        return 0;
    }
    

    Client

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    int x;
    
    int main()
    {
        char ServerIP[16];
        int PORTNR;
        
        char DataIN[1024];
        char DataOUT[1024];
    
        printf("Client startet! \n");
        
        /***** IP Eingabe *****/   
        printf("IP Eingeben: \n"); 
        fgets(ServerIP, 16, stdin);
        //scanf("%s", ServerIP);
    
        printf("PortNr Eingeben: \n"); 
        scanf("%d", &PORTNR);
    
        /***** Socket erzeugen *****/
        int ClientSocket = socket(AF_INET6, SOCK_STREAM, 0);
        if (ClientSocket < 0){printf("Erzeugen des Socket fehlgeschlagen!\n"); return EXIT_SUCCESS;}
        else {printf("Socket erzeugt!\n Verbindung zu %s :%d wird hergestellt...\n", ServerIP, PORTNR);}
        
        /***** Verbindung herstellen *****/
        struct sockaddr_in6 ServerAddr;
     
        memset(&ServerAddr, 0, sizeof (ServerAddr));
        ServerAddr.sin6_family = AF_INET;
        ServerAddr.sin6_port = htons(PORTNR);
        inet_pton(AF_INET6, "ServerIP", &ServerAddr.sin6_addr);
    
        if(connect(ClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == 0){
        printf("Verbindung zum Server wurde hergestellt!\n");
        }
        else {
            char IP[16];
            inet_ntop(AF_INET6, &ServerAddr, IP, 16);        
            printf("Verbindungsfehler! IP Adresse = %s Port = %d \n", IP ,PORTNR);
            return EXIT_SUCCESS;
            }
        
        for(;;){ 
            if(recv(ClientSocket, DataIN, 1024, 0) !=0){
                printf("%s\n", DataIN); 
                memset(DataIN,0,strlen(DataIN));            
            }
            //if(fgets(DataOUT, 1024, stdin) != 0){send(ClientSocket, DataOUT, strlen(DataOUT), 0);}
            scanf("%d", &x);
            send(ClientSocket, &x, sizeof(x), 0); 
            
        }
        
        close(ClientSocket);
        return 0;
    }
    


  • Hi,
    hab mir nur deinen Server angeschaut, dabei sind mir zwei Sachen aufgefallen:
    Erstens sollte addr_size vom Typ socklen_t sein, zweitens sieht die Benutzung von inet_ntop so richtig aus:

    char ServerIP[INET6_ADDRSTRLEN];
    inet_ntop(AF_INET6, &ServerAddr.sin6_addr, ServerIP, sizeof ServerIP);
    

    Heraus kommen sollte dann „::“ als IP vom Server. Und das ist genau das was du angegeben hast, nämlich in6addr_any. Die IP Adresse auf die der Client sich verbinden muss, ist die IP Adresse vom Netzwerkadapter auf dem der Server läuft und da kommst du auf diese Weise nicht dran. Laufen beide Programme auf dem selben PC, kannst du beim Client auf die Loopback Adresse „::1“ verbinden.



  • Hi,

    super vielen Dank für die schnelle Antwort.
    Da das ganze auf einem separaten Board laufen soll, müsste ich auf die IP Adresse vom Netzwerkadapter ran kommen. Gibt es da eine Möglichkeit das in den Code zu implementieren?
    Oder ist es einfacher die IP separat aus dem System auszulesen und dann bei dem Client anzugeben?



  • Die Adresse(n) aus dem System zu bekommen ist wohl möglich, aber stark Betriebsystemabhängig und da hab ich keinen Plan von 😉
    Unter Linux würde ich mir den strace vom Befehl ip a anschauen wie der die Adapter auflistet.
    Am einfachsten ist es die gewünschte IP manuell abzulesen und einzutippen.



  • Hab jetzt mal beim Server alles korrigiert, das scheint zu passen, zumindest kommt er bis zum listen()

    Server startet!
    Socket erzeugt...
    Server bereit!
    IP Adresse = a00:4d2:: Port = 1234
    Warte auf Client...

    Der Client scheint immer noch zu machen was er will:

    Client startet!
    IP = ::1
    Socket erzeugt!
    Verbindung zu ::1 :1234 wird hergestellt...
    Verbindungsfehler! IP Adresse = 200:4d2:: Port = 1234

    Es ist egal was ich als IP eingebe, er gibt jedes mal die 200:4d2:: als
    Adresse an zu der er sich verbinden will.

    Hier nochmal der überarbeitete Code

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    int x;
    int main()
    {
        char ServerIP[INET6_ADDRSTRLEN] = "::1";
        int PORTNR = 1234;
        char DataIN[1024];
        char DataOUT[1024];
    
        printf("Client startet! \n");
        printf("IP = %s\n", ServerIP);
    
        /***** Socket erzeugen *****/
        int ClientSocket = socket(AF_INET6, SOCK_STREAM, 0);
        if (ClientSocket < 0){printf("Erzeugen des Socket fehlgeschlagen!\n"); return EXIT_SUCCESS;}
        else {printf("Socket erzeugt!\n Verbindung zu %s :%d wird hergestellt...\n", ServerIP, PORTNR);}
        
        /***** Verbindung herstellen *****/
        struct sockaddr_in6 ServerAddr;
     
        memset(&ServerAddr, 0, sizeof (ServerAddr));
        ServerAddr.sin6_family = AF_INET;
        ServerAddr.sin6_port = htons(PORTNR);
        inet_pton(AF_INET6, "ServerIP", &ServerAddr.sin6_addr);
    
        if(connect(ClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == 0){
        printf("Verbindung zum Server wurde hergestellt!\n");
        }
        else {
            char IP[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, &ServerAddr, IP, INET6_ADDRSTRLEN);        
            printf("Verbindungsfehler! IP Adresse = %s Port = %d \n", IP ,PORTNR);
            return EXIT_SUCCESS;
            }
        
        for(;;){ 
            if(recv(ClientSocket, DataIN, 1024, 0) !=0){
                printf("%s\n", DataIN); 
                memset(DataIN,0,strlen(DataIN));            
            }
            scanf("%d", &x);
            send(ClientSocket, &x, sizeof(x), 0); 
         }
        
        close(ClientSocket);
        return 0;
    }
    


  • Soweit ich sehen kann zwei Fehler:

    • ServerAddr.sin6_family = AF_INET6; // beachte die 6
    • inet_pton(AF_INET6, ServerIP, &ServerAddr.sin6_addr); // keine Anführungszeichen


  • Hey super, jetzt klappt das auch. Vielen Dank.



  • So jetzt muss ich das ganze Thema leider doch nochmal aufrollen:
    mein Code funktioniert lokal problemlos, auch mit statischen IPs geht das.
    Wenn ich das ganze auf 2 PCs probiere kommt aber keine Verbindung zu stande.
    Die PC lassen sich anpingen, eine Verbindung steht also.
    Jemand eine Idee woran das liegt?



  • Firewall, Portfreigabe!?!



  • Firewall ist deaktiviert.
    Gibt es noch eine andere Möglichkeit die Ports freizugeben?



  • Mutmaßlich hast du einen Router zwischen den beiden Computern, die miteinander kommunizieren sollen. Ich könnte mir vorstellen, dass der den Port "1234" blockiert.



  • Ne hab ne direkte Verbindung per Kabel.
    Ist sicherheitshalber sogar ein Crossover Kabel.



  • Hab jetz nochmal bissl rumprobiert und folgendes festgestellt:
    wenn ich es lokal teste, ist es egal ob ich beim Server eine feste IP vergebe oder nicht und beim Client ist es egal was ich für eine IP eingebe, es wird immer eine Verbindung hergestellt.
    Hier nochmal die Codes:

    /***** SERVER *****/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    #define PORT 1234
    int x;
    char Y[10];
    
    
    int main()
    {
        char DataIN[1024];
        char DataOUT[1024];
    
        printf("Server startet!\n");
    
        /***** Socket erzeugen *****/
        int ServerSocket = socket(AF_INET6, SOCK_STREAM, 0);
        if (ServerSocket < 0){printf("Erzeugen des Socket fehlgeschlagen!\n"); return EXIT_SUCCESS;}
        else {printf("Socket erzeugt...\n");}
    
        /***** Verbindung herstellen *****/
        struct sockaddr_in6 ServerAddr;
    
        memset(&ServerAddr, 0, sizeof(ServerAddr));
    
        ServerAddr.sin6_family = AF_INET6;
        ServerAddr.sin6_port = htons(PORT);
        inet_pton(AF_INET6, "2001:abcd::77/64", &ServerAddr.sin6_addr);    
    
        if(bind(ServerSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == -1){
            printf("Fehler beim Binden des Socket!\n"); return EXIT_SUCCESS;}
        else{
            char ServerIP[INET6_ADDRSTRLEN];
            memset(&ServerIP, 0, sizeof(ServerIP));
            inet_ntop(AF_INET6, &ServerAddr.sin6_addr, ServerIP, sizeof(ServerIP));
            printf("Server bereit!\n IP Adresse = %s Port = %d \n", ServerIP ,PORT);
            //printf("Server bereit...\n");
            }
    
        if(listen(ServerSocket, 5) == 0){printf("Warte auf Client...\n");}
    
        /***** Verbindung mit Client *****/
        struct sockaddr_in6 ClientAddr;
        socklen_t addr_size = sizeof(ClientAddr);
    
        int ClientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &addr_size);
        if (ClientSocket == -1) {printf("Clientanfrage nicht akzeptiert!\n"); return EXIT_SUCCESS;}
    
        printf("Client Anfrage akzeptiert!\n");
        strcpy(DataOUT, "[SERVER] Anfrage akzeptiert bitte Zahl eingeben!");
        send(ClientSocket, DataOUT, strlen(DataOUT), 0);
    
        recv(ClientSocket, &x, 1024, 0);
        printf("[Client] %d \n", x);
    
        close(ClientSocket);
        close(ServerSocket);
        return 0;
    }
    
    /***** Client *****/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    int x;
    int main()
    {
        char ServerIP[INET6_ADDRSTRLEN];
        int PORTNR = 1234;
        char DataIN[1024];
        char DataOUT[1024];
    
        printf("IP Eingeben!\n");
        fgets(ServerIP, INET6_ADDRSTRLEN, stdin);
    
        printf("Client startet! \n");
    
        /***** Socket erzeugen *****/
        int ClientSocket = socket(AF_INET6, SOCK_STREAM, 0);
        if (ClientSocket < 0){printf("Erzeugen des Socket fehlgeschlagen!\n"); return EXIT_SUCCESS;}
        else {printf("Socket erzeugt!\n Verbindung zu %s :%d wird hergestellt...\n", ServerIP, PORTNR);}
    
        /***** Verbindung herstellen *****/
        struct sockaddr_in6 ServerAddr;
    
        memset(&ServerAddr, 0, sizeof(ServerAddr));
        ServerAddr.sin6_family = AF_INET6;
        ServerAddr.sin6_port = htons(PORTNR);
        inet_pton(AF_INET6, ServerIP, &ServerAddr.sin6_addr);
    
        if(connect(ClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == 0){
        printf("Verbindung zum Server wurde hergestellt!\n");
        }
        else {
            char IP[INET6_ADDRSTRLEN];
            memset(&IP, 0, sizeof (IP));
            inet_ntop(AF_INET6, &ServerAddr.sin6_addr, IP, INET6_ADDRSTRLEN);
            printf("Verbindungsfehler! IP Adresse = %s Port = %d \n", IP ,PORTNR);
            return EXIT_SUCCESS;
            }
    
        recv(ClientSocket, DataIN, 1024, 0);
        printf("%s\n", DataIN);
        memset(DataIN,0,strlen(DataIN));
        scanf("%d", &x);
        send(ClientSocket, &x, sizeof(x), 0);
        recv(ClientSocket, DataIN, 1024, 0);
        printf("%s\n", DataIN);
        memset(DataIN,0,strlen(DataIN));
    
        close(ClientSocket);
        return 0;
    }
    

    Ein Test mit IPv4 hat über LAN funktionniert, das läuft.
    Somit kann man das ganze mit hoher Wahrscheinlichkeit auf das Befüllen von sockaddr_in6 SerderAddr eingrenzen.



  • Hab die Lösung gefunden:

    in der struct sockaddr_in6 muss zusätzlich noch

    ServerAddr.sin6_scope_id = if_nametoindex("eth0");
    

    rein weil es IPv6 ist.
    Jetzt geht es auch zwischen den APCs Problemlos.


Anmelden zum Antworten