Решил перестать циклом проверять все сокеты на наличие новых сообщений, и объединить всё в select
. Но теперь абсолютно непонятная проблема, которая заключается в том, что все сообщения, которые адресуются разным сокетам, прилетают в самый первый сокет в fd_set
списке, что меня крайне не устраивает.
При старте проги очищаю список
FD_ZERO(&WinSocket::master);
После создания и проверки пригодности сокета отправляю его в список
FD_SET(s, &WinSocket::master);
(Все сокеты абсолютно новые, копий быть не может)
После чего запрашиваю сообщение, номер сокета мне тоже нужно узнать.
int index;
string response = WinSocket::fetchServerMessage(index);
Сама реализация
string fetchServerMessage(int & indexSock) {
string res;
fd_set copy = master;
cout << "count: " << copy.fd_count << endl;
int t = select(0, ©, nullptr, nullptr, nullptr);
for (int i = 0; i < copy.fd_count; ++i) {
cout << "i - " << i << endl;
SOCKET &sock = copy.fd_array[i];
int mret;
char buffer[2048];
mret = recv(sock, buffer, sizeof(buffer), 0);
if ((0 < mret) && (mret <= sizeof(buffer))) {
res.assign(buffer, static_cast<size_t>(mret));
res = UTF8::Convert(res.c_str());
}
if (res.size() > 1 && res[res.size() - 2] == '\r' && res[res.size() - 1] == '\n') {
indexSock = i;
cout << res << endl;
return res;
}
}
return nullptr;
}
Функция выполняется до select
и спокойно себе ждёт, пока придёт сообщение.
Но проблема в том, что даже если сообщение приходит сокету под номером 5, то эта функция все равно найдёт это сообщение у первого сокета, и, соответственно, вернёт index
равным 0, т.е. индекс первого сокета. При этом он не просто находит это сообщение у первого сокета, даже если я отправлю ответ, то он пойдёт не от пятого сокета, а снова от первого.
Как добиться той работы, которая мне нужна?
UPD
Окей, я запутался. эта функция работает как надо, т.е. получает сообщение тот сокет, который и должен его получить, и соответственно нормально отвечает. Только индекс по прежнему равен первому сокету, т.е. 0. Я запутался.
Теперь вопрос стоит иначе:
Как получить индекс активного сокета?
UPD2
Окей2, я распутался. Оказывается, select меняет тот массив, который я ему дал, именно поэтому в гайде было написано, что нужно создавать копию массива сокетов, и теперь понятно, почему у меня крашилась прога, если я передавал не копию. А меняет он массив на тот, в котором только те сокеты, в которые пришло сообщение. Всего 6 часов понадобилось, что бы разобраться. Кайф.
Итоговый код:
string fetchServerMessage(int &indexSock) {
string res;
fd_set copy = master;
int t = select(0, ©, nullptr, nullptr, nullptr);
for (int i = 0; i < t; ++i) {
SOCKET &sock = copy.fd_array[i];
int mret;
char buffer[2048];
mret = recv(sock, buffer, sizeof(buffer), 0);
if ((0 < mret) && (mret <= sizeof(buffer))) {
res.assign(buffer, static_cast<size_t>(mret));
res = UTF8::Convert(res.c_str());
if (res.size() > 1 && res[res.size() - 2] == '\r' && res[res.size() - 1] == '\n') {
for (int i = 0; i < master.fd_count; ++i) {
if (sock == master.fd_array[i])
indexSock = i;
}
return res;
}
}
return nullptr;
}
Вообщем я понял, что больше с сокетами работать не буду. А ещё я понял, что не нужно улучшать то, что и так прекрасно работает.
Во-первых результат select
, то бишь количество готовых сокетов, игнорируется.
Во-вторых, проверять, готов сокет или нет следует вызовом макроса FD_ISSET
, никакого индекса получать не надо:
if(0 != FD_ISSET(s, ©))
{
// Пытаемся читать...
}
В-третьих, может быть готово несколько сокетов.
Виртуальный выделенный сервер (VDS) становится отличным выбором
При установки boost через Command Prompt for VS, а именно при прописывании команды: b2exe, вылезает ошибка: ТЫЦ
Работаю над заданием по созданию игры "Танчики" (Battle city)И уже почти все готово, но не могу настроить скорость полета снарядов
В книге Брюса Эккеля "Философия С++ часть 2" автор приводит пример использование множественного наследование в качестве средства для расширения...