Вы можете создать 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
}
}
recv
только из предыдущего accepted socket
- Дождаться окончания связи
- 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
бесполезна.