2009-12-18 16 views
5

Próbuję uniknąć TIME_WAIT w kliencie. Łączę, a następnie ustawiamy O_NONBLOCK i SO_REUSEADDR. Wywołuję odczyt dopóki nie zwróci 0. Gdy read zwraca 0, errno jest równe 0. Zinterpretowałem to jako znak, że serwer zamknął połączenie. Jeśli jednak zadzwonię pod zamknięciem, gniazdo zostanie ustawione na TIME_WAIT, co zostanie potwierdzone przez netstat.Unikanie TIME_WAIT

Ponieważ wykonuję wiele połączeń z tym samym hostem/portem, w końcu zaczynam widzieć błędy "Adres w użyciu" (patrz http://hea-www.harvard.edu/~fine/Tech/addrinuse.html).

Czy powinienem wywoływać zamknięcie po przeczytaniu zwraca 0? Jeśli nie, zwolniony zostanie deskryptor pliku?

+0

Sidenote: wartość errno jest niezdefiniowana podczas odczytu zwraca 0 - errno jest definiowana tylko po awarii. –

Odpowiedz

5

Stroną, która zainicjowała zamknięcie połączenia, jest ta, która kończy się stanem TIME_WAIT. read() Powracanie 0 powinno wskazywać, że serwer najpierw zamknął gniazdo, więc tak - powinno to oznaczać, że TIME_WAIT kończy się po stronie serwera, a klient przechodzi przez LAST_ACK. Nie można uniknąć stanu TIME_WAIT. Nawet jeśli uda ci się przenieść go z klienta na serwer, nadal nie możesz ponownie użyć tej krotki, dopóki nie zakończy się TIME_WAIT (niezależnie od tego, po której stronie jest włączona).

Ponieważ trzy części tej krotki są stałe w scenariuszu (server host, server port, client host), naprawdę masz tylko te opcje:

  • spróbować zrobić więcej porty klienckie dostępne. Niektóre systemy operacyjne domyślnie używają niewielkiego zakresu dostępnych portów dla "portów efemerycznych" (nie jestem pewien co do tego pod tym względem). W takim przypadku należy sprawdzić, czy można zmienić zakres, zmieniając konfigurację w systemie operacyjnym, lub, alternatywnie, polowanie aplikacji na działający port z bind()/connect() w pętli, dopóki połączenie nie zadziała.

  • Zwiększ liczbę dostępnych wartości client host, korzystając z wielu adresów IP na kliencie. Jednak musisz mieć aplikację bind() na jeden z tych adresów IP.

  • Poszerz listę dostępnych wartości o server host/server port, używając wielu portów i/lub adresów IP na serwerze. Klient będzie musiał wybrać jedną, z którą będzie się łączyć (round robin, losowo itd.).

  • Prawdopodobnie najlepsza opcja, jeśli jest to możliwe: zmień protokół tak, aby wykonane połączenia nie zostały zamknięte, ale przejdź do stanu "bezczynności", aby można je było ponownie użyć później, zamiast otwierać nowe połączenie (jak utrzymywanie aktywności HTTP).

+0

Przepraszam, że mogę skomentować stare pytanie, ale czy pierwszy akapit tej odpowiedzi nie powinien brzmieć "strona, z którą INICJATYWNIE zamknęło się połączenie, które kończy się w stanie TIME_WAIT"? Wydaje mi się, że pamiętam, że przeczytałem to w jakiejś książce, a także, co wydaje się być zawarte w http://hea-www.harvard.edu/~fine/Tech/addrinuse.html – zentrunix

+0

@ JoséX .: Tak, ty " w porządku. – caf

1

Później na tej samej stronie wspominają o SO_REUSEADDR. Tego właśnie potrzebujesz. Zdecydowanie chcesz zamknąć deskryptor pliku odczytu, gdy zwróci zero.

+0

Przepraszamy. Zapomniałem dodać, że ustawiłem SO_REUSEADDR. Zobacz w artykule, że nie zapobiega to błędom adresu podczas korzystania z tego samego portu/hosta. – richcollins

0

Ustawianie SO_REUSEADDR po stronie klienta nie pomaga po stronie serwera, chyba że również ustawia SO_REUSEADDR