Plně duplexní tok a zpětný tlak v SOCKS relayi
Navrhněte tok relaye kolem nezávislých bajtových toků, částečného I/O, omezených bufferů a zpětného tlaku místo odhadovaných velikostí odpovědí.
SOCKS handshake proběhl úspěšně. Nyní relay čte od klienta, zapisuje do cíle, čeká na úplnou odpověď a teprve potom znovu čte od klienta. Tato posloupnost může zablokovat zcela platnou aplikaci.
Jakmile je TCP tunel navázán, SOCKS nedefinuje zprávy uvnitř něj. Cíl může poslat první. Obě strany mohou posílat nezávisle. Jedna strana může poslat krátký záznam a pak čekat na odpověď druhé.
Předávejte bajty, ne odhadované transakce
Volání příjmu vrací dostupné bajty podle svých příznaků a stavu socketu. Neříká obecnému relayi, že odpověď aplikace je úplná. Čekání na naplnění libovolně velkého bufferu může bránit předání malé zprávy, kterou protějšek potřebuje k pokračování.
K obsluze obou směrů použijte stávající model souběžnosti aplikace: smyčku událostí, asynchronní I/O nebo jiný záměrně zvolený návrh. Důležité je, aby pokrok v jednom směru nevyžadoval vymyšlenou hranici zprávy ve druhém.
Udržujte dva omezené buffery čekajících dat
Data přečtená od klienta mohou stále čekat na cestu k cíli, zatímco data z cíle čekají na cestu ke klientovi. Tyto čekající bajty sledujte odděleně.
Odeslání může zapsat méně bajtů, než bylo požadováno. Nezapsanou část ponechte; nezahazujte ji ani nepřehrávejte celý buffer. Dočasně nezapisovatelný socket je důvod čekat na správnou událost připravenosti, ne se neustále točit.
Buffery omezte. Pokud je cíl pomalý, pokračující čtení neomezených klientských dat jen přesouvá frontu do paměti relaye. Zpětný tlak znamená pozastavit čtení, když je odpovídající buffer plný, a obnovit je, když zápis uvolní místo.
Konec v jednom směru vyžaduje politiku
TCP může zavřít směr odesílání, zatímco druhý směr má stále užitečná data. Rozhodněte, jak tento stav předat po vyčerpání bufferovaných bajtů, a rozlišujte řádné uzavření od chyby nebo termínu.
Nic z toho nevyžaduje, aby relay dešifroval nebo analyzoval užitečné zatížení aplikace. Potřebuje správné zpracování toku. Zvětšení samotného bufferu nedokáže opravit relay, který čeká na špatnou stranu nebo předpokládá, že každé čtení odpovídá jednomu celému požadavku.