Frage zu Tutorial von www.c-worker.ch (TCP/UDP Socket Programmierung)



  • Hallo zusammen ... ich beschäftige mich gerade mit UDP Socketprogrammierung...

    Dabei habe ich mich an das Tutorial von c-worker.ch gehalten.

    In dem Tutorial kan man jedoch nur abwechselt 1x senden und 1x empfangen ...

    Also habe ich mit Threads gearbeitet und das folgende Ergebnis hervorgebracht.
    Das Problem die Funktion recvfrom() liefert solange SOCKET_ERROR, bis ich zum ersten mal was sende ... von da an, blockiert die Funktion korrekt und empfängt alles richtig ...

    Aber warum kommt solange ich nichts gesendet habe immer der Fehler?

    Außerdem soll die Funktion recvfrom() NULL zurückliefern, wenn der Server die Verbindung trennt ...
    Leider funktioniert das auch nicht ... warum?

    So und hier nun der Code:

    #include <windows.h>
    #include <winsock2.h>
    
    #include <stdio.h>
    #include <conio.h>
    
    SOCKET CreateSocket(char *ServerName, u_short Port, SOCKADDR_IN &addr);
    bool CloseSocket(SOCKET &Socket);
    
    #define DEBUG
    //Client
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    bool inline PrintToLog(const char *Text)
    {
     return (printf(Text) == EOF)? false : true;
    };
    //---------------------------------------------------------------------------
    DWORD WINAPI recvThread(LPVOID Data)
    {
       long rc;
       SOCKADDR remoteAddr;
       int remoteAddrLen = sizeof(SOCKADDR);
    
       char buf[256];
       do
       {
          rc = recvfrom((SOCKET)Data, buf, 255, 0, &remoteAddr, &remoteAddrLen);
          if (rc == 0) // Server hat die Verbindung getrennt
          {
             PrintToLog("Server hat die Verbindung getrennt...\n");
             break;
          }
          if (rc == SOCKET_ERROR) // Fehler beim Empfangen
          {
    
             PrintToLog("Fehler beim  ausfuehren der Funktion recvfrom()...\n");
             //break;
          }
          buf[rc]='\0';
          PrintToLog(buf);
       }
       while (rc != 0);
    
     return (DWORD)Data;
    }
    //Client
    //---------------------------------------------------------------------------
    int main(int argc, char* argv[])
    {
       char *ServerName = "192.168.0.13";
    
       SOCKET Socket;
       SOCKADDR_IN addr;
       Socket = CreateSocket(ServerName, 12345, addr;
    
       if (Socket)
       {
             HANDLE hThread = CreateThread(NULL, 0, recvThread, (LPVOID)Socket, 0, 0);
    
             char buf[256];
             do
             {
                gets(buf);
                if (strlen(buf) == 0);
    
                sendto(Socket, buf, strlen(buf), 0, (SOCKADDR*)&addr, sizeof(SOCKADDR));
    
             } while (1);
    
             WaitForSingleObject(hThread, INFINITE);
    
             CloseSocket(Socket);
             CloseHandle(hThread);
       }
       getchar();
      return 0;
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    SOCKET CreateSocket(char *ServerName, u_short Port, SOCKADDR_IN &addr)
    {
       WSADATA wsa;
       SOCKET Socket;
    
       long rc = WSAStartup(MAKEWORD(2,0), &wsa);
       if (rc != NULL)
       {
          return 0;
       }
    
       Socket = socket(AF_INET, SOCK_DGRAM, 0);
       if (Socket == INVALID_SOCKET)
       {
          CloseSocket(Socket);
          return 0;
       }
    
       memset(&addr, 0, sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten
       addr.sin_family      = AF_INET;
       addr.sin_port        = htons(Port);
       addr.sin_addr.s_addr = inet_addr(ServerName);
    
     return Socket;
    }
    //---------------------------------------------------------------------------
    bool CloseSocket(SOCKET &Socket)
    {
     return closesocket(Socket) && WSACleanup();
    }
    //---------------------------------------------------------------------------
    

    Vielen Dank für Hilfe!!



  • Hinweis für deine CreateSocket Funktion:
    Benütze INVALID_SOCKET (-1). Ein Socket Value kann durchaus 0 sein.
    http://msdn2.microsoft.com/en-us/library/ms740516.aspx



  • Wenn Du ein SOCKET_ERROR bekommst würde ich mit WSAGetLastError() den genauen Fehler herausfinden.



  • Generell ist es so, dass UDP ein verbindungsloses Protokoll ist.
    Das heisst es gibt kein Status "Verbunden", "Nicht Verbunden" usw.

    der Returnwert 0 von recvfrom hat nicht die gleiche Bedeutung bei einem Verbindungslosen Socket, bzw. bei einem Verbindungsorientierten Socket.



  • @ simon.gysi:

    Hinweis für deine CreateSocket Funktion:
    Benütze INVALID_SOCKET (-1). Ein Socket Value kann durchaus 0 sein.
    http://msdn2.microsoft.com/en-us/library/ms740516.aspx

    Ok! Guter Hinweis!

    Wenn Du ein SOCKET_ERROR bekommst würde ich mit WSAGetLastError() den genauen Fehler herausfinden.
    

    Habe ich gemacht ... ich kann nur damit genauso wenig anfangen, als dass ich weiß, dass es sich um einen Fehler handelt. Ich bekomme den Fehlercode 10022.

    Generell ist es so, dass UDP ein verbindungsloses Protokoll ist. 
    Das heisst es gibt kein Status "Verbunden", "Nicht Verbunden" usw. 
    
    der Returnwert 0 von recvfrom hat nicht die gleiche Bedeutung bei einem Verbindungslosen Socket, bzw. bei einem Verbindungsorientierten Socket.
    

    Mag sein ... dennoch stand das in der Hilfe so drin (Return Values

    If no error occurs, recvfrom returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.)

    Aber warum tritt nun der von mir beschriebene Fehler auf?
    Das Problem die Funktion recvfrom() liefert solange SOCKET_ERROR, bis ich zum

    ersten mal was sende ... von da an, blockiert die Funktion korrekt und empfängt alles richtig ...
    

    Vielen Dank!



  • 10022: Ein ungültiges Argument wurde angegeben.



  • Hier kannst Du übrigens die Socket Errors nachschlagen:
    http://msdn2.microsoft.com/en-us/library/ms740668(VS.85).aspx

    Hier ist die Doku zu recvfrom(..) auf MSDN:
    http://msdn2.microsoft.com/en-us/library/ms740120.aspx

    Da steht, dass wenn WSAEINVAL (10022) auftritt vermutlich das socket nicht geunden ist.

    -> Beim empfangen musst Du dem socket mitteilen auf welchem interface (ip addr) und auf welchem port Du Daten empfangen möchtest. Das geschieht mit der Funktion bind.

    Q. Warum giengs dann nach dem 1. mal senden???
    A. Weil da das socket implizit gebunden wird.

    Ich würde als Test mal den Sender und Empfänger Code trennen. Das hilft das ganze zu verstehen.

    Ich korrigiere die anderen Fehler absichtlich nicht, da sie nichts mit deinem eigentlichen Problem zu tun haben (ev. sind sie auch nur hier im Forum Code...).

    Grüsse
    Simon


Anmelden zum Antworten