Процедура завершения сокета Windows после closesocket

Во время работы с сокетами Windows в режиме перекрытия и использования подпрограмм завершения (поэтому IOCP) для обратной связи я обнаружил следующий любопытный случай:

  1. Откройте сокет сервера, используя listen а также AcceptEx,
  2. Подключите клиентский сокет к указанному порту, используя ConnectEx

Теперь у нас есть (как минимум) 3 сокета: 1 список сокетов, сокет, подключенный к клиенту, и сокет, подключенный к серверу.

после передачи некоторых данных мы закрываем подключенные к серверу и клиенту сокеты shutdown, После этого шага обе розетки закрываются closesocket,

В настоящее время: просто чтобы убедиться, что у нас нет ожидающей процедуры завершения, я выдаю следующее (псевдокод):

пока SleepEx( 0, TRUE) == WAIT_IO_COMPLETION делать;

Я думал, что теперь будет спасение, чтобы освободить память о OVERLAPPED структуры, используемые WSARecv а также WSASend,

После этого момента, когда поток снова переходит в состояние оповещения, для сокета, подключенного к серверу, выполняется еще один обратный вызов процедуры завершения с ошибкой 10053, но с использованием OVERLAPPED Структура, которую мы только что освободили. Это использование памяти после освобождения.

Вопрос:

Когда вы можете быть уверены, что обратные вызовы завершения больше не выдаются для сокета с использованием перекрывающегося ввода-вывода с использованием процедур завершения?

1 ответ

Решение

Вам нужно дождаться завершения ввода-вывода (закрытие сокета отменит невыполненные запросы и вы получите обратный вызов завершения).

ОС владеет структурой OVERLAPPED и связанным буфером до тех пор, пока вы не выполните синхронизацию по завершении события (ожидая hEvent или получение БТР). Вы не можете ничего сделать с буфером, пока не получите этот обратный вызов, и вы определенно не должны его освобождать. Подождите, пока ОС скажет вам, что она больше не нужна.

Обратите внимание, что отмена не обязательно приводит к немедленному завершению, поскольку драйвер может синхронизироваться с аппаратными запросами и отмечать завершение IRP только при изменении состояния оборудования. (Это будет необходимо, если используется DMA, но может быть сделано для других операций только для согласованности). SleepEx Показанный вами цикл не гарантирует сбор всех отмен.

Следите за каждым сокетом ожидающих операций и используйте WaitForSingleObjectEx вместо SleepEx, явно ждать каждого.

Другие вопросы по тегам