<sys/socket.h> pytanie o odbierane ramki

0

Witam przesyłam od dłuższego czasu ramki za pomocą gniazd przez tcp w trybie nieblokującym.
Wysyłam strukturę o wielkości 1500 bajtów a mój server odbiera to zawsze na dwa sposoby i tylko na dwa!
Albo pakiet 1452 B i wtedy 48
Albo całe 1500

Strasznie mnie to dziwi bo przecież maksymalne pole danych ramki to 1500 wiec niby powinno to być odbierane zawsze jako 1500.
Jednak używam trybu nieblokującego więc niby dane wcale nie musiały by przychodzić w całości i wtedy wersja pierwsza jest dla mnie zrozumiała, ale znowuż też nie do końca bo skoro zawsze by zwracał tyle ile ma aktualnie to dlaczego mój server zawsze powtarza ten sam wynik 1452 i 48?
Mógł by mi ktoś to wyjaśnić?

0

To jedne z najpopularniejszych wartości MTU.

0

W takim razie jeszcze jedno pytanie. Czy jeśli ustawię MTU na 1500 to nawet w trybie nieblokującym wysyłając ramkę 1500B będę również odbierał za pomocą recv albo 1500 albo -1?

0
szymko napisał(a)

Strasznie mnie to dziwi bo przecież maksymalne pole danych ramki to 1500

A skąd to? Ja wiem że ilość danych wysyłanych czy odbieranych nie powinna być większa niż 1024B. W moich programach dla pewności nie wysyłałem więcej niż 512B.

0

maksymalna wielkość pola danych ramki ethernet'owej

0

MTU określa maksymalną wielkość, nie minimalną. Pakiet może zostać podzielony przez urządzenia biorące udział w transmisji. Nigdy nie powinieneś polegać na tym, że dostaniesz dokładnie taką ilość danych, ile określa MTU. Możesz polegać na tym, że nie będzie więcej.

0

Ok ok, ja pisałem jak to wyglądało w mojej praktyce. BJ też napisał że wysyłając 1kB możemy być względnie pewni że tyle dostaniemy po drugiej stronie, wysyłając więcej to już tak niekoniecznie. Ja dzieląc sobie pakiety na 512 bajtów nigdy nie miałem problemów z komunikacją, implementowałem FTP i HTTP.

0

Ale o jakich problemach z komunikacją mówisz? Wątek dotyczy protokołu niższej warstwy niż TCP i UDP.

0
Kumashiro napisał(a)

Ale o jakich problemach z komunikacją mówisz? Wątek dotyczy protokołu niższej warstwy niż TCP i UDP.

EKhem..

szymko napisał(a)

Witam przesyłam od dłuższego czasu ramki za pomocą gniazd przez tcp w trybie nieblokującym.

Skoro ktoś coś wysyła gdzieś to znaczy że jakaś komunikacja następuje prawda? W ogólności chodzi mi o to że używająć send(), sendto(), recv(), recvfrom() nie powinno się formować pakietów danych dłuższych niż 1024B.

0
several napisał(a)

Skoro ktoś coś wysyła gdzieś to znaczy że jakaś komunikacja następuje prawda?

Ale wiesz co to jest stos TCP/IP?

several napisał(a)

W ogólności chodzi mi o to że używająć send(), sendto(), recv(), recvfrom() nie powinno się formować pakietów danych dłuższych niż 1024B.

Nie wiem skąd masz takie rewelacje. Fragmentacja nie następuje w warstwie TCP czy UDP. Jedyne, o co możesz się tam martwić, to wielkość bufora systemowego ale jest ona większa niż 1kB. Ograniczanie wielkości pakietu danych w warstwie TCP nie ma sensu, gdyż nie wiesz czy po drodze jakiś ruter nie poszatkuje Ci tego pakietu na fafdziesiąt mniejszych, a nie będziesz przecież implementował w swoim programie MTU Discovery.

0
Kumashiro napisał(a)

Ale wiesz co to jest stos TCP/IP?

Nie, widocznie źle zrozumiałem problem.

Kumashiro napisał(a)
several napisał(a)

W ogólności chodzi mi o to że używająć send(), sendto(), recv(), recvfrom() nie powinno się formować pakietów danych dłuższych niż 1024B.

Nie wiem skąd masz takie rewelacje.

Już pisałem, z własnej praktyki. Wysyłając więcej raz na jakiś czas pakiet bywał szatkowany jak to określiłeś. Wysyłając dużo więcej pakiety nie dochodziły w całości, w sensie nie dochodziły wszystkie. Formując mniejsze pakiety nigdy nie miałem problemów z otrzymaniem odpowiedniej ilości informacji.

0
several napisał(a)

Wysyłając więcej raz na jakiś czas pakiet bywał szatkowany jak to określiłeś. Wysyłając dużo więcej pakiety nie dochodziły w całości, w sensie nie dochodziły wszystkie. Formując mniejsze pakiety nigdy nie miałem problemów z otrzymaniem odpowiedniej ilości informacji.

