Vraag Hoe maak je een socket met kracht dicht in TIME_WAIT?


Ik voer een bepaald programma op Linux uit dat soms vastloopt. Als je het daarna snel opent, luistert het naar socket 49201 in plaats van naar 49200 zoals het de eerste keer deed. netstat laat zien dat 49200 zich in een TIME_WAIT-status bevindt.

Is er een programma dat u kunt uitvoeren om dat socket onmiddellijk uit de TIME_WAIT-status te verwijderen?


109
2017-09-03 12:57


oorsprong


Als je hier bent vanwege "te veel TIME_WAIT op server ", net sla door de eerste drie antwoorden die de vraag vermijden in plaats van ze te beantwoorden. - Pacerier


antwoorden:


/etc/init.d/networking restart

Laat me het uitwerken. Transmission Control Protocol (TCP) is ontworpen om een ​​bidirectioneel, geordend en betrouwbaar protocol voor gegevensoverdracht tussen twee eindpunten (programma's) te zijn. In deze context betekent de term betrouwbaar dat de pakketten opnieuw worden verzonden als deze in het midden verloren gaan. TCP garandeert de betrouwbaarheid door Acknowledgement (ACK) -pakketten terug te sturen voor een enkele of een reeks pakketten die zijn ontvangen van de peer.

Dit geldt hetzelfde voor de besturingssignalen zoals beëindigingsaanvraag / antwoord. RFC 793 definieert de TIME-WAIT-status als volgt:

TIJD-WACHT - betekent wachten   genoeg tijd om te slagen om zeker te zijn       de externe TCP ontving de bevestiging van zijn verbinding       beëindigingsverzoek.

Zie het volgende TCP-toestandsdiagram: alt text

TCP is een bidirectioneel communicatieprotocol, dus wanneer de verbinding tot stand is gebracht, is er geen verschil tussen de client en de server. Ook kan elk van beide partijen stoppen en moeten beide peers het eens worden over het sluiten om een ​​bestaande TCP-verbinding volledig te sluiten.

Laten we de eerste noemen om de stoppen te roepen als de actieve dichterbij, en de andere de passieve dichterbij. Wanneer de actieve closer FIN verzendt, gaat de status naar FIN-WAIT-1. Vervolgens ontvangt het een ACK voor de verzonden FIN en gaat de status naar FIN-WAIT-2. Zodra het FIN ook van de passieve closer ontvangt, stuurt de actieve closer de ACK naar de FIN en gaat de status naar TIME-WAIT. Als de passieve closer de ACK niet heeft ontvangen bij de tweede FIN, wordt het FIN-pakket opnieuw verzonden.

RFC 793 stelt de TIME-OUT in op tweemaal de maximale levensduur van het segment of 2MSL. Sinds MSL is de maximale tijd dat een pakket rond het internet kan rondzwerven, ingesteld op 2 minuten, 2MSL is 4 minuten. Omdat er geen ACK is voor een ACK, kan de actieve closer niets anders doen dan 4 minuten wachten als hij correct voldoet aan het TCP / IP-protocol, voor het geval de passieve verzender de ACK niet heeft ontvangen in zijn FIN (theoretisch) .

In werkelijkheid zijn ontbrekende pakketten waarschijnlijk zeldzaam en zeer zeldzaam als het allemaal gebeurt binnen het LAN of binnen een enkele machine.

Om de vraag woordelijk te beantwoorden, Hoe kan ik gedwongen een socket sluiten in TIME_WAIT ?, ik zal nog steeds bij mijn oorspronkelijke antwoord blijven:

/etc/init.d/networking restart

Praktisch gezien zou ik het zo programmeren dat het TIME-WAIT-status negeert met de optie SO_REUSEADDR zoals WMR genoemd. Wat doet SO_REUSEADDR precies?

Deze socketoptie vertelt de kernel   dat zelfs als deze poort bezet is (in
  de TIME_WAIT-status), ga je gang en   hergebruik het hoe dan ook. Als het druk is, maar   met een andere staat, zal je nog steeds krijgen   een reeds in gebruik zijnde adresfout. Het   is handig als uw server is afgesloten   naar beneden en vervolgens meteen opnieuw opgestart   terwijl sockets nog steeds actief zijn op zijn   haven. Houd er rekening mee dat als   onverwachte gegevens komen binnen, dat kan het zijn   verwar uw server, maar terwijl dit   is mogelijk, het is niet waarschijnlijk.


139
2017-09-03 13:11



Geweldig antwoord, maar niet het juiste antwoord op zijn vraag. Het opnieuw opstarten van het netwerk zou werken, maar dan zou het opnieuw opstarten, dus dit kan niet goed zijn. - Chris Huang-Leaver
@Chris Huang-Leaver, de vraag is "Is er een programma dat je kunt uitvoeren om die socket onmiddellijk uit de TIME_WAIT-status te dwingen?" als rebooten als een programma kan worden beschouwd, dan zou het ook een goed antwoord zijn. Waarom denk je dat dit niet goed kan zijn? - Eugene Yokota
WMR heeft het meest bruikbare antwoord (dat is wat ik doe als ik dit soort problemen tegenkom). Het opnieuw opstarten van het netwerk is te ingrijpend om een ​​oplossing te zijn en kan langer duren dan alleen wachten op de time-out. Het juiste antwoord op zijn vraag is 'Nee', maar SO laat je geen twee letterantwoorden typen :-) - Chris Huang-Leaver
oke oke, de volgende keer dat een proces SIGTERM vasthoudt, sla ik gewoon mijn computer kapot in plaats van hem te repareren. - Longpoke


