Socket, Receive() und Timeout

UInt

Mitglied
Hallo,

ich habe ein MFC Serverprüfprogramm, das einen Client simuliert. Die Kommunikation geht über TCP. Das Socket dafür habe ich von der Klasse CSocket abgeleitet. Es funktioniert prima, das Problem dabei ist, dass die Funktion Receive() kein Timeout hat :mad:. Das heisst, dass mein Programm jedes Mal hängt, wenn der Server nicht antwortet.

FRAGE:
Gibt es eine Möglichkeit den Timeout bei CSocket bzw. CAsyncSocket für Receive() einzubauen oder geht das nur mit select()(dann muss ich mein Socket auf SOCKET statt CSocket umschreiben :rolleyes:).

P.S.
IsBlocking() Methode von CAsyncSocket wäre nicht das Richtige, weil ich keine Threads habe.
 
Mach dir zB einen Thread, der immer auf Zeichen zum empfangen wartet
und die dann in ein Array schreibt.
Statt dem Normalen empfangen schaust du nach,
ob ein Zeichen da ist, sonst weisst du halt, dass der Server nichts geschickt hat.
 
Hmmm, select() scheint mir aber in dem Fall dann weniger kompliziert zu sein. Gibt es keine Lösungen ohne Thread für sowas.:confused:
 
Hallo,

also ich würde statt die MFC-Klassen zu verwenden lieber direkt auf die Winsock-API aufsetzen. Die ist nicht komplizierter als die Klassen, aber dafür funktionssicherer.
Die Verwendung eines Threads ist eigentlich auch kein so großer Aufwand, allerdings reicht für den Client, der sich ja nur mit einer Gegenstelle verbindet, auch das "select()" aus.
Ich habe mal ein einfaches Beispiel angehängt. Bei der while()-Schleife kannst du dann eine individuelle Abbruchbedingung einbauen.

Gruß
MCoder

C++:
#include <winsock.h>
#include <string>

#pragma comment (lib, "wsock32.lib")

int main()
{
    WSADATA wsa;

    if( WSAStartup(MAKEWORD(1,1), &wsa) ) // Windows-Sockets initialisieren
    {
        return (-1);
    }

    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if( sock == INVALID_SOCKET )
    {
        return (-1); 
    }

    std::string strHost = "localhost"; // TODO: Hostname zuweisen
    int         nPort   = 5555;        // TODO: Port zuweisen
    
    struct sockaddr_in saClient;
    struct hostent *pHost = gethostbyname(strHost.c_str());

    saClient.sin_family = AF_INET;
    saClient.sin_port   = htons(static_cast<u_short>(nPort));
    saClient.sin_addr   = *reinterpret_cast<struct in_addr*>(pHost->h_addr);

    if( connect(sock, reinterpret_cast<struct sockaddr *>(&saClient), sizeof(saClient)) == 0)
    {
        while( true )    // TODO: individuelle Abbruchbedingung
        {
            fd_set fds;
            FD_ZERO(&fds);
            FD_SET(sock, &fds);

            struct timeval timeout;
            timeout.tv_sec  = 0;
            timeout.tv_usec = 10000;

            int nRet = select(sock+1, &fds, 0, 0, &timeout);
            
            if( nRet > 0 )
            {
                char pbBuffer[1024];
                int nRead = recv(sock, pbBuffer, sizeof(pbBuffer), 0);
                
                if( nRead < 1 )
                {
                    break; // Socketfehler bzw. Socket wurde geschlossen
                }
            }
        }
    }        
    
    closesocket(sock);
    return 0;
}
 
Hi MCoder,

danke für die schnelle Antwort und den Code.:) Ich hätte allerdings noch eine Frage dazu:

Mann muss am Anfang WSAStartup(…) aufrufen.
Da mein Programm mehrere Clients simulieren soll, erzeuge ich die Sockets mit
Code:
sock = new SOCKET
Wie oft soll ich in diesem Fall WSAStartup(…) aufrufen? Reicht es nur einmal oder soll ich es für jeden neuerstellten Socket machen?
 
Hallo,

WSAStartup() ist dafür da, die Verwendung der die Winsock-DLL (WS2_32.DLL) vorzubereiten und muss daher im Programm nur ein einziges Mal ausgeführt werden.

Gruß
MCoder
 
Hmmm,

es ist doch nicht so einfach, wie ich es dachte. Ich darf kein Pointer auf SOCKET machen. :eek:
Wenn ich den Code so schreibe:
Code:
SOCKET *m_Sock;
m_Sock = new SOCKET;    // <------------------1
m_Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  // <----------------------2

in der Zeile "<-------1" habe ich beim Ausführen "Unhandled exception" und spätestens in der Zeile "<---------2" wird es schon Unsinn (Error beim Kompilieren: " '=' : cannot convert from 'SOCKET' to 'SOCKET *' ").

Kann es sein, dass ich was grundsätzlich falsch mache?
 
:) :) :) :)

ja, auf "*m_Sock" bin ich noch gekommen, aber es hilft mir leider alles nicht, wenn die Zeile davor nicht funktioniert.

FRAGE:
wäre es theoretisch möglich, dass der folgende Code funktioniert? Ich weiß nicht, ob meinem Code was fehlt oder es ist einfach nicht machbar.

Code:
SOCKET *m_Sock;
m_Sock = new SOCKET;
 
Hallo,

also bei der Zeile "m_Sock = new SOCKET;" sehe ich keine Fehler, das ist so ok. Das Problem muss daher woanders liegen.
Du hast geschrieben, dass du mehrere Clients erzeugst. Die bildest du doch hoffentlich nicht alle auf die gleiche Membervariable "m_Sock" ab? Dann wäre der Crash nämlich unausweichlich.

Gruß
MCoder
 
Zurück