ООП сокеты не ждут, чтобы принять () - PullRequest
2 голосов
/ 08 августа 2011

у нас есть упражнение для программирования веб-сервера в объектно-ориентированном стиле.Итак, мы создали класс для WinSockets.Мы хотели зациклить основную часть (от принятия до отправки), чтобы обрабатывать соединения одно за другим (просто для запуска; многопоточность будет реализована позже).

Проблема: в первый раз, когда установилось соединение, всехорошо, но тогда сервер не ждет следующего соединения для принятия.Он говорит, что установил соединение, но этот дескриптор выдает ошибку с ошибкой nr «Нет ошибок».

main:

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 Ответ

2 голосов
/ 08 августа 2011

Я думаю, вы в замешательстве. Обычно у вас должно быть 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;

И сделать все это многопоточным.

Примечание : это требование (задание?), Поэтому я не предлагаю вам поступить иначе. Однако в реальной производственной системе это не очень хороший дизайн сервера. Возможно, вы захотите прочитать о подсистемах порт завершения ввода / вывода , epoll и kqueue для эффективной асинхронной операции ввода-вывода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...