Ik weet niet of je de broncode hebt van dat specifieke programma dat je gebruikt, maar als dat zo is, kun je SO_REUSEADDR gewoon instellen via setsockopt(2) waarmee je hetzelfde lokale adres kunt binden, zelfs als de socket in TIME_WAIT staat (tenzij die socket actief luistert, zie socket(7)).

Zie de. Voor meer informatie over de TIME_WAIT-status Veelgestelde vragen over Unix-socket.


50
2017-09-03 13:17



maar ik kreeg de reeds gebonden fout niet. wanneer ik het programma opnieuw uitvoer het luistert in post (123456) ook kan ik a zien dat het systeem TIME_WAIT voor die haven toont maar nog kan ik verbinden. waarom? - Jayapal Chandran
Zelfs met SO_REUSEADDR is het nog steeds mogelijk om de foutmelding 'Adres al in gebruik' te krijgen. Raadpleeg voor meer informatie hea-www.harvard.edu/~fine/Tech/addrinuse.html. - Jingguo Yao
@WMR SO_REUSEADDR "sluit" geen socket. Het stelt u alleen in staat om degenen die al zijn geopend opnieuw te gebruiken. Dus de vraag is nog steeds: "Hoe je een socket met geweld sluit TIME_WAIT?" - Pacerier


Voor zover ik weet is er geen manier om de socket met geweld buiten het schrijven van een betere signaalhandler in je programma te sluiten, maar er is een / proc-bestand dat bepaalt hoe lang de time-out duurt. Het bestand is

/proc/sys/net/ipv4/tcp_tw_recycle

en je kunt de time-out op 1 seconde instellen door dit te doen:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 

Echter, deze pagina bevat een waarschuwing over mogelijke betrouwbaarheidsproblemen bij het instellen van deze variabele.

Er is ook een gerelateerd bestand

/proc/sys/net/ipv4/tcp_tw_reuse

die bepaalt of TIME_WAIT sockets opnieuw kunnen worden gebruikt (vermoedelijk zonder enige time-out).

Overigens waarschuwt de kerneldocumentatie u ervoor om geen van deze waarden te veranderen zonder 'advies / verzoeken van technische experts'. Wat ik niet ben.

Het programma moet zijn geschreven om te proberen de poort 49200 te binden en vervolgens met 1 te verhogen als de poort al in gebruik is. Daarom, als u de broncode beheert, kunt u dit gedrag wijzigen om een ​​paar seconden te wachten en het opnieuw proberen op dezelfde poort, in plaats van te verhogen.


32
2017-09-03 13:24



