Pomyśl napisać jak realizowane tak: #define write(...) send(##__VA_ARGS__, 0).
ostrożny1,
Odpowiedzi:
128
Różnica polega na tym, że recv()/ send()działa tylko na deskryptorach gniazd i pozwala określić określone opcje dla rzeczywistej operacji. Funkcje te są nieco bardziej wyspecjalizowane (na przykład możesz ustawić flagę, aby ignorować SIGPIPElub wysyłać wiadomości pozapasmowe ...).
Funkcje read()/ write()to uniwersalne funkcje deskryptorów plików działające na wszystkich deskryptorach.
Jest to niepoprawne, istnieje jeszcze jedna różnica w przypadku datagramów o długości 0 - Jeśli oczekuje na datagram o zerowej długości, read (2) i recv () z argumentem flag o wartości zero zapewniają inne zachowanie. W tej sytuacji read (2) nie działa (datagram pozostaje w toku), a recv () zużywa oczekujący datagram.
Abhinav Gauniyal
2
@AbhinavGauniyal Jak to zapewni inne zachowanie ? Jeśli jest datagram 0-bajtowy, oba, recvi readnie dostarczy danych do dzwoniącego, ale również nie spowoduje błędu. Dla osoby dzwoniącej zachowanie jest takie samo. Osoba dzwoniąca może nawet nic nie wiedzieć o datagramach (może nie wiedzieć, że jest to gniazdo, a nie plik, może nie wiedzieć, że jest to gniazdo datagramu, a nie gniazdo strumieniowe). To, że datagram pozostaje w toku, jest domyślną wiedzą o tym, jak stosy IP działają w jądrach i nie są widoczne dla osoby dzwoniącej. Z perspektywy dzwoniącego nadal będą zapewniać równe zachowanie.
Mecki
2
@Mekki, która nie jest niejawną wiedzą dla wszystkich, weź mnie na przykład :)
Abhinav Gauniyal
1
@Mecki co oznacza nieblokujący pomyślny odczyt 0 bajtów? Czy datagram nadal pozostaje w toku? Dokładnie to i tylko to mnie martwi: zachowanie, że datagram może pozostać w toku nawet po pomyślnym odczytaniu. Nie jestem pewien, czy sytuacja może się zdarzyć, a więc chciałbym o tym pamiętać.
sehe
2
@sehe Jeśli martwisz się, dlaczego nie używasz recv? Powodem, dla którego recvi sendgdzie wprowadzono go na początku, był fakt, że nie wszystkie koncepcje datagramów można zmapować na świat strumieni. readi writetraktuj wszystko jak strumień danych, czy to potok, plik, urządzenie (np. port szeregowy) czy gniazdo. Jednak gniazdo jest prawdziwym strumieniem tylko wtedy, gdy używa TCP. Jeśli używa UDP, to bardziej przypomina urządzenie blokowe. Ale jeśli obie strony użyją go jak strumienia, będzie działał jak strumień i nie będziesz mógł nawet wysłać pustego pakietu UDP za pomocą writepołączeń, więc taka sytuacja nie wystąpi.
read () jest równoważny recv () z parametrem flags wynoszącym 0. Inne wartości parametru flags zmieniają zachowanie recv (). Podobnie write () jest równoważne send () z flagami == 0.
To nie jest cała historia. recvmogą być wykorzystywane wyłącznie na gnieździe, i będzie produkować błąd, jeśli spróbujesz użyć go, powiedzmy STDIN_FILENO.
Joey Adams,
76
Wątek ten jest teraz pierwszym hitem w Google, Google uwielbia stackoverflow
Eloff
12
read()i write()są bardziej ogólne, działają z dowolnym deskryptorem pliku. Nie będą one jednak działać w systemie Windows.
Możesz przekazać dodatkowe opcje do send()i recv(), więc w niektórych przypadkach może być konieczne ich użycie.
Niedawno zauważyłem, że kiedy korzystałem write()z gniazda w systemie Windows, to prawie działa (FD przeszedł do innego write()niż ten, do którego przeszedł send(); Miałem _open_osfhandle()już FD do przejścia write()). Jednak nie zadziałało, gdy próbowałem wysłać dane binarne zawierające znak 10. wcześniej write()wstawiono znak 13. Zmiana tego send()parametru na parametr flagi 0 rozwiązała ten problem. read()Mógłbym mieć odwrotny problem, jeśli 13-10 są kolejne w danych binarnych, ale nie przetestowałem tego. Ale to wydaje się być kolejną możliwą różnicą między send()i write().
„Wydajność i szybkość”? Czy to nie są takie ... synonimy?
W każdym razie recv()połączenie przyjmuje flagi, które read()tego nie robią, co czyni go bardziej wydajnym lub przynajmniej wygodniejszym. To jedna różnica. Nie sądzę, że istnieje znacząca różnica w wydajności, ale nie przetestowałem tego.
Być może brak konieczności zajmowania się flagami może być postrzegany jako wygodniejszy.
semaj
2
W systemie Linux zauważam również, że:
Przerwanie wywołań systemowych i funkcji bibliotecznych przez procedury obsługi sygnałów
Jeśli wywoływana jest procedura obsługi sygnału, gdy wywołanie systemowe lub wywołanie funkcji biblioteki jest zablokowane, wówczas:
połączenie jest automatycznie wznawiane po powrocie procedury obsługi sygnału; lub
połączenie kończy się niepowodzeniem z błędem EINTR.
... Szczegóły różnią się w zależności od systemu UNIX; poniżej szczegóły dla Linuksa.
Jeśli zablokowane wywołanie jednego z poniższych interfejsów zostanie przerwane przez procedurę obsługi sygnału, wówczas połączenie zostanie automatycznie wznowione po powrocie procedury obsługi sygnału, jeśli użyto flagi SA_RESTART; w przeciwnym razie połączenie nie powiedzie się z błędem EINTR:
Wywołania read (2), readv (2), write (2), writev (2) i ioctl (2) na „wolnych” urządzeniach.
.....
Następujące interfejsy nigdy nie są restartowane po przerwie przez procedurę obsługi sygnału, niezależnie od zastosowania SA_RESTART; zawsze kończą się błędem EINTR, gdy są przerywane przez moduł obsługi sygnału:
Interfejsy gniazda „Input”, gdy limit czasu (SO_RCVTIMEO) został ustawiony w gnieździe za pomocą setsockopt (2): accept (2), recv (2),
recvfrom (2), recvmmsg (2) (również z wartością inną niż NULL argument limitu czasu) i recvmsg (2).
Interfejsy gniazda wyjściowego, gdy limit czasu (SO_RCVTIMEO) został ustawiony w gnieździe za pomocą setsockopt (2): connect (2), send (2), sendto (2) i sendmsg (2).
Sprawdź man 7 signalwięcej szczegółów.
Prostym zastosowaniem byłoby użycie sygnału, aby uniknąć recvfromblokowania na czas nieokreślony.
#define write(...) send(##__VA_ARGS__, 0)
.Odpowiedzi:
Różnica polega na tym, że
recv()
/send()
działa tylko na deskryptorach gniazd i pozwala określić określone opcje dla rzeczywistej operacji. Funkcje te są nieco bardziej wyspecjalizowane (na przykład możesz ustawić flagę, aby ignorowaćSIGPIPE
lub wysyłać wiadomości pozapasmowe ...).Funkcje
read()
/write()
to uniwersalne funkcje deskryptorów plików działające na wszystkich deskryptorach.źródło
recv
iread
nie dostarczy danych do dzwoniącego, ale również nie spowoduje błędu. Dla osoby dzwoniącej zachowanie jest takie samo. Osoba dzwoniąca może nawet nic nie wiedzieć o datagramach (może nie wiedzieć, że jest to gniazdo, a nie plik, może nie wiedzieć, że jest to gniazdo datagramu, a nie gniazdo strumieniowe). To, że datagram pozostaje w toku, jest domyślną wiedzą o tym, jak stosy IP działają w jądrach i nie są widoczne dla osoby dzwoniącej. Z perspektywy dzwoniącego nadal będą zapewniać równe zachowanie.recv
? Powodem, dla któregorecv
isend
gdzie wprowadzono go na początku, był fakt, że nie wszystkie koncepcje datagramów można zmapować na świat strumieni.read
iwrite
traktuj wszystko jak strumień danych, czy to potok, plik, urządzenie (np. port szeregowy) czy gniazdo. Jednak gniazdo jest prawdziwym strumieniem tylko wtedy, gdy używa TCP. Jeśli używa UDP, to bardziej przypomina urządzenie blokowe. Ale jeśli obie strony użyją go jak strumienia, będzie działał jak strumień i nie będziesz mógł nawet wysłać pustego pakietu UDP za pomocąwrite
połączeń, więc taka sytuacja nie wystąpi.Za pierwsze trafienie w Google
źródło
recv
mogą być wykorzystywane wyłącznie na gnieździe, i będzie produkować błąd, jeśli spróbujesz użyć go, powiedzmySTDIN_FILENO
.read()
iwrite()
są bardziej ogólne, działają z dowolnym deskryptorem pliku. Nie będą one jednak działać w systemie Windows.Możesz przekazać dodatkowe opcje do
send()
irecv()
, więc w niektórych przypadkach może być konieczne ich użycie.źródło
Niedawno zauważyłem, że kiedy korzystałem
write()
z gniazda w systemie Windows, to prawie działa (FD przeszedł do innegowrite()
niż ten, do którego przeszedłsend()
; Miałem_open_osfhandle()
już FD do przejściawrite()
). Jednak nie zadziałało, gdy próbowałem wysłać dane binarne zawierające znak 10. wcześniejwrite()
wstawiono znak 13. Zmiana tegosend()
parametru na parametr flagi 0 rozwiązała ten problem.read()
Mógłbym mieć odwrotny problem, jeśli 13-10 są kolejne w danych binarnych, ale nie przetestowałem tego. Ale to wydaje się być kolejną możliwą różnicą międzysend()
iwrite()
.źródło
Kolejną rzeczą na Linuksie jest:
send
nie pozwala na działanie na fd bez gniazda. Dlategowrite
konieczne jest na przykład pisanie na porcie USB .źródło
„Wydajność i szybkość”? Czy to nie są takie ... synonimy?
W każdym razie
recv()
połączenie przyjmuje flagi, któreread()
tego nie robią, co czyni go bardziej wydajnym lub przynajmniej wygodniejszym. To jedna różnica. Nie sądzę, że istnieje znacząca różnica w wydajności, ale nie przetestowałem tego.źródło
W systemie Linux zauważam również, że:
Sprawdź
man 7 signal
więcej szczegółów.Prostym zastosowaniem byłoby użycie sygnału, aby uniknąć
recvfrom
blokowania na czas nieokreślony.Przykład z APUE :
źródło