Узнайте, была ли розетка принята или нет - PullRequest
0 голосов
/ 24 января 2020

У меня есть базовый c пример использования poll() метода:

struct pollfds fds[5];
int nfds = 1;

fds[0].fd = listen_sd;
fds[0].events = POLLIN;

while(1) {
    int ret = poll(fds, nfds, 0);

    if (ret < 0) {
        exit(1);
    }

    int size = nfds;

    for (int i = 0; i < size; i++) {
        if (fds[i].revents == 0) {
            continue;
        }

        if (fds[i].revents != POLLIN) {
            exit(1);
        }

        if (fds[i].fd == listen_sd) {
            // Something happened on the server
            // If there is a client which wasn't accepted yet, it returns its fd
            int new = accept(listen_sd, null, null);
            // If there is a client which was already accepted,
            // it doesn't return anything, just loop in accept() method

        } else {
            // Something happened on a different socket than the server
        }
    }
}

Все сообщения от клиентов будут проходить через сокет сервера.

Это означает, что всегда что-то происходило на сокет сервера, не так ли?

Но как мне сделать что-то вроде этого (в истинном состоянии):

  • Попробуйте принять сокет, какая-то функция должна возврат: сокет уже принят, сокет еще не принят.

  • Когда сокет уже принят - получить данные.

  • Когда сокет еще не принят - примите сокет и получите данные.

1 Ответ

1 голос
/ 24 января 2020

На стороне сервера TCP-сокет, прослушивающий соединения, перейдет в читаемое состояние, когда клиентское соединение ожидает подтверждения. Вызовите accept(), чтобы фактически принять соединение, и затем вы можете начать мониторинг состояний чтения / записи / закрытия в новом сокете TCP, возвращаемом accept(). Это совершенно отдельный сокет, чем тот, который прослушивает соединения. Добавьте его в массив pollfds, чтобы вы могли одновременно опрашивать его и прослушивающий сокет.

Попробуйте что-то вроде этого:

#include <vector>

std::vector<pollfds> fds;

{
pollfds listen_pf;
listen_pf.fd = listen_sd;
listen_pf.events = POLLIN;
listen_pf.push_back(listen_pf);
}

while (true) {
    int ret = poll(fds.data(), fds.size(), 0);
    if (ret < 0) {
        exit(1);
    }

    size_t i = 0, size = fds.size();

    while (i < size) {
        if (fds[i].revents & POLLIN) {
            if (fds[i].fd == listen_sd) {
                // accept a pending client connection...
                int client_sd = accept(listen_sd, NULL, NULL);
                if (client_sd != -1) {
                    pollfds client_pf;
                    client_pf.fd = client_sd;
                    client_pf.events = POLLIN | POLLOUT | POLLRDHUP;
                    fds.push_back(client_pf);
                }
            }
            else {
                // read data from fds[i].fd as needed...
                if (read fails) {
                    fds.erase(fds.begin()+i);
                    --size;
                    continue;
                }
            }
        }

        if (fds[i].revents & POLLOUT) {
            // write pending data to fds[i].fd as needed ...
            if (write fails) {
                fds.erase(fds.begin()+i);
                --size;
                continue;
            }
        }

        if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
            if (fds[i].fd == listen_fd) {
                exit(1);
            }
            else {
                fds.erase(fds.begin()+i);
                --size;
                continue;
            }
        }

        ++i;
    }
}

На стороне клиента TCP сокет, соединяющийся с сервером, перейдет в состояние записи для записи, когда connect() успешен, и соединение с сервером полностью установлено и готово к вводу / выводу.

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