denk dat de tweede twee voorbeelden moeten zijn s / rw / tw / ik zou bewerken, maar missen voldoende rep.
Genomen uit kerneldocumentatie: Let op. Zowel tcp_tw_recycle als tcp_tw_reuse kunnen problemen veroorzaken. U moet niet inschakelen zonder de netwerktopologie te begrijpen tussen de knooppunten die worden gebruikt of gebruikt door het knooppunt waarop de parameter is ingeschakeld. Verbindingen die lopen via knooppunten die op de hoogte zijn van TCP-verbindingsstatussen, zoals firewall, NAT of load balancer, kunnen frames beginnen te laten vallen vanwege de instelling. Het probleem zal zichtbaar worden wanneer er voldoende groot aantal verbindingen is.
Instellen op 1 werkt voor toekomstige verbindingen, maar hoe zit het met de huidige verbindingen die al zijn geopend? - Pacerier


Eigenlijk is er een manier om een ​​verbinding te doden - killcx. Ze beweren dat het werkt in elke staat van de verbinding (die ik niet heb geverifieerd). Je moet de interface weten waar communicatie plaatsvindt, het lijkt standaard uitgegaan van eth0.

UPDATE: een andere oplossing is snijder die in sommige repositories van linux distributies zit.


16
2017-10-30 17:32



Bedankt! Dit hulpprogramma werkt geweldig! Heeft me gered van het opnieuw opstarten van een lange baan. - Zanson


Een andere optie is om de optie SO_LINGER te gebruiken met een time-out van 0. Op deze manier, wanneer u sluit, wordt de socket gedwongen afgesloten, waarbij een RST wordt verzonden in plaats van in het FIN / ACK-sluitgedrag te gaan. Hiermee wordt de TIME_WAIT-status vermeden en is deze mogelijk voor sommige toepassingen beter geschikt.


3
2018-06-10 22:33



Het verliest ook alle uitgaande gegevens die nog onderweg zijn en kan een fout aan het andere einde veroorzaken. Niet aangeraden. - user207421
@EJP Niet vroeg opblijven is bijna altijd de juiste oproep. Netwerken is niet betrouwbaar, en vechten dat dingen zal vertragen. Een gecrashte app kan er niet van uitgaan dat gegevens veilig zijn gemaakt. - Tobu
Eigenlijk zou ik dit elke dag aanraden wanneer het andere eindpunt een met fouten uitgeruste, ingebedde industriële busgateway is die zijn eigen applicatielaag betrouwbaar transport via TCP implementeert, waarbij het transport voorkomt dat de verbinding ooit wordt gesloten tenzij deze RST ontvangt en dus vol raakt de verbindingslimiet op die gateway. Er. Ik gaf je een heel specifiek en heel reëel voorbeeld dat helaas vereist dat je je toevlucht neemt tot hacks zoals deze. - andyn
@Tobu Netwerken is niet betrouwbaar, maar TCP probeert dat wel te zijn, en dat slechter maken betekent niet dat iets beter maken, en TCP zijn werk laten doen, betekent niet dat je iets 'vecht'. - user207421


Een alternatieve oplossing zou zijn om een ​​betrouwbare proxy- of poort-doorstuursoftware te hebben die luistert naar poort 49200 en vervolgens de verbinding doorstuurt naar een van de verschillende instanties van uw minder betrouwbare programma met behulp van verschillende poorten ... HAPROXY komt voor de geest.

Overigens is de poort waar je verbinding mee maakt vrij hoog. U kunt proberen een ongebruikte te gebruiken net boven het bereik 0-1024. Het is minder waarschijnlijk dat uw systeem een ​​lager poortnummer gebruikt als een kortstondige poort.


2
2017-08-21 20:28





TIME_WAIT is het meest voorkomende probleem bij socket-programmering van client-serverarchitectuur. Wacht een paar seconden met proberen periodiek is de beste oplossing voor. Voor real-time applicaties die ze nodig hebben, moet de server onmiddellijk opstaan Er is een SO_REUSEADDR-optie voor hen.


0
2017-10-13 19:07