Jak rozumiem, dzieje się tak, gdy klient wysyła żądanie połączenia:
- Serwer będzie powiązany z określonym numerem portu. Numer portu jest zawsze powiązany z procesem nasłuchiwania. Ponieważ tylko serwer nasłuchuje połączeń przychodzących, nie musimy wiązać się po stronie klienta
- Serwer będzie nasłuchiwał na tym numerze portu.
- Klient wyśle
connect()
zapytanie. - Serwer zaakceptuje żądanie za pomocą
accept()
. Gdy tylko serwer zaakceptuje żądanie klienta, jądro przydziela losowy numer portu dla serwera w celu dalszego,send()
areceive()
ponieważ ten sam numer portu na serwerze nie może być używany do wysyłania i nasłuchiwania, a poprzedni port jest nadal nasłuchuje nowych połączeń
Biorąc to wszystko pod uwagę, w jaki sposób serwer dowiaduje się, na którym porcie odbiera klient? Wiem, że klient wyśle segmenty TCP z portem źródłowym i docelowym, więc serwer użyje portu źródłowego tego segmentu jako portu docelowego, ale jaką funkcję wywołuje serwer, aby dowiedzieć się o tym porcie? Czy to accept()
jest
Odpowiedzi:
Jest to część nagłówka TCP (lub UDP itp.) W pakiecie. Tak więc serwer dowiaduje się, ponieważ mówi to klient. Jest to podobne do sposobu, w jaki wyszukuje adres IP klienta (który jest częścią nagłówka IP).
Np. Każdy pakiet TCP zawiera nagłówek IP (przynajmniej ze źródłowym adresem IP, docelowym adresem IP i protokołem [TCP]). Następnie jest nagłówek TCP (z portem źródłowym i docelowym oraz więcej).
Kiedy jądro odbiera pakiet SYN (początek połączenia TCP) ze zdalnym adresem IP 10.11.12.13 (w nagłówku IP) i zdalnym portem 12345 (w nagłówku TCP), wówczas zna zdalny adres IP i port . Odsyła SYN | ACK. Jeśli otrzyma potwierdzenie ACK,
listen
połączenie zwraca nowe gniazdo skonfigurowane dla tego połączenia.Gniazdo TCP jest jednoznacznie identyfikowane przez cztery wartości (zdalny adres IP, lokalny adres IP, zdalny port, lokalny port). Możesz mieć wiele połączeń / gniazd, o ile przynajmniej jedno z nich się różni.
Zazwyczaj port lokalny i lokalny adres IP będą takie same dla wszystkich połączeń z procesem serwera (np. Wszystkie połączenia z sshd będą na lokalnym IP: 22). Jeśli jedno zdalne urządzenie nawiąże wiele połączeń, każde użyje innego zdalnego portu. Więc wszystko oprócz zdalnego portu będzie takie samo, ale to dobrze - tylko jeden z czterech musi się różnić.
Możesz użyć np. Wirehsark, aby zobaczyć pakiet, który oznaczy dla ciebie wszystkie dane. Oto podświetlony port źródłowy (zauważ, że jest podświetlony w zdekodowanym pakiecie, a także zrzut heksowy u dołu):
źródło
write
(itp.) Trafią we właściwe miejsce.„Żądanie połączenia (
connect()
zwykle wywołanie systemowe programu klienckiego ) powoduje trójdrożny uścisk dłoni . Pierwszy pakiet trójdrożnego uścisku dłoni (od klienta do serwera) ma ustawioną flagę SYN i zawiera numer portu TCP programu klienta jądro przypisuje do niego.Możesz to zobaczyć w artykule na temat pakietów Nmap vs. Natural SYN . Dekodowanie pakietu SYN Nmap ma frazę „source.60058> dest.22”. „Prawidłowe dekodowanie pakietu SYN” zawiera zwrot „source.35970> dest.80”. Dwa pakiety SYN informują zdalne jądro, że pakiety pochodzą odpowiednio z portu TCP 60058 i portu 35970.
źródło
getpeername()
powinno pozwolić ci to zrobić na dowolnym otwartym gnieździe.accept()
Wywołanie systemowe że kod serwer ma użyć, aby uzyskać deskryptor gniazda do komunikowania się z powrotem do klienta ma parametr ( „sockaddr” W moich stronach man), który zawiera adres IP potencjalnego klienta i numer portu TCP.Gniazdo TCP jest gniazdem zorientowanym strumieniowo. Dwa deskryptory gniazd (należące do Ciebie i Twojego partnera) są niezawodnie połączone. Więc nie musisz się martwić o port klienta - po prostu napisz swój deskryptor gniazda!
Ponadto, możesz się zalogować do getsockname (2), jeśli naprawdę chcesz to wiedzieć (może do logowania).
źródło
Połączenie jest zdefiniowane przez krotkę (źródłowy adres IP, port źródłowy, docelowy adres IP, port docelowy). Odpowiedzi są odwrotne.
źródło