2012-06-05 9 views
5

Mam bibliotekę innej firmy, która działa jako serwer HTTP. Przekazuję mu adres i port, który następnie wykorzystuje do nasłuchu połączeń przychodzących. Ta biblioteka słucha w taki sposób, że nie otrzymuje wyłącznego korzystania z portu i adresu, do którego jest przypisana. W rezultacie mogę słuchać tego samego portu wiele razy.Jak sprawdzić, czy port TCP jest już odsłuchiwany?

Potrzebuję uruchomić wiele wystąpień tego serwera HTTP w tym samym procesie. Każda instancja ma domyślny port, ale jeśli ten port nie jest dostępny, powinien użyć następnego dostępnego portu. Tutaj jest mój problem; Mogę skończyć z dwoma serwerami HTTP nasłuchującymi na tym samym porcie.

Nie mogę zmienić kodu serwera HTTP i serwer HTTP nie ostrzeże mnie, jeśli nie może nasłuchiwać na porcie, który mu podaję, więc muszę być w stanie sprawdzić, czy port jest już w użyciu przed uruchomieniem każdego serwera HTTP . Próbowałem sprawdzić, czy port jest już odsłuchiwany przez powiązanie mojego własnego gniazda z ustawieniem SO_REUSEADDR na FALSE i SO_EXCLUSIVEADDRUSE ustawione na TRUE, ale wywołania bind i listen zarówno się powiodą, gdy istniejący serwer HTTP już nasłuchuje na tym porcie.

W jaki sposób ten serwer HTTP osiąga ten efekt i jak dokładnie sprawdzić, czy port jest słuchany w ten sposób?

+0

Czy jest jakiś powód, dla którego musisz korzystać z tej konkretnej biblioteki serwerów HTTP? Biorąc pod uwagę, że jest on uszkodzony i nie masz nad nim wystarczającej kontroli, a nawet dostępu do tego, co robi, aby to zadziałało, przełączanie wydaje się bardzo dobrym pomysłem. – abarnert

+0

Z ciekawości, która to biblioteka? –

+0

"Ta biblioteka słucha w taki sposób, że nie otrzymuje wyłącznego korzystania z portu i adresu, do którego jest przypisana". W TCP nie jest to możliwe. Jedyną formą udostępniania portów, która jest możliwa w TCP, jest powiązanie z różnymi lokalnymi adresami IP i tym samym numerem portu. Musisz ponownie zbadać, a następnie sformułować swoje pytanie. – EJP

Odpowiedz

4

Szybką i brudną metodą byłoby spróbowanie connect() do portu na localhost. Jeśli wywołanie connect() powiedzie się, to wiesz, że port jest aktualnie słuchany (przez kogokolwiek, kto otrzymał połączenie). Jeśli połączenie się nie powiedzie (w szczególności z ECONNREFUSED), możesz być prawie pewien, że nikt nie słucha na tym porcie.

Oczywiście, tutaj jest stan wyścigu: Nic tak naprawdę nie powstrzymuje innego programu od wtargnięcia do portu i chwycenia portu natychmiast po wykonaniu powyższego testu, ale zanim zdążysz się połączyć z portem samemu. Powinieneś więc wziąć wynik testu jako podpowiedź od bezwzględnej reguły i (miejmy nadzieję) mieć jakiś sposób na jej obsługę, jeśli później dowiesz się, że port jest już w użyciu.

+0

Jego zamierzony kod testowy będzie miał dokładnie taki sam stan wyścigu (lub raczej będzie miał taki sam stan wyścigu, jeśli zadziałał ...). I naprawdę, nie da się tego uniknąć, biorąc pod uwagę jego projekt. – abarnert

+0

(Powyższe wyjaśnia, dlaczego dałem ci +1 pomimo warunków wyścigu, nie zgadzając się z twoją odpowiedzią lub czymś w tym stylu). – abarnert

2

Użyj numeru portu 0. System wybierze wolny port.

+0

Nie mam dostępu do serwera HTTP gniazdo wewnętrzne, więc jeśli przekażę 0 jako port, nie mogę odzyskać portu, który podał system operacyjny. –

+0

Następnie połącz gniazdo za pomocą portu 0, użyj 'getsockaddr', aby znaleźć wybrany numer portu, zainicjuj serwer HTTP przy użyciu tego samego portu, a następnie zamknij tymczasowe gniazdo. –

1

http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx wyjaśnia, w jaki sposób różne opcje wchodzą w interakcje.

Nie podałeś nam prawie wystarczających informacji, aby powiedzieć nam dokładnie, co dzieje się w twoim przypadku użycia, ale mogę popracować nad jednym przypadkiem użycia, który wyglądałby jak to, co widzisz.

Załóżmy, że jesteś na Win 2003 lub nowszym, a podstawową kartą NIC jest 10.0.0.1, a wszystko działa na tym samym koncie użytkownika.

Pojawia się pierwsze wystąpienie aplikacji, a kod testowy próbuje powiązać 10.0.0.1:12345 z SO_EXCLUSIVEADDREUSE. Oczywiście to działa.

Zamknij gniazdo, a następnie powiedz serwerowi HTTP, aby nasłuchiwał portu 12345. Łączy 0.0.0.0:12345 z SO_REUSEADDR, co oczywiście działa.

Teraz pojawia się druga instancja aplikacji, a Twój kod testowy próbuje powiązać 10.0.0.1:12345 z SO_EXCLUSIVEADDREUSE. Zgodnie z wykresem w artykule MSDN, który działa.

Zamknij gniazdo, a następnie powiedz serwerowi HTTP, aby nasłuchiwał portu 12345. Łączy 0.0.0.0:12345 z SO_REUSEADDR, który działa.

Jeśli to jest problem, zakładając, że nie można uzyskać serwera HTTP, aby powiązać określony adres, można rozwiązać problemy, używając 0.0.0.0 w kodzie testowym.(Oczywiście, jeżeli jest to jeden z setek możliwych problemów, to rozwiązanie nie zadziała.)

Jeśli nie wiesz, jakie opcje gniazd, adres itp. Używa serwer HTTP i nie mieć źródło, wystarczy uruchomić go w debugerze i zlikwidować odpowiednie połączenia.