Порт завершения ввод-вывода и обрыв связи или закрытие сокета

Подскажите, вот такая вот "проблема":

Предположим вот есть вот такая вот ситуация:

  • Создал сокет
  • Связал его спортом завершения
  • Соединился с удаленным сервером WSACOnnect
  • Вызвал WSASend для отправки данных на сервер и помещение задачи

отправки в очередь порта завершения.

Предположим я отправляю 10Гб данных на сервер. В какой то момент происходит следующее:

  • происходит обрыв связи у какой то из сторон.
  • обрыва связи не происходит, но удаленный сервер по какой то причине закрывает сокет.

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

То в случае с закрытием сокета на удаленном сервере, задача так навсегда и останется в порут завершения ?

Как такие случаи должны обрабатываться ?


Ответы (1 шт):

Автор решения: Alexander Ushakov

Чтоб происходит при разных сценариях зависит от используемых протоколов. Передача любых данных по сети происходит на нескольких уровнях (подробнее: https://ru.wikipedia.org/wiki/Сетевая_модель_OSI).

Если сильно упростить, то при передаче могут происходить следующие проблемы:

  1. потеряется очередной пакет данных. В случае протокола TCP эта потеря будет обнаружена и пакет будет передан повторно, получатель не заметит ничего кроме некоторой задержки. В случае протокола UDP эти данные просто не дойдут до получателя, он получит не всё что ему отправил отправитель.
  2. одна из сторон закроет сокет. В этом случае другая сторона будет уведомлена о разрыве соединения специальным паетом и тоже закроет свой сокет.
  3. пропадет связь и данные совсем перестанут ходить. В этом случае через заданное время сработает таймер и соединение на обоих сторонах будет закрыто по таймауту. Время таймаута можно настроить.

Так что ничего не зависнет, отправка в случаях 2 и 3 вернет вам ошибку, которую вы сможете обработать и понять что произошло.

Дополнение: Конкретно по случаю WSASend - результат операции отправки передается в качестве параметра в callback, задаваемый последним параметром в вызове WSASend: lpCompletionRoutine

int WSAAPI WSASend(
  SOCKET                             s,
  LPWSABUF                           lpBuffers,
  DWORD                              dwBufferCount,
  LPDWORD                            lpNumberOfBytesSent,
  DWORD                              dwFlags,
  LPWSAOVERLAPPED                    lpOverlapped,
  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

Этот callback имеет тип LPWSAOVERLAPPED_COMPLETION_ROUTINE:

void LpwsaoverlappedCompletionRoutine(
  DWORD dwError,
  DWORD cbTransferred,
  LPWSAOVERLAPPED lpOverlapped,
  DWORD dwFlags
)

где dwErrorCode - код результата передачи. При удачной отправке там будет 0 (ERROR_SUCCESS)

dwNumberOfBytesTransfered - число переданных байт. В случае ошибки - 0

→ Ссылка