У меня есть поток загрузки по TCP в приложении (работающем на Win2k12).
Проблема в том, что соединение закрывается отправителем из-за истечения времени ожидания.
Я использовал wirehark, чтобы посмотреть, что происходит на 2 разных серверах (на одном сервере все работает нормально, на другом истекает время ожидания). Я заметил одинаковое поведение на обоих:
Когда начинается загрузка, все вроде нормально, размер окна 64k и некоторое время остается неизменным, сегменты подтверждаются. Затем в какой-то момент размер окна начинает уменьшаться, пока не станет 0. (Насколько я знаю, это нормально, получатель не может поспевать за отправителем.) Однако от получателя нет сообщения ACK или обновления окна до тех пор, пока весь буфер считывается приложением, затем обновление окна снова объявляет размер окна 64 КБ. Затем все начинается сначала. Размер окна уменьшается до нуля.
Мне это не кажется правильным. Когда приложение читает из буфера, в нем должно быть свободное место, и должно быть отправлено обновление окна, чтобы отправитель мог отправить следующий сегмент.
Еще я не понимаю поведения на отказавшем сервере. Этот сервер объявляет все большие и большие размеры окон в каждом таком цикле, в последнем цикле перед тайм-аутом размер окна был ~ 800 000. Тайм-аут возникает из-за того, что буфер не опустошается достаточно быстро. Но я понятия не имею, почему на этом сервере увеличивается размер окна? Есть ли на сервере настройка, предотвращающая это?
Верны ли мои предположения, или я что-то неправильно понял в протоколе TCP? Приветствуются любые идеи по решению этой проблемы.
Спасибо.
Если принимающий процесс не обрабатывает данные так быстро, как они могут быть переданы по сети, окно должно уменьшаться по мере получения пакетов до тех пор, пока приемный буфер не будет заполнен, и окно будет равно 0. Предполагается, что сервер все еще принимает ACK. полученные данные в этой ситуации, так что отправитель знает, что не следует передавать их повторно.
После того, как окно перешло в 0, принимающая сторона не должна сообщать о том, что в окне есть место для дополнительных данных, сразу после того, как приложение считывает другой байт из потока. Он должен как минимум подождать, пока не освободится достаточно места, чтобы соответствовать одному пакету размера MTU. Ждать намного дольше - не лучшая идея.
Динамическое изменение размера выделения памяти во время передачи - разумное поведение. Однако алгоритм должен стремиться к достижению достаточно большого размера, чтобы не создавать узких мест, но он не должен быть намного больше этого. Колебаний, как вы их описываете, быть не должно. И если принимающее приложение не успевает за поступающими данными, то размер окна увеличивать не следует.
Отправитель не должен истекать тайм-аут соединения, не отправив сначала несколько пакетов проверки активности. Если отправитель прерывает соединение без отправки пакетов проверки активности, то я бы сказал, что на отправителе есть ошибка. Если отправитель отправляет пакеты keep-alive, но получатель не отвечает на них, я бы сказал, что на получателе есть ошибка.
Вы проверили связь с каждого конца соединения, чтобы убедиться, что нет значительного сброса пакетов, вызывающего тайм-аут?