Czy gniazda domeny FIFO, potoku i Uniksa są takie same w jądrze Linuksa?

30

Słyszałem, że FIFO są nazwane fajkami. I mają dokładnie taką samą semantykę. Z drugiej strony, myślę, że gniazdo domeny Unix jest dość podobne do potoku (chociaż nigdy z niego nie korzystałem). Zastanawiam się więc, czy wszystkie odnoszą się do tej samej implementacji w jądrze Linuksa. Dowolny pomysł?

Justin
źródło
Z odpowiedzi poniżej zdałem sobie sprawę, że moje pytanie jest niejasne i trudno na nie odpowiedzieć. Prawdopodobnie nikt nie znał tak wielu szczegółów implementacyjnych w jądrze (nawet dla programistów jądra). Jeśli ktoś może potwierdzić, że gniazdo domeny, potok i FIFO w systemie Unix buforują dane wysyłane do pamięci współużytkowanej pod Linuksem, moje pytanie zostało rozwiązane. Cóż ... częściowo rozwiązany.
Justin
FIFO = nazwane rury! = Rury. FIFO mogą być dwukierunkowe jak para gniazd. Zwykłe rury są jednokierunkowe. Wszystkie mają interfejs pliku i semantykę plików. Dlaczego wdrożenie jest dla Ciebie ważne?
PSkocik
Wiem, że potoki są buforami okrągłymi i że w systemie STREAMS mogą one mieć wspólną implementację, jednak Linux domyślnie nie używa STREAMS. Uważam, że Linux na stałe koduje te kanały IPC. Jednak nie mam ochoty sprawdzać. : D Dlaczego ty nie? Kod jest publicznie dostępny.
PSkocik
Jeśli wszystkie mają tę samą implementację, ich wydajność powinna być blisko siebie. Dla mnie kod jądra jest zbyt trudny do zrozumienia.
Justin,

Odpowiedzi:

35

Gniazda domen UNIX i FIFO mogą współdzielić część ich implementacji, ale pod względem koncepcyjnym są bardzo różne. FIFO działa na bardzo niskim poziomie. Jeden proces zapisuje bajty do potoku, a inny odczytuje z niego. Gniazdo domeny UNIX zachowuje się tak samo jak gniazdo TCP / IP.

Gniazdo jest dwukierunkowe i może być używane przez wiele procesów jednocześnie. Proces może przyjmować wiele połączeń na tym samym gnieździe i jednocześnie obsługiwać kilku klientów. Jądro dostarcza nowy deskryptor pliku za każdym razem connect(2)lub accept(2)jest wywoływane w gnieździe. Pakiety zawsze przejdą do właściwego procesu.
W przypadku FIFO byłoby to niemożliwe. Do komunikacji dwukierunkowej potrzebujesz dwóch FIFO i pary FIFO dla każdego z Twoich klientów. Nie ma możliwości pisania lub czytania w sposób selektywny, ponieważ są one znacznie bardziej prymitywnym sposobem komunikacji.

Anonimowe potoki i FIFO są bardzo podobne. Różnica polega na tym, że anonimowe potoki nie istnieją jako pliki w systemie plików, więc żaden proces nie może open(2)tego zrobić. Są używane przez procesy, które współużytkują je w inny sposób. Jeśli proces otworzy FIFO, a następnie wykona na przykład a fork(2), jego dziecko odziedziczy deskryptory plików, a wśród nich potok.

Gniazda domen UNIX, anonimowe potoki i FIFO są podobne, ponieważ używają segmentów pamięci dzielonej. Szczegóły implementacji mogą się różnić w zależności od systemu, ale idea jest zawsze taka sama: dołącz tę samą część pamięci w dwóch odrębnych procesach mapowania pamięci, aby współdzieliły dane
( edytuj: to byłby oczywisty sposób na wdrożenie, ale to jest nie jak to jest faktycznie zrobione w Linuksie, który po prostu wykorzystuje pamięć jądra dla buforów, patrz odpowiedź @ tjb63 poniżej).
Jądro następnie obsługuje wywołania systemowe i wyodrębnia mechanizm.

lgeorget
źródło
„Gniazda domen UNIX i FIFO mogą współdzielić część ich implementacji”… chodzi o „jakąś część”… Właśnie zdałem sobie sprawę, że moje pytanie jest niejasne i trudno na nie odpowiedzieć. Prawdopodobnie nikt nie wie tak wielu szczegółów na temat tego, jakie części dzielą w jądrze (nawet dla programistów jądra). Niemniej jednak ... czy ktokolwiek może potwierdzić, że gniazdo domeny, potok i FIFO w systemie Unix buforują dane wysyłane do pamięci współdzielonej pod Linuksem? Jeśli to zostanie potwierdzone, moje pytanie zostało rozwiązane. Cóż ... częściowo rozwiązany.
Justin
Cóż, tak, jądro zarządza buforem. Na przykład za pomocą FIFO możesz zabić pisarza, a czytelnik może nadal wysłać to, co zostało wysłane do fajki przed śmiercią pisarza. W przypadku gniazd jest to nieco bardziej skomplikowane, ponieważ działają z podłączonym protokołem. Ale jeśli wyślesz, powiedzmy, int do gniazda, a następnie wyjdziesz poza zakres, aby int został wyczyszczony ze stosu nadawców, odbiorca nadal może go odczytać. Więc gdzieś jest bufor.
lgeorget
Ponownie czytam komentarz, nie jestem pewien, czy wszystko jest jasne ... Daj mi znać, jeśli nadal jest coś niejasnego.
lgeorget
Twój komentarz jest dla mnie jasny.
Justin
7