W protokole TCP to nie powinno mieć miejsca. Tam poprawnośc każdego pakietu jest potwierdzana i w razie potrzeby transmisja jest ponawiana. Nie jest możliwe żebyś dostał tylko część danych, o ile poprawnie obsługujesz połączenia strumieniowe i z maszyną/systemem odbiorcy jest wszystko OK.
Protokół UDP jest bezpołączeniowy i o weryfikację, ponawianie itp. musisz się zatroszczyć sam. Nie ma gwarancji, że pakiet UDP dotrze do odbiorcy. Nie ma też gwarancji, że pakiety dotrą w kolejności wysyłania. Taki urok UDP.
Powstał protokół STCP, który łączy zalety UDP i TCP. Jest datagramowo-strumieniowy i do tego połączeniowy. Jak na razie się coś nie przyjmuje.

0
Kumashiro napisał(a)

W protokole TCP to nie powinno mieć miejsca. Tam poprawnośc każdego pakietu jest potwierdzana i w razie potrzeby transmisja jest ponawiana. Nie jest możliwe żebyś dostał tylko część danych, o ile poprawnie obsługujesz połączenia strumieniowe i z maszyną/systemem odbiorcy jest wszystko OK.

Wiem że TCP dba o poprawność transmisji, ale informacja nie dochodziła mi w całości i to jest fakt. Obsługując FTP nie udało mi się na raz wysłać pliku większego niż 7.5kB. "Na raz" czyli zapakować do send() bufor o takim rozmiarze. To nie jest tak że chciałem ładować pliki do pamięci, wiadomo że trzeba je pociąć żeby ramu nie zawalić, po prostu robiłem testy. Testy przeprowadzałem na plikach graficznych, wrzuciłem na przypał wszystkie bajty do tablicy i patrzyłem jak sobie z takim czymś send() i recv() poradzi, i rezultaty były jak napisałem wyżej. Tym nie mniej, te bajty które doszły były poprawne, włączając podgląd takiego pliku widać było obciętą grafikę. I stąd mój wniosek by nie traktować send() i recv() buforami większymi niż 1K.
Być może to było jakieś moje niedopatrzenie, jeżeli ta sytuacja Cię interesuje pokażę Ci kod mojego ftpa i wtedy będziesz mógł potwierdzić lub wykluczyć mój błąd. Kod wymaga refaktoryzacji bo pisałem go daaawno i zostało tam jeszcze kilka komentów które zdążyłem sobie wyjaśnić ale kilka razy wysyłałem i odbierałem za jego pomocą pliki o rozmiarze ~700MB więc działa poprawnie.

0
several napisał(a)

Wiem że TCP dba o poprawność transmisji, ale informacja nie dochodziła mi w całości i to jest fakt. Obsługując FTP nie udało mi się na raz wysłać pliku większego niż 7.5kB. "Na raz" czyli zapakować do send() bufor o takim rozmiarze.

TCP jest protokołem strumieniowym. Tam nie przesyła się danych "na raz". Nie ma gwarancji, że pojedyncze wywołanie send() spowoduje wysłanie wszystkich danych z przekazywanego mu bufora (to samo jest "w drugą stronę" z recv()). Dlatego powinieneś po każdym wywołaniu send() sprawdzać wartość zwracaną i w razie potrzeby (jeśli nie poleciało wszystko) powtórzyć wywołanie z danymi, które zostały. W niektórych bibliotekach są funkcje sendall() i recvall(), które robią tę pętelkę.
Jeśli chcesz mieć "jeden send() - jedno recv()", to powinieneś użyć protokołu datagramowego (UDP). Jeśli musisz użyć TCP, musisz poprawnie obsługiwać transmisję.

several napisał(a)

To nie jest tak że chciałem ładować pliki do pamięci, wiadomo że trzeba je pociąć żeby ramu nie zawalić, po prostu robiłem testy. Testy przeprowadzałem na plikach graficznych, wrzuciłem na przypał wszystkie bajty do tablicy i patrzyłem jak sobie z takim czymś send() i recv() poradzi, i rezultaty były jak napisałem wyżej. Tym nie mniej, te bajty które doszły były poprawne, włączając podgląd takiego pliku widać było obciętą grafikę. I stąd mój wniosek by nie traktować send() i recv() buforami większymi niż 1K.

To założenie jest dość niebezpieczne. Może się zdarzyć tak, że jedno wywołanie send() wyśle np. tylko 512B. Wtedy będziesz miał "dziurę" w danych.

several napisał(a)

Być może to było jakieś moje niedopatrzenie, jeżeli ta sytuacja Cię interesuje pokażę Ci kod mojego ftpa i wtedy będziesz mógł potwierdzić lub wykluczyć mój błąd. Kod wymaga refaktoryzacji bo pisałem go daaawno i zostało tam jeszcze kilka komentów które zdążyłem sobie wyjaśnić ale kilka razy wysyłałem i odbierałem za jego pomocą pliki o rozmiarze ~700MB więc działa poprawnie.

Nie ma takiej potrzeby :)
Polecam natomiast przeczytanie książki (np. "Programowanie Zastosowań Sieciowych w Systemie UNIX") żeby zobaczyć co i jak. Reguła braku gwarancji wysłania/odebrania danych jednym wywołaniem nie jest taka oczywista i wiele osób się na to nacina.

0

Dodatkowo może się wysłać i te 10KB jednym wywołaniem send, ale żeby odebrać może być potrzeba wywołania recv kilka razy.

0

w przypadku TCP pakiety albo dotarły w całości, albo zerwało połączenie. nie ma możliwości żeby jakiś pakiet zginął albo żeby dotarły w innej kolejności. każdy nienaprawialny problem z komunikacją skutkuje zerwaniem połączenia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1