Пусть recv () только предыдущий принятый сокет - PullRequest
0 голосов
/ 22 февраля 2020

Я использую это серверное приложение:

enter image description here

Я хотел бы добавить некоторые условия к FD_ISSET() перед recv():

if (`client's socket` was the previous `accepted socket`) {
    canRecv = TRUE;
} else {
    canRecv = FALSE;
}

Это мое представление о функциональности программы:

  1. recv только из предыдущего accepted socket
  2. Ожидание окончания связи
  3. FD_CLR ()

Я не знаю, как:

  1. l oop через каждый fd с select()
  2. пусть только один recv()
  3. возвращает остальных в очередь select()

Я использую простой пример из Центра знаний IBM:

https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzab6/xnonblock.htm

1 Ответ

1 голос
/ 22 февраля 2020

Вы можете создать std::vector<int> sockets;, чтобы сохранить ваши сокеты. Проверка того, является ли это последним, который вы добавили, будет выполняться путем проверки if(current_socket == sockets[sockets.size()-1]) ...

Вот пример с вспомогательным классом для хранения списка ваших сокетов и функции для ожидания активности.

#include <cerrno>
#include <cstring>
#include <utility>
#include <vector>

constexpr unsigned other_socket    = 0b00;
constexpr unsigned server_socket   = 0b01;
constexpr unsigned latest_addition = 0b10;

class SocketList {
public:
    explicit SocketList(int server) : readfds{} { add(server); }

    void add(int s) {
        sockets.push_back(s);
        FD_SET(s, &readfds);
        if(s > max_fd) max_fd = s;
    }

    // return the ready sockets and a state for each
    std::vector<std::pair<int, unsigned>> wait() {
        int ready_sockets;
        do {
            ready_sockets = select(max_fd + 1, &readfds, nullptr, nullptr, nullptr);
        } while(ready_sockets == -1 && errno == EINTR); // retry if interrupted

        // throw if an error occured
        if(ready_sockets == -1) throw std::runtime_error(std::strerror(errno));

        std::vector<std::pair<int, unsigned>> result;

        // loop through each fd used in the select()
        for(int s : sockets) {
            if(FD_ISSET(s, &readfds)) {
                auto x = other_socket;

                if(s == sockets[0]) x |= server_socket;
                if(s == sockets[sockets.size() - 1]) x |= latest_addition;

                result.emplace_back(s, x);
            }
        }
        return result;
    }

private:
    int max_fd = 0;
    fd_set readfds;
    std::vector<int> sockets;
};

Может использоваться следующим образом:

    int server = socket(...);

    SocketList ss(server);

    // all sockets in result are ready
    auto result = ss.wait();

    for(auto [sock, state] : result) {
        if(state & server_socket) {
            // do server things on sock
        } else if(state & latest_addition) {
            // do stuff if sock was the latest addition
        } else {
            // do this if sock is not the server socket or the latest addition
        }
    }
  1. recv только из предыдущего accepted socket
  2. Дождаться окончания связи
  3. FD_CLR ()

Для этого вам действительно не нужно выбирать. Просто recv прямо на ранее принятом сокете. Как правило, это нехорошее поведение сервера, который должен обслуживать множество клиентов одновременно, поскольку плохой клиент может подключиться, ничего не отправляя, и это не позволит серверу отвечать на запросы каких-либо новых клиентов - пока плохой клиент не решит отключиться (если что когда-либо случится).

Я не знаю, как:
1. l oop через каждый fd с select()

Это показано в коде выше.

пусть только один recv()

Если у вас есть вектор result в приведенном выше примере, вы можете l oop через них и сохранить только часть, имеющую дело с latest_addition:

        if(state & latest_addition) {
            // do stuff if sock was the latest addition
        }
вернуть остальных в очередь select()

Состояние других готовых сокетов в result останется неизменным, если вы не читаете с них, поэтому они возвращаются автоматически. Это также означает, что следующий select немедленно вернется, если вы не прочитали все готовые fd, поэтому программа будет вращаться очень быстро, пока не будет выполнено какое-либо действие с последним добавленным сокетом, что эффективно делает это Программа опроса и select бесполезна.

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