Tłumaczenie: Grzegorz Szczepanik
Dokument ten opisuje w prostym języku podstawy funkcjonowania komputerów PC, podobnych do Unixa systemów operacyjnych i Internetu.
Ten dokument ma służyć jako pomoc dla tych użytkowników Linuksa i Internetu, którzy uczą się poprzez praktykę. Chociaż jest to świetna droga nabywania umiejętności, czasami pozostawia osobliwe luki w wiedzy o podstawach - luki które mogą uczynić trudnym kreatywne myślenie lub efektywne rozwiązywanie problemów, ze względu na brak jasnego modelu myślowego tego co się naprawdę dzieje.
Spróbuję opisać w jasnym, prostym języku jak to wszystko działa. Prezentacja będzie ustawiona pod kątem ludzi używających Unixa bądź Linuksa na sprzęcie standardu PC. Niemniej jednak, zwykle będę się tu odnosił do Unixa, ponieważ większość z tego co będę opisywał jest stała niezależnie od platform i wariantów Unixa.
Zamierzam założyć, że używasz Intel PC. Detale różnią się odrobinę jeśli eksploatujesz Alphę, lub Power PC albo inny komputer pod Unixa, ale podstawowe pojęcia są takie same.
Nie chcę powtarzać rzeczy, tak więc musisz skupić uwagę, ale oznacza to także, że uczyszsię z każdym słowem które czytasz. Dobrym pomysłem jest pobieżne przeczytanie za pierwszym razem; powinieneś wracać i czytać ponownie kilka razy po tym jak strawisz to czego się nauczyłeś.
To jest ewoluujący dokument. Zamierzam wprowadzać dodatkowe sekcje w odpowiedzi na odzew użytkowników, tak więc powinieneś okresowo powracać tu i przeglądać go.
Jeśli czytasz to zamierzając nauczyć się hackerstwa, powinieneś także przeczytać Jak zostać Hackerem FAQ (How To Become A Hacker). Są tam linki do kilku innych użytecznych zasobów.
Nowe wersje The Unix and Internet Fundamentals HOWTO będą okresowo wysyłane do grup comp.os.linux.help i news.answers Będzie je także można ściągnąć z różnych stron WWW o Linuksie i FTP włączając stronę domową LDP. Możesz przeczytać ostatnią wersję poprzez WWW poprzez URL http://sunsite. unc.edu/LDP/HOWTO/Fundamentals-HOWTO.html. Polskie tłumaczenie będzie oczywiście umieszczane na tej stronie.
Jeśli masz pytania lub komentarze na temat tego dokumentu,
proszę napisz do Erica S. Raymonda esr@thyrsus.com
Z zadowoleniem powitam wszystkie sugestie i uwagi krytyczne. Szczególnie chętnie
powitam linki do bardziej szczegółowych wyjaśnień indywidualnych pojęć. Jeśli
znajdziesz błąd w tym dokumencie, proszę poinformuj mnie o tym abym mógł
poprawić to w następnej wersji. Dzięki.
Jeśli masz uwagi co do tego (bardzo niedoskonałego) tłumaczenia, to proszę
poinformuj mnie o błędach (gszczepa@theta.uoks.uj.edu.pl),
abym mógł je poprawić. Dzięki.
Twój komputer ma wewnątrz procesor, który faktycznie wykonuje obliczenia. Ma wewnętrzną pamięć (którą użytkownicy DOS/Windows nazywają "RAM", a użytkownicy Unixa często nazywają "rdzeniem" (core)). Procesor i pamięć znajdują się na płycie głównej która jest sercem Twojego komputera. Twój komputer posiada także ekran i klawiaturę. Ma dyski twarde i stacje dyskietek. Ekran i dyski mają kontrolery na kartach włożonych w płytę główną, które pomagają komputerowi sterować tymi urządzeniami peryferyjnymi. (Klawiatura jest zbyt prosta aby potrzebować oddzielnej karty; kontroler jest wbudowany w konstrukcję klawiatury.)
W szczegółowe wyjaśnienia jak te urządzenia pracują zagłębimy się później. Na teraz, tutaj jest kilka podstawowych rzeczy, do trzymania w umyśle, o tym jak wszystko pracuje razem:
Wszystkie części komputera umieszczone na płycie głównej komunikują się poprzez szynę. Fizycznie, szyna jest tym w co wtykasz swoje karty (kartę graficzną, kontroler dysku, kartę dźwiękową jeśli ją masz). Szyna jest informacyjną autostradą pomiędzy procesorem, ekranem, dyskiem i wszystkim innym. Procesor właściwie nie może zobaczyć żadnych innych części bezpośrednio; musi komunikować się z nimi poprzez szynę. Tylko inny podsystem ma rzeczywiście szybki, natychmiastowy dostęp do pamięci (core). Żeby uruchomić programy, muszą one być w pamięci. Kiedy twój komputer czyta program lub dane z dysku, obecnie odbywa się to tak, że procesor używa szyny do wysyłania żądania odczytu do kontrolera dysku. Jakiś czas potem kontroler używa szyny do sygnalizowania komputerowi, że odczytuje dane i umieszcza je w pewnym położeniu w pamięci. Procesor może używać szyny do zaglądania do pamięci. Twoja klawiatura i ekran także komunikują się z procesorem poprzez szynę, ale w prostszy sposób. Zajmiemy się tym później. Teraz wiesz wystarczająco dużo, aby zrozumieć co się dzieje kiedy włączasz swój komputer.
Komputer bez działających programów jest tylko bezwładnym kawałkiem elektroniki. Pierwszą rzeczą którą komputer musi zrobić kiedy jest włączony, jest uruchomienie specjalnego programu nazywanego systemem operacyjnym. Funkcją systemu operacyjnego jest wspomaganie innych programów komputerowych poprzez zajmowanie się szczegółowym kontrolowaniem sprzętu.
Proces wgrywania systemu operacyjnego jest nazywany ładowaniem bądź startowaniem. Komputer potrafi wystartować ponieważ instrukcje dotyczące ładowania są wbudowane w jeden z jego układów scalonych, układ BIOS (Basic Input/Output System)
Układ BIOS-u nakazuje komputerowi poszukać w stałym miejscu na dysku o najniższym numerze (dysk startowy) specjalnego programu nazywanego programem ładującym (pod Linuksem program ładujący nazywany jest LILO). Program ładujący jest wprowadzany do pamięci i uruchamiany. Funkcją programu ładującego jest uruchomienie prawdziwego systemu operacyjnego.
Program ładujący robi to poprzez wyszukanie jądra, załadowanie go do pamięci (core) i uruchomienie. Kiedy ładujesz Linuksa i widzisz "LILO" na ekranie za którym następuje grupa kropek, to wtedy następuje ładowanie jądra. (Każda kropka oznacza, że następuje ładowanie innego bloku dyskowego kodu jądra.)
(Możesz się zastanawiać dlaczego BIOS nie ładuje jądra bezpośrednio - dlaczego dwukrokowy proces z program ładującym? No cóż, BIOS nie jest zbyt sprytny. Faktycznie jest bardzo głupi, Linux nie używa go wcale po załadowaniu. Został on (BIOS) oryginalnie napisany dla prymitywnych 8-bitowych PC z maleńkimi dyskami i dosłownie nie ma wystarczającego dostępu do dysku aby załadować jądro bezpośrednio. Pośrednictwo programu ładującego pozwala także na załadowanie jednego z kilku systemów operacyjnych na różnych miejscach dysku, gdyby, co jest mało prawdopodobne, Unix nie był wystarczająco dobry dla ciebie.
Zaraz po tym jak jądro się uruchomi rozgląda się dookoła, odnajduje resztę sprzętu i przygotowuje się do uruchamiania programów. Robi nie przez szturchanie (poking) zwykłej pamięci ale raczej portów wejścia/wyjścia (I/O) - specjalnych adresów szyny na których prawdopodobnie kontrolery urządzeń czekają na komendy. Jądro nie robi tego losowo, posiada sporo wbudowanej wiedzy na temat co można znaleźć w określonych miejscach i jak kontrolery będą odpowiadać jeśli są obecne. Ten proces nazywany jest wyszukiwaniem (autoprobing).
Większość z komunikatów które są widoczne podczas ładowania pokazuje jak jądro wyszukuje sprzęt poprzez porty I/O, rozpracowuje co jest dostępne i adaptuje się do komputera. Jądro Linuksa jest nadzwyczajnie sprawne w tym, lepsze niż większość innych Unixów i znacznie lepsze niż DOS czy Windows. W rzeczywistości, wielu Linuksowych weteranów jest przekonanych, że sprawność wyszukiwania przez Linuksa podczas ładowania było główną przyczyną erupcji pakietów wolnego Unixa przyciągając krytyczną liczbę użytkowników.
Ale pełne załadowanie się i uruchomienie jądra nie jest końcem procesu ładowania; to tylko pierwszy etap (czasami nazywany poziomem pierwszym uruchamiania (run level 1)).
Następnym krokiem jądra jest upewnienie się, że dyski są w porządku. Dyskowy system plików jest delikatną rzeczą; gdyby został uszkodzony z powodu błędu sprzętowego lub nagłej przerwy w dopływie energii elektrycznej, można podjąć kroki naprawcze zanim Unix zostanie w pełni załadowany. Zajmiemy się tym później, kiedy będziemy mówić o tym "jak system plików może zostać uszkodzony".
Kolejnym krokiem jądra jest uruchomienie kilku demonów. Demon jest programem, należą tu np. demon drukarki, demon pocztowy lub serwer WWW które czają się w tle czekając na rzeczy do zrobienia. Te specjalne programy często muszą koordynować kilka żądań, które mogą spowodować konflikt. Są one demonami ponieważ często jest łatwiej napisać jeden program który jest uruchamiany stale i wie o wszystkich żądaniach niż próbować się upewnić, że stado kopii (jeden proces na każde żądanie i wszystkie uruchomione w tym samym czasie) nie następują na siebie nawzajem. Zbiór demonów które uruchamia twój system może być różny, ale prawie zawsze będzie zawierał bufor drukarki (print spooler - demon nadzorujący Twoją drukarkę).
Zaraz po tym jak wszystkie demony wystartują, mamy poziom drugi uruchamiania (run level 2). Następnym krokiem jest przygotowanie na użytkowników. Jądro uruchamia kopię programu nazywanego getty do obserwowania konsoli (może być więcej kopii do obserwowania portów szeregowych). To ten program wypisuje zachętę startową na konsoli. Mamy teraz trzeci poziom uruchamiania (run level 3) i system czeka na zalogowanie się będąc gotowym do uruchamiania programów.
Kiedy się logujesz (podajesz nazwę i hasło) to identyfikujesz się dla getty i komputera. Potem uruchamia się program nazywany (chyba naturalnie) login który zajmuje się czymś w rodzaju prowadzenia gospodarstwa domowego, a następnie uruchamia się interpreter komend, powłoka (shell). (Tak, getty i login mogą być tym samym programem. Są one rozdzielone dla historycznych powodów w które nie warto tutaj się zagłębiać.)
W następnym rozdziale zajmiemy się tym co dzieje się podczas uruchamiania programów z powłoki.
Normalnie powłoka wyświetla znak "$", który widać po zalogowaniu (chyba że został zmieniony na coś innego). Nie będziemy zajmować się tutaj składnią powłoki i łatwymi rzeczami, które możesz zobaczyć na ekranie; zamiast tego zaglądniemy za scenę; popatrzymy na to co się dzieje z punktu widzenia komputera.
Po załadowaniu, a przed uruchomieniem programów możesz myśleć, że twój komputer zawiera zwierzyniec procesów które wszystkie czekają na coś do zrobienia. Wszystkie one czekają na zdarzenia. Zdarzeniem może być naciśnięcia klawisza lub poruszenie myszki. Lub, jeśli komputer podłączony jest do sieci zdarzeniem może być pakiet danych nadchodzących z sieci.
Jądro jest jednym z tych procesów. Jest specjalnym procesem ponieważ może kontrolować kiedy inne procesy mogą zostać uruchomione i jest normalnie jedynym procesem z bezpośrednim dostępem do sprzętu komputera. Faktycznie procesy użytkownika muszą wystosować żądanie do jądra kiedy chcą dostać dostęp do danych wejściowych z klawiatury, pisać na ekran czytać i zapisywać dysk, w ogóle robić coś poza przerzucaniem bitów w pamięci. Te żądania znane są jako funkcje systemowe.
Normalnie wszystkie operacje I/O przechodzą przez jądro tak więc może ono planować operacje i uniemożliwić procesom następowanie na siebie. Kilka specjalnych procesów użytkownika może omijać jądro, zwykle poprzez otrzymywanie bezpośredniego dostępu do portów I/O. X serwery (programy które kierują żądaniami dostępu innych programów do grafiki ekranowej w większości urządzeń Unixowych) są ich najpowszechniejszym przykładem.
Powłoka jest tylko procesem użytkownika i to nie jakimś szczególnym. Czekając na uderzenia klawiszy słucha (poprzez jądro) portu I/O klawiatury. Kiedy jądro widzi je (uderzenie w klawisz) powtarza je na ekranie i przekazuje do powłoki. Kiedy jądro widzi "Enter" przekazuje do linię tekstu do powłoki. Powłoka próbuje zinterpretować te uderzenia klawiszy jako komendy.
Powiedzmy, że napisałeś ls i nacisnąłeś "Enter" aby wywołać Unixowe polecenie listujące katalog. Powłoka stosuje wbudowane reguły aby wykombinować, że chcesz wykonać polecenie zawarte w pliku "/bin/ls". Powoduje funkcję systemową prosząc jądro o wystartowanie "/bin/ls" jako nowego procesu potomnego i danie mu dostępu do ekranu i klawiatury poprzez jądro. Potem powłoka idzie spać czekając aż ls skończy.
Kiedy /bin/ls zakończy, mówi jądru że skończyło poprzez wykonanie funkcji systemowej wyjścia (exit system call). Jądro budzi powłokę i mówi jej, że może kontynuować pracę. Powłoka wyświetla kolejny znak zachęty i czeka na kolejną linię danych wejściowych.
Jednakże, podczas gdy twoje ls jest wykonywane, mogą iść inne rzeczy (musimy przypuścić że listujesz bardzo długi katalog). Możesz przełączyć się na inną wirtualną konsolę, zalogować się tam i zacząć grać w Quake'a, na przykład. Lub przypuśćmy, że jesteś podłączony do Internetu. Twój komputer może wysyłać lub otrzymywać pocztę podczas gdy "/bin/ls" jest uruchomione.
Klawiatura jest bardzo prostym urządzeniem wejściowym; prostym ponieważ bardzo wolno (jak na standardy komputerowe) generuje małe ilości danych. Kiedy naciskach lub puszczasz klawisz to zdarzenie jest sygnalizowane przez kabel klawiatury wzbudzając przerwanie sprzętowe.
Obserwowanie takich przerwań jest zadaniem systemu operacyjnego. Dla każdego możliwego rodzaju przerwania musi istnieć program obsługujący (handler), część systemu operacyjnego która przechowuje w bezpiecznym miejscu wszystkie skojarzone dane (jak wartość naciśniętego/zwolnionego klawisza aż będę mogły być przetworzone.
Tym co program obsługujący (handler) właściwie robi dla klawiatury jest przesyłanie wartości klawisza do obszaru systemowego w pobliżu rdzenia jądra (bottom core). Tam są dostępne do przeglądu gdy system operacyjny przekazuje kontrolę do programu który w danym momencie może czytać z klawiatury.
Bardziej złożone urządzenia wejściowe jak dyski lub karty sieciowe pracują w podobny sposób. Powyżej odnosiliśmy się do kontrolera dysku używającego szyny do sygnalizowania, że żądanie dyskowe zastało zaspokojone. Co właściwie dzieje się, że dysk kończy przerwanie. Program obsługujący przerwanie dyskowe (handler) kopiuje wyszukane dane do pamięci, dla późniejszego użytku programu, który zgłosił żądanie.
Każdemu rodzajowi przerwania przypisano poziom priorytetu. Przerwania niższego priorytetu (jak zdarzenia klawiatury) muszą czekać na przerwania wyższego priorytetu (jak takty zegara lub zdarzenia dyskowe). Unix jest zaprojektowany aby dawać wysoki priorytet rodzajom wydarzeń które muszą być przetwarzane szybko żeby utrzymać płynność reakcji komputera.
Wśród komunikatów startowych twojego systemu operacyjnego możesz zobaczyć odniesienia do numerów IRQ. Możesz być świadomy, że jednym z kilku sposobów błędnego skonfigurowania sprzętu jest usiłowanie przez dwa urządzenia używanie tego samego IRQ, nie wiedząc jednak dokładnie dlaczego.
Tutaj jest odpowiedź. IRQ jest skrótem od Interrupt Request (żądanie przerwania). System operacyjny musi wiedzieć którego numeru przerwania będzie używać każde urządzenie sprzętowe, aby skojarzyć z każdym właściwe programy obsługujące. Jeśli dwa różne urządzenia próbują używać tego samego IRQ, przerwania mogą czasami przydzielone do złego programu obsługującego. Zwykle prowadzi to co najmniej do zablokowania urządzenia i może czasami na tyle zmylić system operacyjny, aby doprowadzić do padu, załamania systemu.
Zasadniczo nie robi. Komputery mogą wykonywać tylko jedno zadanie (lub proces) w tym samym czasie. Ale komputer może zmieniać zadania bardzo szybko i nabierać powolnego człowieka na to, że robi kilka rzeczy na raz. Jest to nazywane podziałem czasu.
Jednym z zadań jądra jest zarządzanie podziałem czasu. Ma ono część nazywaną rozkładem (scheduler) która zawiera informacje o wszystkich innych (poza jądrem) procesach w twoim ZOO. Raz na 1/60 każdej sekundy zegar idący w jądrze generuje przerwanie zegarowe. Rozkład zatrzymuje jakikolwiek uruchomiony obecnie proces, zawiesza go w miejscu i przekazuje kontrolę do innego procesu.
1/60 sekundy może nie brzmi jak dużo czasu. Ale na dzisiejszych procesorach jest wystarczająca do uruchomienia dziesiątków tysięcy instrukcji kodu maszynowego, które mogą zrobić duży kawał roboty. Tak więc, nawet jeśli masz wiele procesów, każdy jeden może zrealizować całkiem dużo w każdym swoim odcinku czasu.
W praktyce program może nie dostać całego swoje odcinku czasu. Jeśli nadejdzie przerwanie z urządzenia I/O jądro faktycznie przerywa bieżące zadanie, uruchamia program obsługujący przerwania (handler) i potem powraca do bieżącego zadania. Nawałnica przerwań o wysokim priorytecie może wykluczyć normalne przetwarzanie; to złe zachowanie jest nazywane jest laniem (thrashing) i jest szczęśliwie bardzo trudne do wywołania pod nowoczesnymi Unixami.
Faktycznie szybkość programu jest tylko bardzo rzadko limitowana przez ilość czasu procesora jaki może dostać (istnieje kilka wyjątków od tej reguły, jak generowanie dźwięku lub grafiki trójwymiarowej). Znacznie częściej opóźnienia są spowodowane przez oczekiwanie przez program na dane z twardego dysku lub połączenia sieciowego.
System operacyjny który potrafi rutynowo wspierać wiele równoczesnych procesów nazywany jest wielozadaniowym (multitasking)Unixowa rodzina systemów operacyjnych została od podstaw zaprojektowana dla wielozadaniowości i jest w tym bardzo dobra - znacznie efektywniejsza niż Windows lub Mac OS, które połknęły wielozadaniowość machinalnie i obsługują ją raczej słabo. Wydajna, niezawodna wielozadaniowość jest ważną częścią tego co czyni Linuksa lepszym dla sieci, komunikacji i usług WWW.
Rozkład jądra pilnuje dzielenia procesów w czasie. Twój system operacyjny musi także dzielić je w przestrzeni, tak aby procesy nie następowały na pamięć roboczą innych. To co system operacyjny robi aby rozwiązać ten problem nazywamy zarządzaniem pamięcią.
Każdy proces w twoim ZOO potrzebuje swojego własnego obszaru w pamięci RAM, miejsca do uruchomienia z niego swojego kodu i trzymania zmiennych i wyników. Możesz myśleć o tym zbiorze jako składającym się z segmentu kodu, tylko do odczytu (zawierającej instrukcje procesu) i zapisywalnego segmentu danych (zawierającej całą pamięć zmiennych procesu). Segment danych jest naprawdę unikalny dla każdego procesu, ale jeśli dwa procesy uruchamiają ten sam kod Unix automatycznie ustawia dla nich uczestniczenie w pojedynczym segmencie kodu aby podnieść wydajność.
Wydajność jest ważna, ponieważ pamięć RAM jest droga. Czasami nie masz jej wystarczająco dużo do pomieszczenia w całości wszystkich programów uruchomionych na komputerze, zwłaszcza jeśli używasz dużych programów jak X serwer. Aby to obejść Unix używa strategii nazywanej pamięcią wirtualną. Nie próbuje trzymać całego kodu i danych w pamięci RAM. Zamiast tego utrzymuje jedynie stosunkowo mały zbiór roboczy; reszta stanu procesów pozostaje w specjalnym obszarze wymiany (swap area) na dysku twardym.
Kiedy proces jest uruchomiony Unix próbuje przewidzieć jak zbiór roboczy będzie się zmieniał i utrzymuje w pamięci tylko potrzebne fragmenty. Robienie tego skutecznie jest skomplikowane, tak więc nie będę próbował wyjaśniać tutaj wszystkiego - ale zależy to od faktu, że kod i dane powiązane są w grupy, z każdą nową korzystającą z zamknięcia gdzieś starej. Tak więc jeśli Unix utrzymuje w pamięci kod i dane które są używane najczęściej, bądź były używane ostatnio skutkuje to zwykle odniesieniem sukcesu w oszczędzaniu czasu.
Zwróć uwagę, że w przeszłości "czasami" użyte dwa akapity wcześniej oznaczało "prawie zawsze" - rozmiar pamięci RAM był zwykle stosunkowo mały w porównaniu do rozmiaru uruchomionych programów, tak więc wymiana (swapping) była częsta. Pamięć jest daleko mniej kosztowna w dzisiejszych dniach i nawet komputery z dolnej półki mają jej zupełnie dużo. W nowoczesnej maszynie dla jednego użytkownika z 64 i więcej megabajtów RAM, jest możliwe uruchomienie X-ów i typowej mieszanki zadań bez żadnej wymiany.
Nawet w tej szczęśliwej sytuacji, część systemu operacyjnego zwana zarządcą pamięci (memory manager) ciągle ma ważne zadania do wykonania. Musi się upewniać, że programy mogą zmieniać tylko ich własne segmenty danych - służy to uniemożliwieniu błędnemu lub złośliwemu kodowi w jednym z programów niszczenia danych w innych. W tym celu utrzymuje tablicę segmentów kodu i danych. Tablica jest uaktualniana kiedy tylko proces żąda więcej pamięci, bądź zwalnia pamięć (to drugie zwykle podczas opuszczania programu).
Ta tablica jest zwykle używana do przekazywania poleceń do wyspecjalizowane elementu sprzętowego komputera nazywanego MMU lub jednostka zarządzania pamięcią (Memory Management Unit). Nowoczesne procesory mają wbudowaną MMU. MMU posiada specjalną zdolność do umieszczania płotków wokół obszarów pamięci, tak więc odniesienia w strefie zakazanej muszą być odrzucone i powodują podnoszenie specjalnych przerwań.
Jeśli zobaczysz kiedyś komunikat Unixa który mówi: Segmentation fault (Błąd segmentacji); Core dumped (rdzeń zrzucony) lub coś podobnego, to właśnie to dokładnie się dzieje; dokonana przez uruchomiony program próba dostępu do pamięci poza swoim segmentem podniosła śmiertelne przerwanie (fatal interrupt). Wskazuje to na błąd w kodzie programu; zrzucenie rdzenia pozostawia programiście informację diagnostyczną mającą mu pomóc w wytropieniu błędu.
Jeśli spoglądamy na dysk pod Unixem, widzimy drzewo nazw katalogów i plików. Normalnie nie potrzebujesz wpatrywać się głębiej, ale wiedza o tym co się dzieje pod spodem może być użyteczna w wypadku padnięcia dysku i potrzeby podjęcia próby ocalenia plików. Niestety, nie jest dobrym pomysłem próba wyjaśnienia organizacji dysku poczynając od poziomu plików w dół, tak więc spróbuję wyjaśnić to od zaczynając od poziomu sprzętu i posuwając się w górę.
Powierzchnia dysku , gdzie przechowywane są dane, jest podzielona podobnie do tablicy do rzutków - na okrągłe ścieżki podzielone na sektory. Ponieważ ścieżki położone bliżej zewnętrznej krawędzi mają większą powierzchnię niż te położone bliżej środka dysku to ścieżki zewnętrzne mają więcej sektorów niż ścieżki wewnętrzne. Każdy sektor (lub blok dyskowy) ma ten sam rozmiar, który pod nowoczesnymi Unixami generalnie wynosi 1 kilobajt (1024 8-bitowe słowa (bajty)). Każdy blok dyskowy ma unikalny adres lub numer bloku dyskowego.
Unix dzieli dysk na partycje dyskowe. Każda partycja jest ciągłym obszarem bloków które są używane oddzielnie od wszystkich innych partycji zarówno jako system plików lub jako przestrzeń wymiany. Partycja o najniższym numerze jest często traktowana specjalnie jako partycja startowa gdzie można umieścić jądro, aby zostało załadowane.
Każda partycja jest albo przestrzenią wymiany (używaną do zaimplementowania "pamięci wirtualnej") lub systemem plików używaną do pomieszczenia plików. Partycje wymiany traktowane są właśnie jak liniowa sekwencja bloków. Z drugiej strony system plików potrzebuje sposobu na przypisanie nazw plików sekwencjom bloków dyskowych. Ponieważ pliki rosną, kurczą się i zmieniają przez cały czas bloki danych pliku nie będą liniową sekwencją ale mogą być rozproszone po całej swojej partycji (gdzie tylko system operacyjny może znaleźć wolny blok w momencie kiedy go potrzebuje).
Wewnątrz każdego systemu plików kojarzenie nazw plików i bloków jest wspierane przez strukturę nazywaną inteligentnym węzłem (I-node). Jest to krąg rzeczy blisko "dna" (bloków o niskich numerach) każdego systemu plików (bloki o bardzo niskich numerach używane są do prowadzenie gospodarstwa i określania przeznaczenia, nie będziemy tego tutaj omawiać). Każdy węzeł opisuje jeden plik. Bloki plików z danymi znajdują się powyżej węzłów.
Każdy węzeł zawiera listę numerów bloków dyskowych w których zapisany jest plik który opisuje. (Właściwie jest to półprawda, prawidłowa tylko dla małych plików, ale reszta detali nie jest tutaj istotna). Zwróć uwagę, że węzły nie zawierają nazwy pliku.
Nazwy plików znajdują się w strukturze katalogów. Struktura katalogów właśnie przypisuje nazwy do numerów węzłów. To dlatego pod Unixem nazwy plików mogą mieć wielorakie prawdziwe nazwy (lub twarde skojarzenia); to tylko wielokrotne pozycje katalogu wskazujące na ten sam węzeł.
W najprostszym przypadku, cały system plików Unixa egzystuje tylko na jednej partycji dyskowej. Chociaż można zobaczyć taką konfigurację na niektórych małych osobistych systemach, jest to raczej niezwykłe. Bardziej typowe jest jego rozłożenie pomiędzy kilka partycji dyskowych, być może na różnych dyskach fizycznych. Tak więc, na przykład, twój może mieć małą partycję z jądrem, odrobinę większą gdzie znajdują się narzędzia systemu operacyjnego i dużo większą z katalogami domowymi użytkownika.
Jedyną partycją do której masz dostęp bezpośrednio po załadowaniu jest twoja główna partycja (root partition). Trzyma ona główny katalog (root directory) systemu plików, główny węzeł pod którym wisi wszystko inne.
Inne partycje systemu muszą być przyłączone do tego głównego, żeby cały system plików z wieloma partycjami był dostępny. Połowie drogi przez proces ładowania Unix czyni dostępnymi te nie-główne partycje. Montuje każdą z nich do katalogu na partycji głównej.
Na przykład, jeśli masz katalog Unixa nazywający się "/usr", jest to prawdopodobnie punkt montowania partycji zawierającej wiele programów zainstalowanych z Unixem, ale nie wymaganych podczas ładowania.
Teraz przyglądniemy się systemowi plików od góry do dołu. Kiedy otwierasz plik (taki jak, powiedzmy, /home/esr/WWW/ldp/fundamentals.sgml) dzieje się co następuje:
Twoje jądro startuje jako nadzorca systemu plików Unixa (na partycji głównej). Szuka katalogu nazwanego" home". Zwykle "home" jest punktem montowania dużej partycji użytkownika, tak więc przechodzi tam. W głównym katalogu tej partycji użytkownika szuka pozycji "esr" i uzyskuje numer węzła. Przechodzi do tego węzła, zauważa że jest to katalog i szuka "WWW". Uzyskuje węzeł przechodzi do odpowiadającemu mu podkatalogu i szuka "ldp". Uzyskuje węzeł jeszcze innemu podkatalogi. Otwiera go i szuka numeru węzła dla" fundamentals.sgml". Ten węzeł nie jest katalogiem, ale zamiast tego zawiera listę bloków dyskowych skojarzonych z tym plikiem.
Wcześniej zasugerowaliśmy, że system plików może być delikatną rzeczą. Teraz wiesz, że aby dostać się do pliku musisz przejść na skróty poprzez coś co może być przypadkowo długim łańcuchem katalogów i odniesień do węzłów. A teraz przypuśćmy, że twój dysk twardy nabawił się błędnych miejsc.
Jeśli masz szczęście zostaną zniszczone tylko zniszczone niektóre pliki z danymi. Jeśli masz pecha może to uszkodzić strukturę plików lub numery węzłów i pozostawić całe drzewo katalogów twojego systemu w stanie zawieszenia - lub, gorzej, poskutkować uszkodzoną strukturą, wskazującą wiele dróg do tego samego bloku dyskowego lub węzła. Takie uszkodzenie może być rozniesione drogą normalnych operacji na plikach, uszkodzonych danych które były w uszkodzonych miejscach.
Szczęśliwie, ta ewentualność stała się raczej niezwykła ponieważ dyski stały się bardziej niezawodne. Mimo to, Unix będzie chciał okresowo sprawdzać integralność systemu plików, aby się upewnić, że wszystko jest w porządku. Nowoczesne Unixy przeprowadzają szybki test integralności każdej partycji podczas ładowania, zanim ją zamontują. Raz na jakiś czas przeprowadzają bardziej gruntowny test, który zajmuje kilka minut więcej.
W obliczu tych wszystkich opinii, że Unix potwornie skomplikowany i narażony na uszkodzenia, może dodawać otuchy wiedza o tym, że test podczas ładowania zwykle wyłapuje i naprawia typowe problemy zanim staną się naprawdę niebezpieczne. Inne systemy operacyjne nie mają tej możliwości dzięki czemu ładują się odrobinę szybciej, ale pozostawiają cię znacznie bardziej wpieprzonego kiedy próbujesz ręcznie odzyskać dane (i to zakładając, że masz kopię Norton Utilities lub czegoś podobnego w bezpiecznym miejscu....)
Zajmowaliśmy się już tym jak działają programy. Każdy program musi się ostatecznie wykonać jako strumień bajtów będącymi instrukcjami języka maszynowego twojego komputera. Ale ludzie nie radzą sobie zbyt dobrze z językiem maszynowym; umiejętność ta stała się rzadka sztuką nawet pomiędzy hakerami.
Prawie cały kod Unixa, z wyjątkiem niewielkiego fragmentu bezpośrednie wsparcia dla interfejsu sprzętowego w jądrze, jest obecnie napisany w języku wysokiego poziomu. ("Wysoki poziom" w tym terminie jest reliktem używanym do rozróżnienia tych języków od języków niskiego poziomu (asemblerów), które w zasadzie były cienkim opakowaniem języka maszynowego).
Istnieje kilka różnych rodzajów języków wysokiego poziomu. Żeby rozmawiać o tym, musisz sobie uzmysłowić, że kod źródłowy programu (utworzona przez człowieka, nadająca się do edycji wersja) musi zostać poddana pewnego rodzaju tłumaczeniu na język maszynowy który komputer ostatecznie wykonuje.
Najbardziej konwencjonalnym rodzajem języków są języki kompilowane. Języki kompilowane poddawane są tłumaczeniu na uruchamialne pliki binarnego kodu maszynowego przez specjalny program nazywany (raczej logicznie) kompilatorem. Kiedy raz plik binarny został wygenerowany, możesz uruchamiać go bezpośrednio bez oglądania się znowu na kod źródłowy. (Większość oprogramowania jest dostarczana jako pliki binarne skompilowane z kodu którego nie widzisz.)
Języki kompilowane zapewniają znakomite wyniki i mają najbardziej kompletny dostęp do systemu operacyjnego, ale także trudno w nich programować.
C, język w którym jest napisany Unix, jest zdecydowanie najbardziej istotnym wśród nich (wraz ze swoim wariantem C++). FORTRAN jest innym językiem kompilowanym ciągle używanym pomiędzy inżynierami i naukowcami, ale jest lata starszy i znacznie bardziej prymitywny. W świecie Unixa żadne inne języki kompilowane nie są powszechnie używane. Poza nim, COBOL jest bardzo szeroko używany dla programów finansowych i biznesowych.
W użyciu jest wiele innych języków kompilowanych, ale większość z nich jest albo na wymarciu, albo są narzędziami wyłącznie badawczymi. Gdy jesteś nowym człowiekiem zajmującym się rozwojem Unixa, używającym języka kompilowanego, to jest to w przytłaczającej większości C lub C++.
Języki interpretowane zależą od interpretera, programu który czyta kod źródłowy i tłumaczy go w locie na obliczenia i funkcje systemowe. Kod źródłowy musi być interpretowany na nowo (w obecności interpretera) za każdym razem kiedy jest wykonywany.
Języki interpretowane są z zasady wolniejsze i często mają ograniczony dostęp do systemu operacyjnego i sprzętu. Z drugiej strony są łatwiejsze do programowania i bardziej wyrozumiałe dla błędów w kodzie źródłowym od języków kompilowanych.
Wiele narzędzi Unixowych, włączając w to powłokę, jest faktycznie małymi językami interpretowanymi. BASIC jest zwykle interpretowany, także Tcl. Historycznie, najważniejszym językiem interpretowanym był LISP (znacznie lepszy niż większość jego sukcesorów). Dzisiaj Perl jest bardzo szeroko używany i coraz bardziej popularny.
Od 1990 rodzaj hybrydowych języków używających zarówno kompilacji jak i interpretacji staje coraz ważniejszy. Języki pseudokodu są podobne do języków kompilowanych w tym, że kod źródłowy jest tłumaczony na niewielkich rozmiarów formę binarną która jest ostatecznie wykonywana, ale nie jest to kod maszynowy. Zamiast niego jest pseudokod który jest zwykle znacznie prostszy, ale znacznie potężniejszy niż prawdziwy język maszynowy. Kiedy uruchamiasz program, interpretujesz pseudokod.
Pseudokod może działać prawie tak samo szybko jak skompilowany plik binarny (interpreter pseudokodu może być całkiem prosty, mały i szybki). Ale języki pseudokodu utrzymują elastyczność i moc dobrego interpretera.
Ważnymi językami pseudokodu są Python i Java.
Aby Ci pomóc zrozumieć jak działa Internet przyglądniemy się temu co dzieje się podczas typowej operacji w Internecie ustawianiu przeglądarki na główną stronę tego dokumentu w jego domowej witrynie w pajęczynie na stronach Projekt Dokumentacji Linuksa (Linux Documentation Project).Adresem tego dokumentu jest:
http://sunsite.unc.edu/LDP/HOWTO/Fundamentals.html
co oznacza, że jest on obecny w pliku /LDP/HOWTO/Fundamentals.html w katalogu WWW hosta sunsite.unc.edu.
Pierwszą rzeczą którą robi twoja przeglądarka jest nawiązanie połączenia sieciowego z maszyną na której jest dokument. Aby to zrobić, najpierw szuka lokalizacji sieciowej hosta sunsite.unc.edu. Odpowiednia lokacja jest właściwie numerem nazywanym adresem IP (potem wyjaśnię co znaczy IP).
Aby to zrobić twoja przeglądarka wysyła zapytanie do programu nazywanego serwerem nazw. Serwer nazw może znajdować się na twojej maszynie, ale prawdopodobnie działa na usługowym komputerze z którym komunikuje się twój komputer. Kiedy łączysz się poprzez dostawcę Internetu (ISP) część twojej procedury konfiguracyjnej prawie na pewno wymaga poinformowania twojego oprogramowania internetowego o adresie IP serwera nazw w sieci twojego dostawcy internetowego (ISP).
Serwer nazw na innej maszynie komunikuje się z innymi, wymieniając i zbierając wszystkie informacje potrzebne do rozszyfrowania nazw hostów (przypisania ich do adresów IP). Twój serwer nazw może zapytać trzy lub cztery miejsca w poprzek sieci w procesie rozszyfrowywania sunsite.unc.edu, ale zwykle dzieję się to bardzo szybko (poniżej sekundy).
Serwer nazw informuję twoją przeglądarkę, że adresem IP sunsite.unc.edu jest 152.2.22.81; wiedząc to twój komputer będzie w stanie wymieniać bity z sunsite.unc.edu. bezpośrednio.
Tym co robi przeglądarka jest wysyłanie do serwera WWW na Sunsite komend takich jak:
GET /LDP/HOWTO/Fundamentals.html HTTP/1.0
Tutaj jest opisane jak to się dzieje. Komenda jest przetwarzana w pakiet, blok bitów podobnych do telegramu, który jest opakowany w ważne rzeczy; adres źródła (adres IP twojego komputera), adres przeznaczenia (152.2.22.81) i numer usługi lub portu (80, w tym przypadku), który wskazuje, że jest to żądanie WWW.
Twój komputer wysyła pakiet poprzez drut (połączenie modemowe do twojego dostawcy Internetu lub sieć lokalną) aż nie dotrze do wyspecjalizowane urządzenia nazywanego routerem. Router posiada w pamięci mapę Internetu nie zawsze kompletną, ale taką która całkowicie opisuje twoje sieciowe okolice i wie jak dotrzeć do routerów dla innych okolic w Internecie.
Twój pakiet może przejść poprzez kilka routerów w drodze do miejsca przeznaczenia. Routery są sprytne. Obserwują jak długo zajmuje innym routerom potwierdzenie otrzymania pakietu. Używają tych informacji do kierowania ruchu na szybkie łącza. Zwracają także uwagę kiedy inne routery (lub kable) są poza siecią i kompensują to, gdy jest to możliwe, poprzez szukanie tras.
Jest wielkomiejską legendą, że Internet został zaprojektowany aby przetrwać wojną jądrową. To nie jest prawda, ale architektura Internetu jest ekstremalnie sprawna, jeśli chodzi o wyciskanie niezawodnych wyników z zawodnego sprzętu w naszych niepewnym świecie. Jest to bezpośrednim następstwem faktu, że jego inteligencja jest rozproszona pomiędzy tysiące routerów, a nie kilka ogromnych przełączników (jak sieć telefoniczna). Znaczy to, że uszkodzenia są sprawnie lokalizowane i sieć może je ominąć.
Zaraz po tym jak twój pakiet dostanie się do miejsca przeznaczenia, komputer używa numeru usługi aby wprowadzić dane do serwera WWW. Serwer WWW wie gdzie skierować odpowiedź dzięki przyglądnięciu się adresowi IP źródła pakietu komendy. Kiedy serwer WWW wysyła dokument jest on dzielony na liczne pakiety. Rozmiar pakietu jest różny zależnie od medium transmisyjnego i typu usługi.
Aby zrozumieć jak jest utrzymywana wielopakietowa transmisja, musisz wiedzieć że Internet używa właściwie dwóch protokołów, przy czym jeden znajduje się ponad drugim.
Znajdujący się niżej protokół, IP (Internet Protocol) potrafi przesłać osobne pakiety ze adresu źródła do adresu miejsca przeznaczenia (to dlatego są one nazywane adresami IP). Jednakże, IP nie jest niezawodny, jeśli pakiety zostaną stracone źródło i maszyna przeznaczenia mogą nigdy o tym nie wiedzieć. W żargonie sieciowym, IP jest protokołem bezstykowym (connectionless) wysyłający wystrzeliwuje pakiety do odbiorcy i nie spodziewa się potwierdzenia odbioru.
IP jest szybki i tani. Czasami szybkość, niska cena i zawodność jest w porządku. Kiedy grasz po sieci w DOOMa lub QUAKE'a, każdy pocisk jest reprezentowany przez pakiet IP. Jeśli kilka z nich zostanie zgubionych, to nie ma wielkiego problemu.
Wyższy poziom, TCP (Transmission Control Protocol), zapewnia niezawodność. Kiedy dwa komputery negocjują połączenie TCP (co robią używając IP), odbiorca wie że ma wysyłać do nadawcy potwierdzenia otrzymanych pakietów. Jeśli nadawca nie otrzyma po pewnym czasie potwierdzenia, wysyła ponownie dany pakiet. Ponadto, nadawca nadaje każdemu pakietowi TCP kolejny numer, który odbiorca może użyć do złożenia pakietów w odpowiedniej kolejności (może być to konieczne gdy połączenie sieciowe chwieje się).
Pakiety TCP/IP zawierają także sumę kontrolną, aby móc wykryć dane uszkodzone przez złe połączenia. Tak więc, z punktu widzenia kogokolwiek kto używa TCP/IP i serwerów nazw, wyglądają one jak niezawodny sposób przekazywania strumieni bajtów pomiędzy parami nazw hostów/numerów usług. Ludzie którzy piszą protokoły sieciowe prawie nigdy nie muszą myśleć o pakietowaniu, składaniu pakietów w odpowiedniej kolejności, sprawdzaniu błędów, sumach kontrolnych i retransmisji, rzeczy te znajdują się poniżej tego poziomu.
Teraz powróćmy do naszego przykładu. Przeglądarki i serwery WWW komunikują za pomocą użytkowego protokołu który działa powyżej TCP/IP, używając go po prostu jako sposobu przekazywania łańcuchów bajtów tam i z powrotem. Ten protokół nazywany jest HTTP (Hyper-Text Transfer Protocol) i już widzieliśmy jedną z jego komend - przykład z GET powyżej.
Kiedy komenda GET przyjdzie do serwera WWW sunsite.unc.edu z numerem usługi 80, zostanie wysłana do demona który nasłuchuje na porcie 80. Większość usług internetowych została zaimplementowana za pomocą demonów na serwerach które nic nie robią, ale czekają na portach, obserwują je i wykonują nadchodzące komendy.
Gdyby konstrukcja Internetu miała jedną ogólną zasadę, to było by nią to, że wszystkie części powinny być tak proste i łatwe w obsłudze jak to możliwe. HTTP i jego krewni (jak SMTP, Mail Transfer Protocol), który jest używany przesyłania poczty elektronicznej pomiędzy hostami), zasadniczo używają prostych, tekstowych komend zakończonych znakiem końca wiersza CR/LF (carriage return/line feed).
Jest to nieznacznie niewydolne; w niektórych okolicznościach możesz otrzymać większą szybkość używając mocno zakodowanego protokołu binarnego. Ale doświadczenie pokazuje, że korzyści z komand łatwych do zrozumienia przez człowieka przewyższają wszelkie marginesowe przyrosty w wydajności, które można otrzymać działając w sposób skomplikowany i nieprzeźroczysty.
Dlatego też, tym co demon na serwerze wysyła z powrotem poprzez TCP/IP jest także tekst. Początek odpowiedzi będzie wyglądał podobnie to tego (kilka nagłówków może zostać zatajonych):
HTTP/1.1 200 OK.
Date: Sat, 10 Oct 1998 18:43:35 GMT
Server: Apache/1.2.6 Red Hat
Last-Modified: Thu, 27 Aug 1998 17:55:15 GMT
Content-Lenght: 2982
Content-Type: text/html
Za tymi nagłówkami będzie pusta linia i tekst strony WWW (po którym połączenie jest zrywane). Twoja przeglądarka wyświetla tą stronę. Nagłówki mówią jej jak (w szczególności, nagłówek Content-Type informuje, że zwrócone dane są rzeczywiście HTML).