Probleme mit SOCKETS und UDP



  • Hallo,

    ich möchte endlich mal richtig mit Sockets arbeiten, aber natürlich mit UDP denn
    TCP/IP kann ich für Spiele absolut nicht gebrauchen weil das ja zu langsam ist.

    Ich hab mir schon einige Beispiele angesehen und verstehe zum Teil schon mal das Grundprinzip.
    Allerdings kommt bei meinem SocketTest keine Nachricht mehr zurück wenn ich UDP verwende.

    // Mit TCP/IP mache ich das so:
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    // Mit UDP mache ich das so:
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    

    Das müsste schon mal soweit richtig sein oder?!

    // Das hab ich aus einem Tutorial, funktioniert auch mit TCP/IP wenn ich das an "192.168.2.1" (mein Router) schicke
    char msg[1024] = "GET / HTTP/1.1\r\nHost: www.example.net\r\n\r\n";
    
    // Result ist bei UDP leider immer -1
    int result = recv(sock, msg, sizeof(msg) - 1, 0);
    

    Wenn euch das an Code nicht reicht, hier ist noch mal der ganze Code:

    #include <cstdio>
    #include <cstdlib> // für exit()
    #include <unistd.h> // für close()
    #include <string> // für memset()
    
    #include <winsock2.h>
    
    using namespace std;
    
    int main(void) {
    
        WSADATA wsa;
        int result;
    
        // starting winsock
        result = WSAStartup(0x0002, &wsa); // 0x0002 for Windows 2.0, 0x0101 for Win 1.1
        if (result) { // WinSock API error handling
            printf("Error: WSAStartup, ");
            switch(result) {
                case WSASYSNOTREADY:     printf("WinSock not ready\n");                             break;
                case WSAVERNOTSUPPORTED: printf("requested WinSock version not supported\n");       break;
                case WSAEINPROGRESS:     printf("blocking WinSock 1.1 operation in progress\n");    break;
                case WSAEPROCLIM:        printf("maximum WinSock tasks reached\n");                 break;
                case WSAEFAULT:          printf("The lpWSAData is not a valid pointer\n");          break;
                default:                 printf("Unknown error code: %d\n", result);                break;
            }
            return result;
        }
    
        // main rutine
    
        SOCKET sock;
    
        // wir holen uns den descriptor für einen socket (soll mal TCP/IP werden)
    
        // int socket(int domain { AF_INET, PF_INET, PF_INET6, PF_IPX, PF_PACKET } , int type { SOCK_DGRAM, SOCK_STREAM } , int protocol );
    
        // !!! Hier ist TCP/IP und UDP !!!
        #if 1
        sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // UDP
        #else
        sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // TCP/IP
        #endif
    
        if (sock == -1 ) {
            perror("could not create socket\n");
            system("PAUSE");
            exit(1);
        } else
            printf("create socket successful\n");
    
        // Strukur anlegen, mit Nullen füllen und initialisieren
        sockaddr_in dest_addr;
        memset(&dest_addr, 0, sizeof(dest_addr));                   // alles mit Nullen füllen
        dest_addr.sin_family        = AF_INET;                      // muss hier nochmal stehen
        dest_addr.sin_port          = htons(80);                    // auf dem Port läuft meistens HTTP
        dest_addr.sin_addr.s_addr   = inet_addr("192.168.2.1");     // IP Addresse von www.example.net
    
        // verbinden
        if (connect(sock, (sockaddr*)&dest_addr, sizeof(sockaddr)) == -1) {
            perror("could not connet to 192.168.2.1:80\n");
            system("PAUSE");
            exit(2);
        } else
            printf("connection successful\n");
    
        // eine Nachricht senden
        char msg[1024] = "GET / HTTP/1.1\r\nHost: www.example.net\r\n\r\n";
        // blockierende Funktion (wartet bis alle Daten gesendet wurden)
        result = send(sock, msg, strlen(msg), 0);
        if (result == -1) {
            perror("couldn't send data");
            system("PAUSE");
            exit(3);
        }
        if (result < (signed)strlen(msg)) { // eigentlich kein Fehler, aber für diese Zwecke lassen wir es einen sein
            perror("couldn't send all data");
            system("PAUSE");
            exit(4);
        }
    
        do {
            // blockierende Funktion, wartet solange bis eine Antwort kommt (Daten, Fehler, Verbindung beendet)
            result = recv(sock, msg, sizeof(msg)-1, 0);
            if (result == 0) {
                puts("\r\nconnection terminated by server\n");
                break;
            } else if (result == -1) {
                perror("recv() error");
                //system("PAUSE");
                //exit(5);
                result = 1;
            } else {
                msg[result] = 0; // string terminieren
                puts(msg);
            }
        } while (result > 0);
    
        // close socket
        close(sock);
    
        WSACleanup();
    
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Kann mir jemand sagen was ich falsch mache oder was da noch fehlt?

    Danke schon mal 🙂


  • Administrator

    LukasBanana schrieb:

    ich möchte endlich mal richtig mit Sockets arbeiten, aber natürlich mit UDP denn
    TCP/IP kann ich für Spiele absolut nicht gebrauchen weil das ja zu langsam ist.

    Absoluter Quark!
    Es kommt ganz auf das Spiel und die Menge an Daten an. UDP wird aber oft gewählt, weil es in Netzwerken und bei Firewalls einige Vorteile bietet. Der zusätzliche Overhead von TCP fällt selten wirklich ins Gewicht. TCP ist allerdings deutlich leichter zu benutzen als UDP.

    Ob der Code funktioniert oder nicht, kann ich nicht gleich sagen, nur was mich stutzig macht, ist die HTTP Anweisung mit UDP. Soweit ich weiss geht HTTP nur über TCP, weshalb dein Router wahrscheinlich nicht antwortet.

    Im übrigen übermittelst du jede Menge Schrott, welcher wahrscheinlich auch noch Probleme macht. Du übermittelst 1023 Zeichen, wovon du aber nur eine ganz kleine Anzahl benutzt. Den Rest lässt du auf einem uninitialisierten Zustand, wodurch irgendwelche Zeichen übermittelt werden. Das kann ja fast nicht gut gehen.

    Und noch was fällt mir auf. Mit UDP und Winsock braucht man doch andere send und receive Funktionen. War doch sowas wie send_to und receive_from. Dafür fiel doch das connect weg. Irgendwas in der Art, am besten machst du mal ein Tutorial zu Winsocks durch.
    http://www.c-worker.ch/tuts/udp.php
    Ist zwar für C, aber wieso nicht.

    Und falls du eine API haben möchtest, welche in C++ ist und Platformunabhängig, wäre noch Boost.Asio zu empfehlen 😉

    Grüssli



  • Wenn es eh ein Spiel werden soll, kann man sich natürlich auch SDL in Verbindung mit SDL_net anschauen. Oder Qt verwenden etc. pp.


  • Administrator

    Noch was ist mir in den Sinn gekommen, das editier ich jetzt nicht rein, da Fellhuhn schon geantwortet hat. Du bist im falschen Forum!
    Winsockets ist WinAPI und somit:
    http://www.c-plusplus.net/forum/viewforum-var-f-is-4.html

    Grüssli



  • Danke schön Dravere 🙂
    Das Tutorial sieht schon mal sehr hilfreich aus



  • Aber noch mal ne kurze Frage - (ich will dafür jetzt nicht extra noch mal einen Thread aufmachen):

    ist die Funktion recvfrom auch einen blokierende Funktion?
    Das wäre nämlich sau unpraktisch 😞
    Wenn das Programm nämlich gerade eine Nachricht empfangen will, aber es kommt keine mehr, hängt sich das Programm auf.


  • Administrator

    LukasBanana schrieb:

    ist die Funktion recvfrom auch einen blokierende Funktion?

    Das weiss ich auch nicht, wir sind ja nicht im WinAPI Forum. Aber das könntest du auch selber in der MSDN nachschlagen:
    MSDN: recvfrom
    Da steht:

    If no incoming data is available at the socket, the recvfrom function blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking.

    LukasBanana schrieb:

    Das wäre nämlich sau unpraktisch 😞
    Wenn das Programm nämlich gerade eine Nachricht empfangen will, aber es kommt keine mehr, hängt sich das Programm auf.

    Deshalb lagert man eigentlich oft solche Sachen in Threads aus. Die recv Funktion ist übrigens auch blockierend, kannst du auch in der MSDN nachlesen 😉

    Grüssli


Anmelden zum Antworten