Клієнт завершує надсилання, проксі бачить EOF, і відповідь зникає. Негайне закриття обох сокетів проксі може спричинити саме таку послідовність. У TCP-ретрансляторі впорядковане завершення в одному напрямку не означає, що інший напрямок завершився.

Розгляньмо клієнта, який надсилає запит, закриває свій бік надсилання й чекає на відповідь:

client -- request, then FIN --> proxy --> service
client <-------- reply ------- proxy <-- service

Проксі має два з'єднання TCP і два незалежно рухомі потоки байтів. Він має передати далі ознаку кінця вхідних даних після передавання байтів, що їй передують.

Спорожніть чергу перед передаванням EOF

Під час приймання ненульового розміру в потоці TCP повернення нуля означає впорядковане завершення цього вхідного потоку. Позначте цей напрямок читання як завершений. Припиніть чекати на подальші вхідні дані з нього, але збережіть байти, вже поставлені в чергу для протилежного сокета.

Коли черга від клієнта до служби спорожніє, викличте shutdown(service_socket, SHUT_WR) на сокеті POSIX. Це припиняє подальше передавання в бік служби, залишаючи напрямок від служби до клієнта доступним. Коли служба завершить свою відповідь, застосуйте дзеркальну операцію після спорожнення черги відповіді.

Закриття дескрипторів належить до моменту, коли обидва напрямки та їхні буфери, що очікують, завершені, або коли помилка чи скасування вимагають припинення. Тримайте обмежений час очікування для партнера, який ніколи не завершує свою залишкову половину.

Готовність — це запрошення до читання

Читабельний сокет може містити дані або стан EOF. Викличте recv і витлумачте результат. Додатні значення — це байти для передавання; нуль — кінець напрямку. На неблокуючому сокеті EAGAIN або EWOULDBLOCK означають, що зараз більше немає вхідних даних, а EINTR може вимагати повторної спроби. Жодне з них не є тією самою подією, що й EOF.

Не шукайте прапорець FIN у поверненому буфері байтів. TCP доставляє цьому API впорядкований потік байтів; межі пакетів і сегмент FIN не є звичайним корисним навантаженням застосунку.

Це життєвий цикл сирого байтового тунелю. HTTP-проксі, що розбирає повідомлення, все одно має поважати кадрування HTTP, а проксі, що завершує TLS, також має протокол закриття TLS. Тримайте ці протокольні рішення вище за напрямний TCP-ретранслятор.

Схожі статті