Ответ 1
TCP-окна используются для управления потоками между одноранговыми узлами соединения. С каждым пакетом ACK хост отправляет поле "размер окна". В этом поле указывается, сколько байтов данных, которые хост может получить до его заполнения. Отправитель не должен отправлять больше, чем этот объем данных.
Окно может заполнить, если клиент не получает данные достаточно быстро. Другими словами, буферы TCP могут заполняться, пока приложение не выполняет что-то другое, кроме чтения из своего сокета. Когда это произойдет, клиент отправит пакет ACK с установленным битом "полный пол". В этот момент сервер должен прекратить отправку данных. Любые пакеты, отправленные на машину с полным окном, не будут подтверждены. (Это приведет к тому, что отправитель с плохой производительностью будет ретранслировать. Хорошо зарекомендовавший себя отправитель будет просто накапливать исходящие данные. Если буфер на отправляющей стороне тоже заполняется, тогда приложение-отправитель будет блокировать, когда оно попытается записать больше данных в сокет!)
Это стойка TCP. Это может произойти по многим причинам, но в конечном итоге это означает, что отправитель передает быстрее, чем считывает приемник.
Как только приложение на принимающей стороне вернется к чтению из сокета, оно сбрасывает некоторые из буферизованных данных, что освобождает некоторое пространство. Получатель затем отправит пакет обновления окна, чтобы сообщить отправителю, сколько данных он может передать. Отправитель начинает передавать свои буферизованные данные, и трафик должен нормально работать.
Конечно, вы можете получить повторные киоски, если приемник постоянно медленно.
Я сформулировал это так, как будто отправитель и получатель отличаются друг от друга, но на самом деле оба партнера обмениваются обновлениями окна с каждым пакетом ACK, и каждая из сторон может заполнить свое окно.
Общее сообщение состоит в том, что вам не нужно напрямую отправлять пакеты обновления окна. На самом деле было бы плохой идеей подделать один.
Что касается исключения, которое вы видите... это вряд ли будет вызвано или предотвращено пакетом обновления окна. Однако, если клиент не читает достаточно быстро, вы можете потерять данные. На вашем сервере вы должны проверить возвращаемое значение из своих вызовов Socket.write(). Это может быть меньше количества байтов, которые вы пытаетесь записать. Это происходит, если буфер передачи отправителя заполняется, что может произойти во время остановки TCP. Возможно, вы теряете байты.
Например, если вы пытаетесь записать 8192 байт при каждом вызове для записи, но один из вызовов возвращает 5691, тогда вам нужно отправить оставшиеся 2501 байт при следующем вызове. В противном случае клиент не увидит оставшуюся часть этого блока 8K, и ваш файл будет короче на стороне клиента, чем на стороне сервера.