OOP套接字不等待accept()

时间:2011-08-08 14:09:02

标签: c++ oop webserver

我们练习以面向对象的方式编写Web服务器。 所以我们为WinSockets创建了一个类。我们想循环主要部分(从接受到发送)逐个处理连接(只是为了启动;多线程将在稍后实现)。

问题:第一次建立连接一切正常,但是,服务器不等待下一个连接接受。它说,它有一个连接,但该描述符抛出错误,错误“无错误”。

主:

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;       
}

1 个答案:

答案 0 :(得分:2)

我觉得你很困惑。您通常应该有2个套接字:1个用于接受连接(您已经拥有此套接字),1个用于交换数据(从new_fd调用accept()中的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 portepollkqueue子系统。