Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » Winsock

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
04.01.2004, 19:49 Uhr
(un)wissender
Niveauwart


Hallo, ich versuche gerade eine eigene kleine Socketlib zu schreiben, allerdings habe ich eine Frage.
Warum wartet ::accept (Winapi) nicht bis eine Connection kommt, sondern
kehrt sofort zurück?
Ich bekomme keine Fehlermeldung.
Die Idee ist, das accept den Prozess solange blocken soll, bis eine Verbindung zustande kommt.
Was mache ich falsch?


C++:
TCPSocket TCPServerSocket::accept( unsigned int port, int backlog )
{
    bind(port);
    listen(backlog);    

    SOCKADDR_IN addr;
    int len = sizeof( SOCKADDR_IN );
    memset( &addr, 0, sizeof( SOCKADDR_IN ) );

    SOCKET new_sock = ::accept(m_hSocket, reinterpret_cast<sockaddr *>(&addr), &len);
    
    if(new_sock == INVALID_SOCKET || m_hSocket == INVALID_SOCKET)
       encodeWinsockErrorAndThrowException();
      
    return TCPSocket(new_sock);
}

void TCPServerSocket::listen(unsigned int backlog )
{
    if( ::listen( m_hSocket, backlog ) == SOCKET_ERROR )
       encodeWinsockErrorAndThrowException();
}

void TCPServerSocket::bind(unsigned int port )
{
    SOCKADDR_IN addr;

    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_family = AF_INET;
    addr.sin_port = ::htons( port );
    memset( addr.sin_zero, 0, sizeof( addr.sin_zero ) );

    if(::bind( m_hSocket, reinterpret_cast<const sockaddr *>(&addr),
               sizeof( SOCKADDR_IN ) ) == SOCKET_ERROR )
       encodeWinsockErrorAndThrowException();
}


--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
04.01.2004, 20:07 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


accept() soll auch auf nicht auf eine Verbindung warten, dafür ist listen() da.

Warum machst du eigentlich die :: vor die Funktionen?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
04.01.2004, 20:31 Uhr
(un)wissender
Niveauwart


Bist du dir sicher?
Folgendes Programme (habe ich im Netz gefunden, funktioniert, und untermauert deine Aussage nicht gerade, denn es wartet genau bei accept()).
Die Ausgabe "after accept" kommt nämlich nicht, also blockt accept, nicht listen.


C++:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>

#define NETWORK_ERROR -1
#define NETWORK_OK     0

void ReportError(int, const char *);


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) {
    WORD sockVersion;
    WSADATA wsaData;
    int nret;

    sockVersion = MAKEWORD(1, 1);            // We'd like Winsock version 1.1


    // We begin by initializing Winsock
    WSAStartup(sockVersion, &wsaData);


    // Next, create the listening socket
    SOCKET listeningSocket;

    listeningSocket = socket(AF_INET,        // Go over TCP/IP
                     SOCK_STREAM,       // This is a stream-oriented socket
                 IPPROTO_TCP);        // Use TCP rather than UDP

    if (listeningSocket == INVALID_SOCKET) {
        nret = WSAGetLastError();        // Get a more detailed error
        ReportError(nret, "socket()");        // Report the error with our custom function

        WSACleanup();                // Shutdown Winsock
        return NETWORK_ERROR;            // Return an error value
    }


    // Use a SOCKADDR_IN struct to fill in address information
    SOCKADDR_IN serverInfo;

    serverInfo.sin_family = AF_INET;
    serverInfo.sin_addr.s_addr = INADDR_ANY;    // Since this socket is listening for connections,
                            // any local address will do
    serverInfo.sin_port = htons(8888);        // Convert integer 8888 to network-byte order
                            // and insert into the port field


    // Bind the socket to our local server address
    nret = bind(listeningSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));

    if (nret == SOCKET_ERROR) {
        nret = WSAGetLastError();
        ReportError(nret, "bind()");

        WSACleanup();
        return NETWORK_ERROR;
    }


    // Make the socket listen
    printf("before listen\n");
    nret = listen(listeningSocket, 10);        // Up to 10 connections may wait at any
                            // one time to be accept()'ed
    printf("after listen\n");
    if (nret == SOCKET_ERROR) {
        nret = WSAGetLastError();
        ReportError(nret, "listen()");

        WSACleanup();
        return NETWORK_ERROR;
    }


    // Wait for a client
    SOCKET theClient;
    printf("before accept\n");
    theClient = accept(listeningSocket,
               NULL,            // Address of a sockaddr structure (see explanation below)
               NULL);            // Address of a variable containing size of sockaddr struct
    printf("after accept\n");
    if (theClient == INVALID_SOCKET) {
        nret = WSAGetLastError();
        ReportError(nret, "accept()");

        WSACleanup();
        return NETWORK_ERROR;
    }


    // Send and receive from the client, and finally,
    closesocket(theClient);
    closesocket(listeningSocket);


    // Shutdown Winsock
    WSACleanup();
    return NETWORK_OK;
}


