WSAStartup с RAII

  1. RAII не выполняет деструктор при вызове exit. Поэтому WSACleanup не запускается. В чем проблема? Я обнаружил, что libnet использует WSAStartup без каких-либо WSACleanup, почему?
  2. WSAStartup может вызывать много раз в одном процессе, так как же обеспечить достаточность WSACleanup?
  3. Как легко и элегантно использовать WSAStartup и WSACleanup?
  4. Кроме того, я написал этот тестовый код для теста WSAStartup без WSAClean, не обнаружил каких-либо отклонений (рост памяти или сбой...)

код:

int main(int argc, char *argv[])
{
    int res;

    while (1) {
        WSADATA wsadata;
        res = WSAStartup(0x0202, &wsadata);
        printf("WSAStartup 1 times:%d\n", res);

        if (res != 0) {
            printf("WSAStartup error:%d\n", WSAGetLastError());
            exit(1);
        }

        res = WSAStartup(0x0202, &wsadata);
        printf("WSAStartup 2 times:%d\n", res);

        if (res != 0) {
            printf("WSAStartup error:%d\n", WSAGetLastError());
            exit(1);
        }
    }

    return 0;
}

person qianchenglong    schedule 13.03.2015    source источник


Ответы (4)


1) exit() — проблема для всего элемента RAII, а не только для сокетов. Открытые файлы, память... Правильное решение - избегать exit().

2+3) Назовите столько WSACleanup, сколько WSAStartup. Я предполагаю, что вы хотите написать класс сокета с одним соединением для каждого объекта, просто вызовите WSAStartup в конструкторе и WSACleanup в деструкторе.
Оба метода используют счетчик вызовов внутри, они без проблем обрабатывают несколько вызовов.

person deviantfan    schedule 13.03.2015
comment
Нет, я просто тестирую и использую некоторые библиотеки, такие как libnet, которые вызывают WSAStartup без WSACleanup, и я также вызываю WSAStartup! - person qianchenglong; 13.03.2015
comment
@qianchenglong Кажется, я не понимаю, что ты хочешь сказать. Если библиотека без какого-либо обслуживания или другой деятельности в течение 12 лет имеет плохой код, не используйте ее. - person deviantfan; 13.03.2015
comment
На самом деле меня это не волнует. Я хочу знать, что WSAStartup без WSACleanup вызовет какие-либо проблемы, а RAII с exit как решить. - person qianchenglong; 13.03.2015
comment
I want to known WSAStartup without WSACleanup will cause any problem Возможно. Ответ находится в исходном коде Windows и может меняться с каждым обновлением. Документы требуют, чтобы вы также вызывали WSACleanup, поэтому вы должны это сделать. RAII with exit how to solve Как я уже писал выше, не используйте выход. Используйте лучший дизайн программы. - person deviantfan; 13.03.2015
comment
Итак, когда происходит socket error, как выйти из программы без прерываний RAII? - person qianchenglong; 13.03.2015
comment
Если класс сокета получает ошибку из-за необработанной функции сокета, передайте ее тому, что использует класс сокета (исключения или возвращаемое значение...). Эта вещь может решить, как действовать (повторить попытку позже, сообщить пользователю, снова делегировать это родителю...). Как только какая-то ошибка становится настолько проблематичной, что попадает в main(), вы можете завершить программу простым и безопасным способом return. - person deviantfan; 13.03.2015
comment
Если бы отказ от вызова WSACleanup был такой огромной проблемой, вам было бы запрещено использовать диспетчер задач для закрытия процессов. Эмпирически это не проблема на любой ОС Windows, которую я когда-либо использовал. - person Martin James; 13.03.2015
comment
@MartinJames Итак, только потому, что ОС может смягчить большинство вещей, вы говорите ему никогда ничего не очищать (и завершать программу из-за каждой незначительной исправимой ошибки)? - person deviantfan; 13.03.2015
comment
@deviantfan ЕСЛИ есть ресурс, который ОС может очистить, И нет основной причины для написания пользовательского кода для выполнения той же работы, нет никаких преимуществ в написании пользовательского кода и есть несколько недостатков, например. вам придется написать лишний, избыточный код, который, конечно же, будет содержать ошибки, требовать тестирования и поддержки. - person Martin James; 20.03.2015

