2011-08-08 80 views
2

我們有練習以面向對象的風格編寫web服務器。 所以我們爲WinSockets創建了一個類。我們希望循環主要部分(從接受到發送)以逐個處理連接(僅用於啓動;稍後將實施多線程)。OOP套接字不等待接受()

問題:第一次,建立連接一切正常,但服務器不會等待下一個連接接受。它說,它有一個連接,但是該描述符會引發一個錯誤,並顯示errornr「No Error」。

主:

NetInterface *socket; 
#ifdef __unix__ 
    socket = new UnixSocket(); 
#elif __WIN32__ || _MSC_VER 
    socket = new WinSocket(); 
#else 
    printf("Ihr System wird nicht Unterstützt"); 
#endif 

socket->socketInit(PORT); 

printf("server: waiting for connections...\n"); 
while(1) { // main accept() loop 
    char *their_addr = socket->akzeptieren(); 
    if(their_addr == NULL) { 
     continue; 
    } 

    printf("server: got connection from %s\n", s); 

    socket->empfangen(); 

    cout << socket->getInPacket() << endl; 
} 

WINSOCKET

class WinSocket : virtual public NetInterface 
{ 
private: 
    WSADATA wsaData; 
    int iResult; 

    SOCKET sockfd; 
    SOCKET new_fd; 

    struct addrinfo *servinfo; 
    struct addrinfo hints; 
    struct addrinfo *p; 

    int iSendResult; 
    string incoming; 
    int recvbuflen; 

    char s[INET6_ADDRSTRLEN]; 

    struct sockaddr_storage their_addr; // connector's address information 
    socklen_t sin_size; 

    int rv; 

public: 
    WinSocket(); 
    int socketInit(const char *port); 
    char *akzeptieren(); 
    void empfangen(); 
    void senden(string s); 
    string getInPacket(); 
    void *get_in_addr(struct sockaddr *sa); 
}; 

[....] 

char *WinSocket::akzeptieren(){ 
    sin_size = sizeof(their_addr); 
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); 
    if (new_fd == INVALID_SOCKET) { 
     perror("accept"); 
     return NULL; 
    } 
    inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); 
    return s;  
} 

回答

2

我覺得你很困惑。你通常應該有2個插座:1個用於接受連接(你已經有這個)和1個用於交換數據(返回new_fdaccept()WinSocket:akzeptieren())。

在大多數框架,大的區別監聽套接字和流套接字之間進行:

// oversimplified interface. 
class Listener 
{ 
public: 
    Listener (const std::string& host, const unsigned short port); 
    Stream * accept(); 
}; 

// oversimplified interface. 
class Stream 
{ 
public: 
    const std::string peer() const; 
    size_t send (const void * data, size_t size); 
    size_t recv (  void * data, size_t size); 
}; 

所以,你的代碼應該是這樣的:

const std::string host = "127.0.0.1"; 
const unsigned short port = 1234; 
Listener listener(host, port); 
while ((stream = listener.accept()) 
{ 
    std::cout 
     << "Connection from '" << stream->peer() << "'." 
     << std::endl; 
    stream->send("Hello, world!", 13); 
    delete stream; // close and shutdown. 
} 

然後,你可以有:

class WinListener; 
class WinStream; 

並使整個事情多線程。

注意:這似乎是一個要求(轉讓?),所以我不會建議你做別的。但是,在真實的生產系統中,這不是一個好的服務器設計。您最終可能想了解有關高效異步I/O的I/O completion port,epollkqueue子系統。