SOCKET select некорректная работа

169
20 марта 2018, 01:44

Решил перестать циклом проверять все сокеты на наличие новых сообщений, и объединить всё в 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, &copy, 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, &copy, 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;
}

Вообщем я понял, что больше с сокетами работать не буду. А ещё я понял, что не нужно улучшать то, что и так прекрасно работает.

Answer 1

Во-первых результат select, то бишь количество готовых сокетов, игнорируется.

Во-вторых, проверять, готов сокет или нет следует вызовом макроса FD_ISSET, никакого индекса получать не надо:

if(0 != FD_ISSET(s, &copy))
{
   // Пытаемся читать...
}

В-третьих, может быть готово несколько сокетов.

READ ALSO
Проблема с установкой boost

Проблема с установкой boost

При установки boost через Command Prompt for VS, а именно при прописывании команды: b2exe, вылезает ошибка: ТЫЦ

165
std :: chrono Не пойму, как использовать

std :: chrono Не пойму, как использовать

Работаю над заданием по созданию игры "Танчики" (Battle city)И уже почти все готово, но не могу настроить скорость полета снарядов

153
Расширение интерфейса библиотеки

Расширение интерфейса библиотеки

В книге Брюса Эккеля "Философия С++ часть 2" автор приводит пример использование множественного наследование в качестве средства для расширения...

155
syntax error C2760. Что означает?

syntax error C2760. Что означает?

Добрый деньПомогите пожалуйста найти ошибку в коде

237