На мой взгляд, exit уничтожит объект только тогда, когда объект размещен в стеке, статическом или глобальном. Его нельзя выделять с помощью new. В случае new объект должен быть удален явно.

Хорошей практикой является то, что WSAStartup должен вызываться при запуске приложения и WSACleanup при завершении приложения. Итак, вы можете определить класс, который выполняет эту работу в своем конструкторе и деструкторе, и определить глобальный объект этого класса. Этот класс позаботится об этом.

У вас должна быть веская причина для многократной инициализации WinSock. В противном случае выполните инициализацию только один раз, что вы можете сделать легко.

person doptimusprime    schedule 13.03.2015
comment
exit будет запускать деструктор в глобальной или статической переменной. Иногда мне нужно использовать любую библиотеку, например libnet. Я нашел в libnet, которая вызывает WSAStartup без WSACleanup. Также в моем классе иногда требуется exit, поэтому RAII не работает. - person qianchenglong; 13.03.2015
comment
Вот что я говорю. Он не будет уничтожать объекты, выделенные с помощью указателей. - person doptimusprime; 13.03.2015
comment
@qianchenglong Also In my class sometime need exit Тогда переделайте свою программу. - person deviantfan; 13.03.2015
comment
'Обратите внимание, что объекты с автоматическим сохранением не уничтожаются при вызове exit (C++).'. Кроме того, завершение процесса вызовом exit() не является проблемой, если только требования вашего приложения не вынуждают это делать, и даже в этом случае вы должны спроектировать свою систему таким образом, чтобы непреднамеренные «завершения» (например, сбой питания) не вызвать целостность данных или другие подобные проблемы при перезапуске. - person Martin James; 13.03.2015

Согласно документу MS -

Приложение может вызывать WSAStartup более одного раза, если ему необходимо получить информацию о структуре WSADATA более одного раза. При каждом таком вызове приложение может указать любой номер версии, поддерживаемый Winsock DLL.

. . .

Приложение должно вызывать функцию WSACleanup при каждом успешном вызове функции WSAStartup. Это означает, например, что если приложение трижды вызывает WSAStartup, оно должно трижды вызывать WSACleanup. Первые два вызова WSACleanup ничего не делают, кроме уменьшения внутреннего счетчика; последний вызов WSACleanup для задачи выполняет освобождение всех необходимых ресурсов для задачи.

Поэтому нормально (и рекомендуется) вызывать WSACleanup столько раз, сколько вы вызывали WSAStartup, который, в свою очередь, получает данные от WSADATA только для каждого вызова, кроме первого.

person Jay    schedule 25.05.2020

RAII не выполняет деструктор при выходе из вызова. Поэтому WSACleanup не запускается. В чем проблема?

ИМЕ, нет. ОС может самоочищаться при завершении процесса - это не глупо.

Я обнаружил, что libnet использует WSAStartup без WSACleanup, почему?

Разработчики библиотеки поняли вышеизложенное - ОС очистится, как это происходит при принудительном завершении процесса va. Диспетчер задач.

WSAStartup может вызывать много раз в одном процессе, так как же обеспечить достаточное количество WSACleanup?

Почему ты бы так поступил? Просто позвоните один раз при запуске. Работа выполнена.

Как легко и элегантно использовать WSAStartup и WSACleanup?

Вызовите WSAStartup один раз при запуске. Вызовите WSACleanup после выхода, если можете (или если хотите, или если вам от этого станет легче :).

Кроме того, я написал этот тестовый код для тестирования WSAStartup без WSAClean, не обнаружил каких-либо отклонений (рост памяти или сбой...)

ОС очищает так же, как и с потоками, файлами, памятью и т. д.

Если бы настольная ОС общего назначения не позаботилась о выделенных ресурсах после завершения процесса, она была бы непригодной для использования.

person Martin James    schedule 13.03.2015