void ReportError(int errorCode, const char *whichFunc) {
   char errorMsg[92];                    // Declare a buffer to hold
                            // the generated error message
  
   ZeroMemory(errorMsg, 92);                // Automatically NULL-terminate the string

   // The following line copies the phrase, whichFunc string, and integer errorCode into the buffer
   sprintf(errorMsg, "Call to %s returned error %d!", (char *)whichFunc, errorCode);

   MessageBox(NULL, errorMsg, "socketIndication", MB_OK);
}



P.S.:
Die :: sind Bereichsauflöser und deuten an, dass globale Funktionen gemeint sind.
--
Wer früher stirbt ist länger tot.

Dieser Post wurde am 04.01.2004 um 20:33 Uhr von (un)wissender editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
05.01.2004, 16:25 Uhr
kronos
Quotenfisch
(Operator)


mit listen wird nur angegeben wieviele verbindungen angenommen werden sollen, tatsächlich angenommen werden sie mit accept. es stimmt also, dass accept "blockt".
auf anhieb fällt mir auf, das bind und listen zu wenig parameter übergeben werden. da fehlt zum beispiel das socket.
zwei tipps:
- header verwenden
- rückgabewerte prüfen
dann findest du deine fehler schnell selbst
--
main($)??<-$<='?'>>2?main($-!!putchar(
(("$;99M?GD??(??/x0d??/a:???;a"+'?'/4)
??($??)+'?'/3-2-1+$%2)??''?')):'?';??>
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
05.01.2004, 16:42 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


da kann ich kronos nur zustimmen

listen verstetzt wie das wort ja schon sagt den server auf einem port nur in Horchstellung.... Wenn ein Anfrage kommt wird diese in die Warteschlange eingereiht. Mit Accept holt man sich immer den nächsten fälligen Auftrag aus der Queue um ihn dann zu verarbeiten....
--
...fleißig wie zwei Weißbrote

Dieser Post wurde am 05.01.2004 um 16:42 Uhr von Windalf editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
05.01.2004, 17:14 Uhr
(un)wissender
Niveauwart


Hm, kronus, das ist das Problem nicht, die Funktionen werden korrekt aufgerufen.
Es gibt einmal meine bind-funktion und einmal ::bind der winapi.
Der Socket ist ein Member von TCPSocket.
Das ist ein recht seltsames Problem, ich habe jetzt eine Version geschrieben die läuft, denn Fehler in der alten Version kreise ich langsam ein.
Auf jeden Fall ist alles korrekt von der Syntax her und es gibt nie einen Errorcode (ich will den ganzen Sourcecode hier nicht posten).
Wenn ich die lösung habe sage ich bescheid, ist aber wahrscheinlich ein sehr seltsamer Fehler, wenn ich den überhaupt lokalisieren kann.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
05.01.2004, 21:07 Uhr
(un)wissender
Niveauwart


So, das folgende läuft, wenn ihr es compilieren wollt, dann vergesst nicht, es mit der winsocklib zu linken (für g++ -lwsock32).

Was aber noch nicht klappt ist, wenn zwei Server gestartet werden auf dem selben Port, dann beeendet sich der zweite einfach ohne Fehlermeldung?!
Wenn ich einen Client starte, ohne einen Server zu starten, dann müsste ich auch eine Meldung kommen a la "keiner hört mich", oder nicht?
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
05.01.2004, 21:08 Uhr
(un)wissender
Niveauwart


TCPSocket.hpp

C++:
#ifndef TCPSOCKET_HPP_INCLUDED
#define TCPSOCKET_HPP_INCLUDED

#include <windows.h>
#include <stdexcept>

class TCPSocket {
    public:
        TCPSocket();
        TCPSocket(SOCKET sock);
        virtual ~TCPSocket();
        
        int write( const void *pData,
                   unsigned int nBytes,
                   unsigned int flags = 0 );
        
        template<typename string_type >        
        int writeString( const string_type &stringToWrite );
        
        int read( void *pData, unsigned int nBytes, unsigned int flags = 0 );
        
        template<typename string_type >
        int readLine( string_type &stringToRead );                  
        void close();
    
    protected:
        void encodeWinsockErrorAndThrowException();
    
    protected:
        SOCKET m_hSocket;
    
    private:
        void init();
        void create();  
    
    private:      
        static unsigned int instanceCounter;
};

class TCPServerSocket: private TCPSocket {
    public:          
        ~TCPServerSocket() {}        
        TCPSocket accept( unsigned int port, unsigned int backlog = SOMAXCONN );
        //Von TCPSocket private geeerbt, wieder public machen.
        void close();
        
    private:
        void listen( unsigned int backlog );
        void bind(unsigned int port );
};

class TCPClientSocket: public TCPSocket {
    public:
        ~TCPClientSocket() {}
        void connect( const char *host, unsigned int nPort );
};

//templates müssen beim g++ im Header stehen!
template<typename string_type>        
int TCPSocket::writeString( const string_type &stringToWrite )
{    
    int nLetters;            
    const char * buffer = stringToWrite.c_str();
    
    if((nLetters = write(buffer, strlen(buffer) + 1) ) == SOCKET_ERROR)
        encodeWinsockErrorAndThrowException();  
                
    return nLetters;
}

template<typename string_type>
int TCPSocket::readLine( string_type &stringToRead )
{    
    unsigned int growth = 128;
    char * buffer = new char[growth];
    
    unsigned char ch = 0;
    unsigned int count;
    
    for(count = 0; ; ++count) {              
        int retCode = read( &ch, 1 );
        
        if( retCode == 0) {
            delete [] buffer;
            throw std::runtime_error("Unexpected zero read, aborted!");
        }
        
        if( retCode == SOCKET_ERROR ) {
            delete [] buffer;
            encodeWinsockErrorAndThrowException();
        }
                
        if( ch != '\n' && ch != '\r' && ch != '\t' && ch != '\0') {
            if(count == growth - 1) {
                char * tempBuffer = new char[(growth *= 2)];
                memcpy(tempBuffer, buffer, count);
                delete [] buffer;
                buffer = tempBuffer;
            }
            buffer[count] = ch;            
        }
        else {
            break;
        }
    }

    buffer[count] = '\0';
    stringToRead.assign(buffer);
    delete [] buffer;
    return stringToRead.length();
}

#endif


--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
05.01.2004, 21:08 Uhr
(un)wissender
Niveauwart


TCPSocket.cpp

C++:
#include "TCPSocket.hpp"
#include <stdexcept>

unsigned int TCPSocket::instanceCounter = 0;

TCPSocket::TCPSocket()
{                    
    try {
        if(TCPSocket::instanceCounter++ == 0)
            init();
        create();
    }
    catch(std::exception &ex) {
        if(--TCPSocket::instanceCounter == 0 )
            ::WSACleanup(); //Weil kein Destruktor?      
        throw;
    }  
}

TCPSocket::TCPSocket(SOCKET sock) : m_hSocket(sock)
{
    ++TCPSocket::instanceCounter;    
}

TCPSocket::~TCPSocket()
{
    close();
    if(--instanceCounter) {
        ::WSACleanup();
    }
}

int TCPSocket::write( const void *pData,
                      unsigned int nBytes,
                      unsigned int flags )
{
    return ::send( m_hSocket, reinterpret_cast<const char *>(pData), nBytes, flags );
}
        
int TCPSocket::read( void *pData, unsigned int nBytes, unsigned int flags )
{
    return ::recv( m_hSocket, reinterpret_cast<char *>(pData), nBytes, flags );
}
        
void TCPSocket::close()
{
    if(::shutdown( m_hSocket, 1 ) != SOCKET_ERROR) {
        char dump[3]; //Socket leeren
        while(0 != ::recv( m_hSocket, dump, 3, 0 ) );
    }
    
    if(::closesocket( m_hSocket ) == SOCKET_ERROR) {
        encodeWinsockErrorAndThrowException();
    }
}

void TCPSocket::init()
{
    WSADATA wd;
    WORD sockVersion = MAKEWORD(1, 1);
    //Version 1.1 gefragt. 0x0101
    if(::WSAStartup( sockVersion, &wd ) == 0) {      
       encodeWinsockErrorAndThrowException();      
    }
  
    //Richtige Version?.
    if ( wd.wVersion != 0x0101 ) {        
        throw std::runtime_error("Socket library must support 1.1 or greater!");      
    }
}

void TCPSocket::create()
{
    
    m_hSocket = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

    if( m_hSocket == INVALID_SOCKET ) {
        encodeWinsockErrorAndThrowException();
    }    
}

void TCPServerSocket::bind( unsigned int port)
{
    SOCKADDR_IN addr;

    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_family = AF_INET;
    addr.sin_port = ::htons( port );
    

    if(::bind( m_hSocket, (LPSOCKADDR)&addr,
               sizeof( SOCKADDR_IN ) ) == SOCKET_ERROR )
       encodeWinsockErrorAndThrowException();
}

void TCPServerSocket::listen( unsigned int backlog)
{
    if( ::listen( m_hSocket, backlog ) == SOCKET_ERROR )
       encodeWinsockErrorAndThrowException();  
}

TCPSocket TCPServerSocket::accept( unsigned int port, unsigned int backlog )
{
    
    bind(port);
    listen(backlog);  
            
    SOCKET new_sock = ::accept(m_hSocket, NULL, NULL);  
    if(new_sock == INVALID_SOCKET || m_hSocket == INVALID_SOCKET)
       encodeWinsockErrorAndThrowException();
      
    return TCPSocket(new_sock);  
}

void TCPClientSocket::connect( const char *host, unsigned int port )
{
    unsigned int ulAddr = 0;
    hostent *pEnt = ::gethostbyname( host );
    SOCKADDR_IN addr;

    if( pEnt == 0 ) {
        ulAddr = ::inet_addr( host );

        if( ulAddr == INADDR_NONE )
            throw std::runtime_error("Invalid address!");
                            
        addr.sin_family = AF_INET;        
    }
    else {
        memcpy( &ulAddr, pEnt->h_addr_list[0], sizeof( unsigned int ) );
        addr.sin_family = pEnt->h_addrtype;
    }

    addr.sin_addr.s_addr = ulAddr;
    addr.sin_port = ::htons( port );

    memset( addr.sin_zero, 0, sizeof( addr.sin_zero ) );

    if( ::connect( m_hSocket, (const sockaddr *)&addr, sizeof( SOCKADDR_IN ) )
        == SOCKET_ERROR )
    {
        encodeWinsockErrorAndThrowException();
    }    
}

void TCPSocket::encodeWinsockErrorAndThrowException()  
{        
    switch ( ::WSAGetLastError() ) {
        case WSANOTINITIALISED :
            std::runtime_error("Unable to initialise socket.");
            break;
        case WSAEAFNOSUPPORT :
            std::runtime_error("The specified address family is not supported.");
            break;
        case WSAEADDRNOTAVAIL :
            std::runtime_error("Specified address is not available from the local machine.");
            break;
        case WSAECONNREFUSED :
            std::runtime_error("The attempt to connect was forcefully rejected.");
            break;
        case WSAEDESTADDRREQ :
            std::runtime_error("Address destination address is required.");
            break;
        case WSAEFAULT :
            std::runtime_error("The namelength argument is incorrect.");
            break;
        case WSAEINVAL :
            std::runtime_error("The socket is not already bound to an address.");
            break;
        case WSAEISCONN :
            std::runtime_error("The socket is already connected.");
            break;
        case WSAEADDRINUSE :
            std::runtime_error("The specified address is already in use.");
            break;
        case WSAEMFILE :
            std::runtime_error("No more file descriptors are available.");
            break;
        case WSAENOBUFS :
            std::runtime_error("No buffer space available. The socket cannot be created.");
            break;
        case WSAEPROTONOSUPPORT :
            std::runtime_error("The specified protocol is not supported.");
            break;
        case WSAEPROTOTYPE :
            std::runtime_error("The specified protocol is the wrong type for this socket.");
            break;
        case WSAENETUNREACH :
            std::runtime_error("The network can't be reached from this host at this time.");
            break;
        case WSAENOTSOCK :
            std::runtime_error("The descriptor is not a socket.");
            break;
        case WSAETIMEDOUT :
            std::runtime_error("Attempt timed out without establishing a connection.");
            break;
        case WSAESOCKTNOSUPPORT :
            std::runtime_error("Socket type is not supported in this address family.");
            break;
        case WSAENETDOWN :
            std::runtime_error("TCPSocketwork subsystem failure.");
            break;
        case WSAHOST_NOT_FOUND :
            std::runtime_error("Authoritative Answer Host not found.");
            break;
        case WSATRY_AGAIN :
            std::runtime_error("Non-Authoritative Host not found or SERVERFAIL.");
            break;
        case WSANO_RECOVERY :
            std::runtime_error("Non recoverable errors, FORMERR, REFUSED, NOTIMP.");
            break;
        case WSANO_DATA :
           std::runtime_error("Valid name, no data record of requested type.");
            break;
        case WSAEINPROGRESS :
            std::runtime_error("Address blocking Windows Sockets operation is in progress.");
            break;
        case WSAEINTR :
            std::runtime_error("The (blocking) call was canceled via WSACancelBlockingCall().");
            break;
        default :
            std::runtime_error("Unknown error.");
            break;
  }
}



TestServer

C++:
#include "TCPSocket.hpp"
#include <cstdlib>
#include <iostream>

int main()
{
    try {
        TCPServerSocket ssocket;
        std::cout << "Waiting...\n";
        TCPSocket client = ssocket.accept(8888);
        std::string input;
        client.readLine(input);
        client.close();
        std::cout << input << "\n";              
    }
    catch(std::exception &ex) {
        std::cout << ex.what() << "\n";
    }
    system("pause");
    return 0;
}



TestClient

C++:
#include <cstdlib>
#include <iostream>
#include <string>
#include <stdexcept>
#include "TCPSocket.hpp"

int main()
{
    try {
        TCPClientSocket sock;
        sock.connect("localhost", 8888);
        std::string output("Dies ist ein langer String!");
        sock.writeString(output);
    }
    catch(std::exception &ex) {
        std::cout << ex.what() << "\n";
    }
    system("pause");
    return 0;
}


--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
05.01.2004, 22:43 Uhr
(un)wissender
Niveauwart


So, ich sollte einfach throw vor die runtime_errors schreiben, dann klappts auch mit der Fehlerbehandlung!

In void TCPSocket::init() muss es ::WSAStartup( sockVersion, &wd ) != 0
heißen, nicht == 0.

Allerdings gibt es Ärger mit dem Schließen der Sockets, ich arbeite dran.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: