Se o processo de recebimento não estiver processando dados tão rápido quanto eles podem ser transferidos pela rede, a janela deverá ficar menor à medida que os pacotes forem recebidos até que o buffer de recebimento esteja cheio e a janela seja 0. O servidor ainda está supostamente para ACK os dados recebidos nesta situação, de tal forma que o remetente sabe não retransmiti-lo.
Quando a janela for para 0, a extremidade receptora não deve anunciar que há espaço na janela para mais dados imediatamente após o aplicativo ler outro byte do fluxo. Deve pelo menos esperar até que haja espaço livre suficiente para corresponder a um pacote com tamanho de MTU. Esperar muito mais que isso não é uma boa ideia.
Redimensionar dinamicamente a alocação de memória durante a transferência é um comportamento sensato. No entanto, o algoritmo deve procurar convergir em um tamanho que seja grande o suficiente para não causar um gargalo, mas não deve ser muito maior do que isso. Flutuação do jeito que você descreve, não deveria estar acontecendo. E se o aplicativo de recebimento não conseguir acompanhar os dados que chegam, o tamanho da janela não deve ser aumentado.
O remetente não deve expirar a conexão sem enviar alguns pacotes de manutenção primeiro. Se o remetente expirar a conexão sem enviar pacotes keep-alive, então eu diria que há um bug no remetente. Se o remetente enviar pacotes keep-alive, mas o receptor não responder a eles, então eu diria que há um bug no receptor.
Você inspecionou a comunicação de cada extremidade da conexão para garantir que não haja queda significativa de pacotes causando o tempo limite?