Całkiem niezła dyskusja na ten temat: http://www.slideshare.net/divyekapoor/linux-kernel-implementation-of-pipes-and-fifos

O ile widzę, zarówno ze slajdów prezentacji, jak i źródła @ http://lxr.free-electrons.com/source/fs/pipe.c - fifo są zaimplementowane jako owijanie wokół rur, a same rury są zaimplementowane przez wirtualny system plików pipefs.

@lgeorget - Wydaje się, że potoki używają pamięci jądra do buforowania między czytnikami a programami zapisującymi - nie używają „pamięci współużytkowanej” jako takiej i kopiują pamięć między przestrzenią adresową użytkownika a jądrem (np. pipe_readwywołania pipe_iov_copy_to_user, które wywołują __copy_to_user_inatomic(lub copy_to_user) , __copy_to_user_inatomicwywołuje copy_user_generic, który jest jednym z kilku wdrożeń ASM.

tjb63
źródło
4

„FIFO” i „ nazwany potok” to to samo - choć jest to całkiem odmienne od tego, jak powłoka obsługuje „potok” (|) między dwoma poleceniami w wierszu poleceń.

Nazwany potok (FIFO) to pojedynczy „plik” współdzielony przez dwa programy, z których jeden zapisuje do niego, a drugi odczytuje z niego… Z drugiej strony gniazdo to „połączenie” między dwoma „plikami” - co może korzystać z sieci i znajdować się na osobnych komputerach - gdzie jeden program odczytuje / zapisuje do jednego „pliku”, a inny program odczytuje / zapisuje do drugiego ... Nie sądzę, że są do siebie podobne… Z drugiej strony oba gniazda i nazwane potoki - a także pliki, urządzenia, dowiązania symboliczne - wszystkie używają i-węzłów i wszystkie implementują niektóre typowe funkcje (takie jak odczyt i zapis).

Baard Kopperud
źródło
1
Tak, gniazdo domeny Unix jest rodzajem gniazda, więc jego interfejs API jest podobny do innych interfejsów API gniazd, takich jak TCP lub UDP itp. Jednak gniazdo domeny Unix może być używane tylko jako „lokalny” IPC. A sposób przesyłania danych odbywa się w pierwszej kolejności, podobnie jak FIFO i rura. Sądzę więc, że możliwe jest, że interfejs API gniazda domeny Unix jest po prostu kolejną enkapsulacją identycznej implementacji, więc używamy go tak, jakby był gniazdem. Myślę, że to możliwe, że wszystkie mają tę samą wewnętrzną część jądra ... Chcę potwierdzić, czy to prawda, czy nie.
Justin
1

Nie wydaje mi się, Justin. Jeśli się nie mylę i całkiem możliwe, myślę, że FIFO używają pliku na dysku, a gniazda Domeny Unix używają pamięci jądra.

Ponadto, jako dodatek do powyższego plakatu, który wspomniał, że gniazda domenowe Unix są dwukierunkowe, tak jest tylko w przypadku korzystania z gniazda SOCK_STREAM. SOCK_DGRAM Gniazda domeny Unix są w rzeczywistości jednokierunkowe i mogą wysyłać () tylko z kodu, który wywołał connect (), do kodu, który wywołał bind ().

Oczywiście kod, który wywołał connect (), musi również wywołać bind (), aby utworzyć własny punkt końcowy, ale nie ma to nic wspólnego z twoim pytaniem.

Anonimowy
źródło
3
Witamy na StackExchange i dziękuję za wysłanie wiadomości. Kilka uwag ... 1) Jeśli „prawdopodobnie” się pomylisz, powinieneś dokładnie sprawdzić przed odpowiedzią; ta strona nie jest forum ani czatem. 2) Dziękujemy za precyzję w przypadku gniazd zorientowanych na datagram. 3) Nie ma potrzeby publikowania czegoś, co nie ma nic wspólnego z pytaniem. :)
lgeorget
1

Moje 2 centy ... Gniazdo FIFO i UNIX są dwukierunkowe (podobne), ale gniazdo ma topologię gwiazdy, podczas gdy FIFO jest tylko kolejką (i dlatego nie może się zastąpić), tak, ich implementacja może współdzielić kod wewnętrznie.

**

char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666);
fd = open(myfifo, O_RDWR);   //so that you can read/write to it
 ...
write(fd, buff1, sizeof(buff1));  
getchar();//wait till some one reds this and writes something else
int sz=read(fd, buff1, sizeof(buff1));  //read that something**
Asif Bahrainwala
źródło
FIFO jest dwukierunkowy?
jhfrontz