Interprocess Communication

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Лекція № 1

Лекція № 17


Interprocess Communication


Ми з вами говорили, що далі мова піде про поділюваних ресурсах, доступ до яких може здійснюватися з боку довільних процесів, в загальному випадку, у довільному порядку. Ці ресурси доступні будь-якому процесу, а процеси не обов'язково повинні бути спорідненими. При наявності такої схеми виникають дві принципові проблеми:

  1. Іменування;

  2. Синхронізація;


Проблеми іменування пов'язані з тим, що родинних зв'язків немає й у спадщину передати нічого не можна.

Якщо проблема іменування вирішена, то виникає проблема синхронізації доступу - як організувати обмін з ресурсами, щоб цей обмін був коректним. Якщо у нас є, наприклад, ресурс "оперативна пам'ять", то коли один процес ще не дописав інформацію, а інший процес вже прочитав весь блок, то виникає некоректна ситуація.

Рішення цих проблем ми й будемо розглядати.


Проблема іменування вирішується за рахунок асоціювання з кожним ресурсом деякого ключа. У загальному випадку це цілочисельне значення. Тобто при створенні ресурсу, що його автор приписує йому номер та визначає права доступу до цього ресурсу. Після цього будь-який процес, який вкаже системі, що він хоче спілкуватися з ресурсом з ключем N, і володіє необхідними правами доступу, буде допущений для роботи з цим ресурсом.

Однак таке рішення не є ідеальним, тому що цілком можлива колізія номерів - коли збігаються номери поділюваних ресурсів. У цьому випадку процеси будуть плутатися, що неминуче призведе до помилок. Тому в системі передбачено стандартне засіб генерації унікальних ключів. Для створення унікального ключа використовується функція ftok


# Include

# Include

key_t ftok (char * s, char c);


Суть її дії - за текстовому рядку і символу генерується унікальний для кожної такої пари значення ключа. Після цього сгенерованими ключем можна користуватися як для створення ресурсу, так і для підтвердження використання ресурсу. Більше того, для виключення колізій, рекомендується вказувати в якості параметра "покажчика на рядок" шлях до деякого свого файлу. Другий аргумент - символьний, який дозволяє створювати деякі варіанти ключа, пов'язаного з цим ім'ям, цей аргумент називається проектом (project). При такому підході можна домогтися відсутності колізій.

Давайте подивимося конкретні засоби роботи з розділяються ресурсами.


Колективна пам'ять.

Загальна схема роботи з розділяютьсяресурсами така - є певний процес-автор, створює ресурс з якими-небудь параметрами. При створенні ресурсу пам'яті, що розділяється задаються три параметри - ключ, права доступу і розмір області пам'яті. Після створення ресурсу до нього можуть бути підключені процеси, які бажають працювати з цією пам'яттю. Відповідно, є дія підключення до ресурсу за допомогою ключа, який генерується за тими ж правилами, що і ключ для створення ресурсу. Зрозуміло, що тут є момент деякої рассинхронізациі, який пов'язаний з тим, що споживач ресурсу, що розділяється (процес, який буде працювати з ресурсом, але не є його автором) може бути запущений і почати підключатися до запуску автора ресурсу. У цій ситуації особливого криміналу немає, так як є функції управління доступом до ресурсу, з використанням яких можна встановити деякі опції, що визначають правила роботи функцій, взаємодіючих з розділяються ресурсами. Зокрема, існує опція, що змушує процес дочекатися появи ресурсу. Це також, можливо, не дуже добре, наприклад, автор може так і не з'явитися, але іншого виходу немає, це є деякі накладні витрати. Ось в загальних словах - що є що.

Давайте розглянемо ті функції, які надаються нам для роботи з розділяються ресурсами.


Перша функція - створення спільної пам'яті.

int shmget (key_t key, int size, int shmemflg);

key - ключ пам'яті, що розділяється

size - розмір розділу пам'яті, який повинен бути створений

shmemflg - прапори


Ця функція повертає ідентифікатор ресурсу, який асоціюється зі створеним по даному запиту ресурсом. Тобто в рамках процесу за аналогією з файловими дескрипторами кожному ресурсу, що розділяється визначається його ідентифікатор. Треба розділяти ключ - це загальносистемний атрибут, і ідентифікатор, використовуючи який ми працюємо з конкретним ресурсом в рамках процесу.

За допомогою цієї функції можна як створити новий розділяється ресурс "пам'ять" (у цьому випадку в прапорах повинен бути зазначений IPC_CREAT)?, А також можна підключитися до існуючого ресурсу, що розділяється. Крім того, в можливих прапорах може бути вказано прапорець IPC_EXECL, він дозволяє перевірити і підключитися до існуючого ресурсу - якщо ресурс існує, то функція підключає до нього процес і повертає код ідентифікатора, якщо ж ресурс не існує, то функція повертає -1 і відповідний код в errno.


Наступна функція - доступ до пам'яті, що розділяється:

char * shmat (int shmid, char * shmaddr, int shmflg);

shmid - ідентифікатор ресурсу, що розділяється

shmaddr - адреса, з якого ми хотіли б розмістити поділювану пам'ять


При цьому, якщо значення shmaddr - адреса, то пам'ять буде підключена, починаючи з цієї адреси, якщо його значення - нуль, то система сама підбере адресу початку. Також як значення цього аргументу можуть бути деякі зумовлені константи, які дозволяють організувати, зокрема вирівнювання адреси по сторінці або початку сегмента пам'яті.

shmflg - прапори. Вони визначають різні режими доступу, зокрема, є прапор SHM_RDONLY.


Ця функція повертає покажчик на адресу, починаючи з якого буде починатися запитувана колективна пам'ять. Якщо відбувається помилка, то повертається -1.

Хотілося б трохи поговорити про права доступу. Вони реально можуть використовуватися і коректно працювати не завжди. Так як, якщо апаратно не підтримується закриття області даних на читання або на запис, то в цьому випадку можуть виникнути проблеми з реалізацією такого роду прапорів. По-перше, вони не будуть працювати, тому що ми отримуємо покажчик і починаємо працювати з покажчиком, як з покажчиком, і загальна схема тут не передбачає захисту. Друге, можна програмно зробити так, щоб працювали прапори, але тоді ми не зможемо вказувати довільну адресу, в цьому випадку система буде підставляти і повертати в якості адресу розділеної пам'яті деякі свої адреси, звернення до яких буде створювати свідомо помилкову ситуацію, виникне переривання процесу, під час якого система подивиться - хто і чому був ініціатором некоректного звернення до пам'яті, і якщо той процес має потрібні права доступу - система підставить потрібні адреси, інакше доступ для процесу буде заблокований. Це схоже на встановлення контрольної точки в програмі при налагодженні, коли створювалася свідомо помилкова ситуація для того, щоб можна було перервати процес і оцінити його стан.


Третя функція - відкріплення поділюваної пам'яті:

int shmdt (char * shmaddr);

shmaddr - адреса прикріпленою до процесу пам'яті, який був отриманий при підключенні пам'яті на початку роботи.


Четверта функція - управління пам'яттю, що розділяється:

int shmctl (int shmid, int cmd, struct shmid_ds * buf);

shmid - ідентифікатор пам'яті, що розділяється

cmd - команда управління.


Зокрема, можуть бути команди: IPC_SET (змінити права доступу та власника ресурсу - для цього треба мати ідентифікатор автора даного ресурсу або користувачів), IPC_STAT (показує стан ресурсу - в цьому випадку заповнюється інформація в структуру, покажчик на яку передається третім параметром, IPC_RMID (знищення ресурсу - після того, як автор створив процес - з ним працюють процеси, які підключаються і відключаються, але не знищують ресурс, а за допомогою цієї команди ми знищуємо ресурс в системі).

Це все, що стосується функцій управління розділяється.

Передача повідомлень.

Наступним засобом взаємодії процесів у системі IPC - це передача повідомлень. Її суть в наступному: у системі є так звана чергу повідомлень, в якій кожне повідомлення представляє з себе структуру даних, з якою асоційований буфер, що містить текст повідомлення і ознака, яка називається типом повідомлення. Черга повідомлень може бути розглянута двояко:

  • чергу розглядається, як одна єдина наскрізна чергу, порядок повідомлень в якій визначається хронологією їх потрапляння в цю чергу.

  • крім того, так як кожне повідомлення має тип (на схемі - буква поруч з номером повідомлення), то цю чергу можна розглядати, як суперпозицію черг, пов'язану з повідомленнями одного типу.


Система IPC дозволяє створювати розділяється ресурс, званий "черга повідомлень" - таких черг може бути довільна кількість. За аналогією з пам'яттю, - ми можемо створити чергу, підключитися до неї, надіслати повідомлення, приймає повідомлення, знищити чергу і т.д. Розглянемо функції роботи з чергами повідомлень:


Створення черги повідомлень:

int msgget (key_t key, int flags);

У залежності від прапорів при зверненні до цієї функції або створюється розділяється ресурс, або здійснюється підключення до вже існуючого.


Відправка повідомлення:

int msgsnd (int id, struct msgbuf * buf, int size, int flags);

id - ідентифікатор черги повідомлення;

struct msgbuf {

long type; / * тип повідомлення * /

char mtext [s] / * вказівник на тіло повідомлення * /

}

size - розмір повідомлення, тут вказується розмір повідомлення, розміщеного за вказівником buf;

flags - прапори, зокрема, прапором може бути константа IPC_NOWAIT. При наявності такого прапора будуть наступні дії - можлива ситуація, коли буфера, передбачені системою під чергу повідомлень, переповнені. У цьому випадку можливі два варіанти - процес буде чекати звільнення простору, якщо не вказано IPC_NOWAIT, або функція поверне -1 (з відповідним кодом у errno), якщо було вказано IPC_NOWAIT.


Отримання повідомлення:

int msgrcv (int id, struct msgbuf * buf, int size, long type, int flags);

id - ідентифікатор черзі;

buf - покажчик на буфер, куди буде прийнято повідомлення;

size - розмір буфера, в якому буде розміщено текст повідомлення;

type - якщо тип дорівнює нулю, то буде прийнято перше повідомлення з наскрізною черги, якщо тип більше нуля, то в цьому випадку буде прийнято перше повідомлення з черги повідомлень, пов'язаної з типом, рівним значенням цього параметра.

flags - прапори, зокрема, IPC_NOWAIT, він забезпечить роботу запиту без очікування приходу повідомлення, якщо такого повідомлення в момент звернення функції до ресурсу не було, інакше процес буде чекати.


Управління чергою:

int msgctl (int id, int cmd, struct msgid_dl * buf);

id - ідентифікатор черзі;

cmd - команда управління, для нас інтерес представляє IPC_RMID, яка знищить ресурс.

buf - цей параметр буде залишений без коментаря.


Ми описали два засоби взаємодії між процесами. Що ж ми побачили? Зрозуміло, що назви та описи інтерфейсів мало зрозумілі. Перш за все слід відмітити те, що як тільки ми переходимо до питання взаємодії процесів, у нас виникає проблема синхронізації. І тут ми вже бачимо проблеми, пов'язані з тим, що після того, як ми попрацювали з пам'яттю, або чергою повідомлень, в системі може залишатися "мотлох", наприклад, процеси, які чекають повідомлень, які в свою чергу не були послані. Так, якщо ми звернулися до функції отримання повідомлень з типом, яке взагалі не прийшов, і якщо не стоїть ключ IPC_NOWAIT, то процес буде чекати його появи, поки не зникне ресурс. Або ми можемо забути знищити ресурс (і система нікого не поправить) - цей ресурс залишиться у вигляді забруднюючої елемента системи.

Коли людина починає працювати з подібними засобами, то він бере на себе відповідальність за всі наслідки, які можуть виникнути. Це перший набір проблем - системна синхронізація і акуратність. Друга проблема - синхронізація даних, коли приймач і передавач працюють синхронно. Зауважимо, що найгірший із синхронізації ресурс з розглянутих нами - колективна пам'ять. Це означає, що коректна робота з пам'яттю, що не може здійснюватися без використання засобів синхронізації, і, зокрема, деяким елементом синхронізації може бути черга повідомлень. Наприклад, ми можемо записати в пам'ять дані і надіслати повідомлення приймача, що інформація надійшла в ресурс, після чого приймач, отримавши повідомлення, починає зчитувати дані. Також як синхронізуючого засоби можуть застосовуватися сигнали.

І це головне - не мова інтерфейсів, а проблеми, які можуть виникнути при взаємодії паралельних процесів.

Лекція № 18


До сьогоднішнього дня ми розібрали два механізми взаємодії процесів у системі IPC - це механізм спільної (або розділяється) пам'яті і механізм повідомлень. Ми з вами з'ясували, що однією з основних проблем, яка виникає при взаємодії процесів, є проблема синхронізації. Яскравим прикладом механізму, для якого ця проблема є найбільш гострою, є механізм взаємодії процесів з використанням пам'яті, що розділяється.

Ви пам'ятаєте, що механізм пам'яті, що розділяється дозволяє створювати об'єкт, який стає доступним всім процесам, що підтвердив ключ доступу до цього об'єкта, а також мають відповідні права. Після цього загальна пам'ять стає, з точки зору кожного з цих процесів, як би фрагментом адресного простору кожного з них, до якого цей процес може добиратися через вказівник цього адресного простору. З іншого боку немає жодних засобів, які дозволили б синхронізувати читання і запис в цю область даних. Так як в цю область даних одночасно має доступ довільну кількість процесів, то проблема синхронізації тут має місце бути.

Можлива ситуація, коли один з процесів почав запис до колективної пам'ять, але ще не закінчив, але інший процес не дочекався завершення запису, вважав і почав користуватися цією інформацією. У цьому випадку можливі колізії. Тобто без синхронізації використовувати механізм пам'яті, що розділяється неможливо.

Наступний механізм, який ми з вами розглянули - черга повідомлень. Є можливість спільної роботи з поділюваним об'єктом, який називається чергу повідомлень. Є повідомлення, яке складається з деякого специфікатора типу, і деякого набору даних. Процес, підтвердивши ключ і маючи права доступу до цього ресурсу, що розділяється, може здійснювати дії по запису повідомлень в чергу, і з читання повідомлень з черги.

Порядок читання та запису повідомлень з черги відповідає назві цієї структури - черга. Крім того, за рахунок того, що кожне повідомлення типізовані, є можливість розгляду цієї черги з кількох точок зору. Перша точка зору - це одна черга і порядок у ній хронологічний. Друга точка зору - це можливість подання цієї черги у вигляді кількох черг, кожна з яких містить елементи певного типу.

Зрозуміло, що механізм повідомлень може виступати в двох ролях: як засіб передача даних, і як засіб синхронізації (зрозуміло яким чином).

Отже, до сьогоднішнього дня ми познайомилися з двома цими механізмами. Нагадаю, як тільки ми переходимо до роботи від однопроцессной задачі до задачі багатопроцесорний, у нас відразу ж виникають проблеми, пов'язані з тим, що будь-який паралелізм накладає певну відповідальність на програму. Це відповідальність за синхронізації доступу до пам'яті, що розділяється, відповідальність за правильність підпрограми, що займається прийомом і передачею повідомлень і т.д. Можна, наприклад, помилитися в механізмі передачі і прийому повідомлень за рахунок того, що якийсь процес буде нескінченно довго чекати неіснуюче повідомлення, то, яке ніколи в черзі не з'явиться, і система вам ніколи таку помилку не зафіксує. Тобто можливі зависання процесів, можуть утворитися незвільнені ресурси ("сміття"), і це призводить до деградації системи.

Зараз ми напишемо наступну програму: перший процес буде читати деяку текстову рядок з стандартного вводу і у випадку, якщо рядок починається на літеру 'a', то цей рядок в якості повідомлення буде передана процесу А, якщо 'b' - процесу В, якщо ' q '- то процесам А і В і потім буде здійснений вихід. Процеси А і В роздруковують отримані рядка на стандартний висновок.


Основний процес

# Include

# Include

# Include

# Include

struct {long mtype; / * тип повідомлення * /

char Data [256]; / * повідомлення * /

} Message;


int main ()

{Key_t key; int msgid; char str [256];

key = ftok ("/ usr / mash", 's') / * отримуємо унікальний ключ, однозначно визначає доступ до ресурсу даного типу * /

msgid = msgget (key, 0666 | IPC_CREAT) / * створюємо чергу повідомлень, 0666 визначає права доступу * /

for (;;) {/ * запускаємо вічний цикл * /

gets (str); / * читаємо зі стандартного вводу рядок * /

strcpy (Message.Data, str); / * і копіюємо її в буфер повідомлення * /

switch (str [0]) {

case 'a':

case 'A': Message.mtype = 1 / * встановлюємо тип і посилаємо повідомлення в чергу * /

msgsnd (msgid, (struct msgbuf *) (& Message), strlen (str) +1, 0);

break;

case 'b':

case 'B': Message.mtype = 2;

msgsnd (msgid, (struct msgbuf *) (& Message), strlen (str) +1, 0);

break;

case q ':

case 'Q': Message.mtype = 1;

msgsnd (msgid, (struct msgbuf *) (& Message), strlen (str) +1, 0);

Message.mtype = 2;

msgsnd (msgid, (struct msgbuf *) (& Message), strlen (str) +1, 0);

sleep (10); / * чекаємо отримання повідомлень процесами А і В * /

msgctl (msgid, IPC_RMID, NULL); / * знищуємо чергу * /

exit (0);

default: break;

}

}

}

Процес-приймач А / * Процес У аналогічний з точністю до четвертого параметра в msgrcv * /

# Include

# Include

# Include

# Include

struct {long mtype;

char Data [256];

} Message;


int main ()

{Key_t key; int msgid;

key = ftok ("/ usr / mash", 's') / * отримуємо ключ за тими ж параметрами * /

msgid = msgget (key, 0666 | IPC_CREAT) / * створюємо чергу повідомлень * /

for (;;) {/ * запускаємо вічний цикл * /

msgrcv (msgid, (struct msgbuf *) (& Message), 256, 1, 0); / * читаємо повідомлення з типом 1 * /

if (Message.Data [0] = 'q' | | Message.Data [0] = 'Q') break;

printf ("% s", Message.Data);

}

exit (0);

}

Семафори

З точки зору тих проблем, з якими ми знайомимося, семафори - це є цілком законне і існуюче поняття. Вперше ввів це поняття досить відомий вчений Дейкстра. Семафор - це деякий об'єкт, який має цілочисельне значення S, і з яким пов'язані дві операції: V (S) і P (S).

Операція P (S) зменшує значення семафора на 1, і якщо S  0 процес продовжує роботу. Якщо S <0, то процес буде призупинено і стане в чергу очікування, пов'язану з семафором S, до тих пір, поки його не звільнить інший процес.

Операція V (S) збільшує семафор на 1. Якщо S> 0, то процес продовжує виконання. Якщо S  0, то розблокується один з процесів, що очікує у черзі процесів, пов'язаної з семафором S, і поточний процес продовжить виконання.

Вважається, що операції P (S) і V (S) неподільні. Це означає, що виконання цих операцій не може перерватися до їх завершення. Тобто якщо семафор реалізовано у системі, то це повинна бути одна команда.


Окремим випадком продекларованого семафора є двійковий семафор, максимальне значення якого дорівнює одиничці. При цьому значення S може бути дорівнює 1, це означає, що жоден з процесів (пов'язаних з цим семафором) не перебуває в критичному ділянці. При S = ​​0 один з процесів перебуває у критичному ділянці {ось-ось потрапить в чергу}, а інший нормально функціонує. При S = ​​-1 один з процесів перебуває у критичному ділянці, а інший заблокований і знаходиться в черзі.

Насправді двійкові семафори найбільш часто знаходили застосування в апаратних реалізаціях, наприклад, у багатомашинних комплексах із загальною оперативною пам'яттю.


Одним з поділюваних ресурсів, який підтримує система IPC є т.зв. масив семафорів. Система дозволяє процесам, які беруть участь у взаємодії з даними ресурсом, збільшувати або зменшувати один або кілька семафорів з даного масиву на довільне значення (в межах розрядної сітки). Система забезпечує очікування процесами обнулення одного або декількох семафорів.

Давайте розглянемо кошти, що надаються системою IPC, для створення, управління і взаємодії з семафорами.


int semget (key_t key, int n, int flags);

int semop (int semid, struct sembuf * sops, int n);


struct sembuf {

short sem_num; / * номер семафора в масиві семафорів * /

short sem_op; / * код операції, яку треба виконати * /

short sem_flg; / * прапори * /

}


Перший параметр функції semget - ключ, другий - кількість семафорів (довжина масиву семафорів) і третій параметр - прапори. Через прапори можна визначити права доступу і ті операції, які повинні виконуватися (відкриття семафора, перевірка, і т.д.). Функція semget повертає цілочисельний ідентифікатор створеного ресурсу, що розділяється, або -1, якщо ресурс не вдалося створити (причина - у errno).

Перший параметр функції semop - ідентифікатор семафора, другий - покажчик на структуру sembuf і третій параметр - кількість покажчиків на цю структуру, які передаються функцією semop. У структурі міститься вся інформація про необхідний дії.

Поле операції інтерпретується наступним чином. Нехай значення семафора з номером sem_num одно sem_val. У цьому випадку, якщо значення операції не дорівнює нулю, то оцінюється значення суми (sem_val + sem_op). Якщо ця сума більше або дорівнює нулю, то значення даного семафора встановлюється рівним сумі попереднього значення та коду операції. Якщо ця сума менше нуля, то дія процесу буде призупинено до настання однієї з наступних подій:

  1. Значення суми (sem_val + sem_op) стане більше або дорівнює нулю.

  2. Прийшов якийсь сигнал. (Значення semop в цьому випадку дорівнюватиме -1).


Якщо код операції semop дорівнює нулю, то процес буде очікувати обнулення семафора. Якщо ми звернулися до функції semop з нульовим кодом операції, а до цього моменту значення семафора стало рівним нулю, то ніякого очікування не відбувається.

Розглянемо третій параметр - прапори. Якщо третій параметр дорівнює нулю, то це означає, що прапори не використовуються. Прапорів є велика кількість у т.ч. IPC_NOWAIT (при цьому прапорі у всіх тих випадках, коли ми говорили, що процес буде очікувати, він не буде чекати).

Звертаю вашу увагу, що за одне звернення до функції semop можна передати n структур і відповідно виконати дії з n семафорами з цього масиву. Якщо в цій послідовності будуть присутні дві різні операції з одні семафором, то швидше за все, виконається остання.


Функція управління масивом семафорів.


int semctl (int id, int sem_num, int cmd, union sem_buf arg);


Перший параметр - ідентифікатор, другий - номер семафора в масиві, з яким ми будемо виконувати команду cmd з третього параметра. Останній параметр - деяке об'єднання типу sembuf.

Команди можуть бути традиційні (IPC_RMID), і крім них є інші команди, і серед них IPC_SET, яка встановлює значення семафора, при цьому значення передається через об'єднання arg. При установці семафора цією функцією, затримок, які визначають основний зміст роботи семафора, не буде.

Ось ті функції, які призначені для роботи з семафорами. Приклад роботи з семафорами розглянемо на наступній лекції.

Лекція № 19


Ми зупинилися на засобах синхронізації доступу до ресурсів, - на семафорах. Ми говорили про те, що семафори - це той формалізм, який спочатку був запропонований вченим у галузі комп'ютерних наук Дейкстри, тому часто в літературі їх називають семафорами Дейкстри. Семафор - це є деяка змінна і над нею визначені операції P і V. Одна дозволяє збільшувати значення семафора, інша - зменшувати. Причому з цими змінами пов'язані можливості блокування процесу та розблокування процесу. Звернемо увагу, що мова йде про неподільні операціях, тобто тих операціях, які не можуть бути перервані, якщо почалися. Тобто не може бути так, щоб під час виконання P або V прийшло переривання, і система передала керування іншому процесу. Це принципово. Тому семафори можна реалізовувати програмно, але при цьому ми повинні розуміти, що ця реалізація не зовсім коректна, тому що

  1. програма пишеться людиною, а переривається апаратурою, звідси можливе порушення неразделяемості;

  2. в розвинених обчислювальних системах, які підтримують багатопроцесорну обробку або обробку поділюваних ресурсів у рамках одного процесу, передбачені семафорні команди, які фактично реалізовують операції P і V. Це важливо.


Ми говорили про реалізацію семафорів в Unix в системі IPC і про те, що ця система дозволяє створити розділяється ресурс "масив семафорів", відповідно, як і до будь-якого ресурсу, що розділяється, до цього масиву може бути забезпечений доступ з боку різних процесів, що володіють потрібними правами і ключем до цього ресурсу.

Кожен елемент масиву - семафор. Для управління роботою семафора є функції:

    1. semop, яка дозволяє реалізовувати операції P і V над одним або кількома семафорами;

    2. segctl - управління ресурсом. Під управлінням тут розуміється три речі:

      1. - Отримання інформації про стан семафора;

      2. - Можливість створення деякого режиму роботи семафора, знищення семафора;

      3. - Зміна значення семафора (під зміною значення тут розуміється встановлення початкових значень, щоб використовувати надалі семафори, як семафори, а не скриньки для передачі значень, інші зміни - тільки за допомогою semop);


Давайте наведемо приклад, яким спробуємо проілюструвати використання семафорів на практиці.

Наша програма буде оперувати з розділяється.

1 процес - створює ресурси "колективна пам'ять" і "семафори", далі він починає приймати рядки зі стандартного вводу і записує їх до колективної пам'ять.

2 процес - читає рядки з пам'яті, що розділяється.

Таким чином ми маємо критичний ділянку в момент, коли один процес ще не дописав рядок, а інший її вже читає. Тому слід встановити деякі синхронізації і затримки.

Слід зазначити, що, як і всі програми, які ми наводимо, ця програма не досконала. Але не тому, що ми не можемо її написати (у крайньому випадку можна попросити своїх аспірантів або студентів), а тому, що досконала програма буде займати занадто багато місця, і ми свідомо робимо деякі спрощення. Про ці спрощення ми постараємося згадувати.


1й процес:

# Include

# Include

# Include

# Include


int main (void)

{Key_t key;

int semid, shmid;

struct sembuf sops;

char * shmaddr;

char str [256];

key = ftok ("/ usr / mash / exmpl", 'S') / * створюємо унікальний ключ * /

semid = semget (key, 1,0666 | IPC_CREAT) / * створюємо один семафор з певними правами доступу * /

shmid = shmget (key, 256, 0666 | IPC_CREAT) / * створюємо поділювану пам'ять на 256 елементів * /

shmaddr = shmat (shmid, NULL, 0); / * підключаємося до розділу пам'яті, в shaddr - покажчик на буфер з пам'яттю, * /

semctl (semid, 0, IPC_SET, (union semun) 0) / * инициализируем семафор зі значенням 0 * /

sops.sem_num = 0; sops.sem_flg = 0;


/ * Запуск нескінченного циклу * /

while (1) {printf ("Введіть рядок:");

if ((str = gets (str)) == NULL) break;

sops.sem_op = 0; / * очікування обнулення семафора * /

semop (semid, & sops, 1);

strcpy (shmaddr, str); / * копіюємо рядок у розд. пам'ять * /

sops.sem_op = 3; / * збільшення семафора на 3 * /

semop (semid, & sops, 1);

}


shmaddr [0] = 'Q' / * вкажемо другий процесу на те, * /

sops.sem_op = 3; / * що пора завершуватися * /

semop (semid, & sops, 1);

sops.sem_op = 0; / * чекаємо, поки обнулиться семафор * /

semop (semid, & sops, 1);

shmdt (shmaddr) / * відключаємося від розд. пам'яті * /

semctl (semid, 0, IPC_RMID, (union semun) 0) / * вбиваємо семафор * /

shmctl (shmid, IPC_RMID, NULL); / * знищуємо поділювану пам'ять * /

exit (0);

}


2й процес:


/ * Тут нам треба коректно визначити існування ресурсу, якщо він є - підключитися, якщо ні - зробити щось ще, але саме цього ми робити не будемо * /

# Include

# Include

# Include

# Include


int main (void)

{Key_t key; int semid;

struct sembuf sops;

char * shmaddr;

char st = 0;


/ * Далі аналогічно попередньому процесу - ініціалізації ресурсів * /

semid = semget (key, 1,0666 | IPC_CREAT);

shmid = shmget (key, 256, 0666 | IPC_CREAT);

shmaddr = shmat (shmid, NULL, 0);

sops.sem_num = 0; sops.sem_flg = 0;


/ * Запускаємо цикл * /

while (st! = 'Q') {

printf ("Чекаємо відкриття семафора \ n");

/ * Очікування позитивного значення семафора * /

sops.sem_op =- 2;

semop (semid, & sops, 1);

/ * Будемо чекати, поки "значення семафора" + "значення sem_op" не перевалить за 0, тобто якщо прийде "3", то "3-2 = 1" * /

/ * Тепер значення семафора дорівнює 1 * /

st = shmaddr [0];

{/ * Критична секція - робота з пам'яттю, - в цей момент перший процес до пам'яті, що розділяється доступу не має * /}

/ * Після роботи - закриємо семафор * /

sem.sem_op =- 1;

semop (semid, & sops, 1);

/ * Повернувшись в початок циклу ми знову будемо чекати, поки значення семафора не стане більше нуля * /

}

shmdt (shmaddr) / * звільняємо поділювану пам'ять і виходимо * /

exit (0);

}


Це програма, що складається з двох процесів, синхронно працюють з пам'яттю,. Зрозуміло, що за наявності інтересу можна працювати і з повідомленнями.

На цьому ми закінчуємо велику і досить важливу тему організації взаємодії процесів в системі.

Наша самоціль - не вивчення тих коштів, які надає Unix, а вивчення принципів, які надає система для вирішення тих чи інших завдань, так як інші ОС надають аналогічні або схожі засоби управління процесами.


Системи програмування.


Система програмування - це комплекс програмних засобів, що забезпечують підтримку технологій проектування, кодування, тестування і налагодження, називається системою програмування

Етап проектування

Було сказано, що на сьогоднішній день достатньо складно, а практично неможливо створювати програмне забезпечення без етапу проектування, такого ж довгого, нудного і детального періоду, який проходить під час проектування будь-якого технічного об'єкта. Слід зрозуміти, що ті програми, які пишуться студентами в якості практичних та дипломних завдань не є по суті справи програмами - це іграшки, так як їх складність невелика, обсяги незначні і такого роду програми можна писати злегка. Реальні ж програми так не створюються, так само, як і не створюються складні технічні об'єкти. Ніхто ніколи не може собі уявити, щоб яка-небудь авіаційна компанія продекларувала створення нового літака і дала команду своїм заводам зліпити лайнер з такими-то параметрами. Так не буває. Кожен з елементів такого об'єкта, як літак, проходить складний етап проектування.

Наприклад, фірма Боїнг підняла в повітря літак "Боїнг-777", чудові цього факту полягає в тому, що літак злетів без попередньої продувки в аеродинамічній трубі. Це означає, що весь літак був спроектований і промодельований на програмних моделях, і це проектування та моделювання було настільки чітким і правильним, що дозволило відразу ж підняти літак у повітря. Для довідки - продування літака в аеродинамічній трубі стоїть божевільні гроші.

Приблизно та ж ситуація відбувається при створенні складних сучасних програмних систем. На початку 80х рр. була започаткована СОІ (стратегічна оборонна ініціатива), її ідея була в тому, щоб створити складної технічної системи, яка б в автоматичному режимі встановила контроль за пусковими установками СРСР і країн Варшавського блоку, і в разі фіксації старту з наших позицій якого -то непродекларірованного об'єкту автоматично починалася війна. Тобто запускалися б кошти знищення даного об'єкта та засоби для відповідних дій. Реально той департамент збройних сил, який займався цим проектом, зазнав ряд криз у зв'язку з тим, що провідні фахівці в галузі програмного забезпечення відмовлялися брати участь у реалізації цього проекту через неможливість коректно його спроектувати, тому що система мала гігантським потоком вхідних даних, на основі яких повинні були бути прийняті однозначні рішення, відповідальність за які оцінити досить складно. Насправді ця проблема підштовхнула до розвитку з одного боку - мов програмування, які володіли надійністю, зокрема, мова Ада, однією з метою якого було створення безпомилкового ПЗ. У таких мовах накладалися обмеження на місця, де найбільш ймовірне виникнення помилки (міжмодульних інтерфейси; вираження, де присутні різні типи даних і т.п.) Зауважимо, що мова C не задовольняє вимогам безпеки. З іншого боку - до детального проектування, яке б дозволяло деяким формальним чином описувати створюваний проект і працювати з проектом в частині його деталізації. Причому, перехід від деталізації до кодування не мав би чіткої межі. Зрозуміло, що це є деяка завдання не сьогоднішнього, а завтрашнього дня, але реально розробники програм знаходяться на шляху створення таких засобів, які дозволили б поєднати проектування і кодування. Сьогоднішні системи програмування, які будуються на об'єктно-орієнтованому підході, частково вирішують цю проблему.

Наступна проблема проектування. Ми продекларували модулі, оголосили їх взаємозв'язку, як-то описали семантику модулів (це теж проблема). Але ніхто не дасть гарантії, що цей проект правильний. Для вирішення цієї проблеми використовується моделювання програмних систем. Тобто, коли разом з побудовою проекту, який декларує всі інтерфейси, функціональність та інше, ми можемо якимось чином промоделювати роботу всієї або частин створюваної системи. Реально при створенні великих програмних систем на сьогоднішній день немає єдиних інструментаріїв для таких дій. Кожні з існуючих систем мають різні підходи. Іноді ці підходи (як і у нас, так і за кордоном) досить архаїчні.

Але тим не менше слід розуміти, що період проектування є дуже важливий момент.

Кодування

Якщо складено нормальний проект, то з кодуванням проблем немає. Але слід звернути увагу на те, що фахівець у програмуванні це не той, хто швидко пише на С, а той, хто добре і детально зможе спроектувати завдання. При сучасному розвитку інструментальних засобів закодувати зможе будь-який школяр, а спроектувати систему - це і є професійна завдання людей, що займаються програмуванням - вибрати інструментальні засоби, скласти проект, промоделювати рішення.

Основний компонент системи кодування - мова програмування. У голові кожного програміста лежить ієрархія мов програмування - від машинного коду і асемблера до універсальних мов програмування (FORTRAN, Algol, Pascal, C і т.д.), спеціалізованих мов (SQL, HTML, Java і т.д.)

Ми маємо ЯП і програму, яка написана в нотації цієї мови. Система програмування забезпечує переклад вихідної програми в об'єктний мову. Цей процес перекладу називається трансляцією. Об'єктний мова може бути як декому мовою програмування високого рівня (трансляція), так і машинний мова (компіляція). Ми можемо говорити про трансляторах-компіляторах і трансляторах-інтерпретатора.

Компілятор - це транслятор, що переводить текст програми в машинний код.

Інтерпретатор - це транслятор, який зазвичай поєднує процес перекладу та виконання програми (компілятор спочатку переводить програму, а тільки потім її можна виконати). Він, грубо кажучи, виконує кожен рядок, при цьому машинний код не генерується, а відбувається звернення до деякої стандартної бібліотеці програм інтерпретатора. Якщо результат роботи компілятора - код програми на машинній мові, то результат роботи транслятора - послідовність звернень до функцій інтерпретації. При цьому, також як і при компіляції, коли створюється відтранслювати програма, у нас теж може бути створена програма, але в цьому інтепретіруемом коді (послідовності звертань до функцій інтерпретації).

Зрозуміла різниця - компілятори більш ефективні, так як в інтерпретатора неможлива оптимізація та постійні виклики функцій також не ефективні. Але інтерпретатори більш зручні за рахунок того, що при інтерпретації можна включати у функції інтерпретації безліч сервісних засобів: налагодження, можливість інтеграції інтерпретатора і мовного редактора (компіляція це робити не дозволяє).

На сьогоднішній день кожен з методів - і компіляція та інтерпретація займають свої певні ніші.

Лекція № 20


На минулій лекції ми почали розглядати системи програмування. Насправді ця тема може бути підставою цілого курсу, тому що ця тема включає в себе все те, що може бути в сучасній науці про комп'ютери - це і хороші практичні рішення, і розроблені, реально застосовувані, теоретичні рішення, і багато іншого. Ми говорили, що система програмування - це комплекс програм, що забезпечує життєвий цикл програми в системі. Життєвий цикл створюваного програмного забезпечення містить наступні етапи:


Ми з вами говорили про важливість етапу проектування, про те що програмний продукт являє собою складний об'єкт, що має величезне число зв'язків між своїми компонентами. Пропустити етап проектування не можна. Для проектування програмних систем, необхідні спеціалізовані засоби, які дозволили б (в ідеалі) описувати проект деяким формальним чином, і послідовно уточнюючи його, приводити формальний опис проекту в реальний код програми.

Ми говорили, що важливим етапом проектування, є етап моделювання системи, тобто той етап, коли ми беремо зовнішні навантаження, які можуть надходити на систему, приписуємо властивості потоку подій, пов'язаних з цими зовнішніми навантаженнями, певний статистичний закон, і розглядаємо можливе поведінку системи при такій емуляції зовнішнього середовища. Зрозуміло, що без етапу моделювання теж важко створити будь-який програмний продукт.


Етап кодування

Ми також говорили, що важливою частиною системи програмування є засоби кодування. Етап кодування в життєвому циклі програми традиційно (і звичайно не правильно) однозначно пов'язується з поняттям системи програмування. Дуже багато, коли починають говорити про систему програмування, мають на увазі під цим транслятор мови програмування. Хотілося б цими лекціями вам показати, що система програмування - це щось суттєво більш широке, ніж транслятор. Всі компоненти однаково необхідні.

Транслятор - це програма, яка переводить програму нотації однієї мови, в нотацію іншої мови. Компілятор - це транслятор, що переводить програму з нотації однієї мови в нотацію машинної мови. Машинною мовою може бути або код конкретної машини, або об'єктний код. Перекладачі можуть бути інтерпретаторами, тобто поєднувати аналіз вихідної програми з її виконанням. Результатом роботи інтерпретатора є не машинний код, а послідовність звернень до бібліотеки функцій інтерпретатора. Інтерпретатор, на відміну від транслятора, може вибирати одну за одною інструкції і відразу їх виконувати. При інтерпретації (на відміну від трансляції або компіляції), може бути розпочато виконання програми яка має синтаксичні помилки.


Крос-транслятори. Якщо розглядати системи трансляції, то є ще один вид трансляторів - крос-транслятори (і крос-компілятори). Крос транслятор працює на деякому типі обчислювальної системи, яка називається інструментальна ЕОМ. Інструментальна ЕОМ може характеризуватися своєю архітектурою та / або операційним оточенням, яке функціонує на ній. Крос-транслятор забезпечує переклад програми, записаної в нотації деякої мови, в код обчислювальної системи, відмінної від інструментальної ЕОМ. Та обчислювальна система, для якої генерується код, називається об'єктної ЕОМ, і відповідно, той код, який ми отримуємо, називається об'єктним кодом (це не теж, що об'єктний модуль). Наприклад, комп'ютеру, який управляє руховою установкою літака, зовсім не потрібно мати операційну середу, яка забезпечить роботу користувача з розробки програм для нього. Йому абсолютно не потрібно мати засоби редагування тексту, трансляції і т.д., тому що в нього одна функція - управляти руховою установкою. На цьому комп'ютері буде працювати операційна система реального часу. Для створення програм для такого роду комп'ютерів і використовуються системи крос-програмування та крос-транслятори. На звичайній машині типу PC може бути розміщений транслятор, який буде генерувати код для заданого комп'ютера.

Насправді, бувають ситуації, коли тип об'єктної машини збігається з типом інструментальної машини, але відрізняються операційні середовища, які функціонують на даних машинах. У цьому випадку також потрібна система крос-програмування.

Крос-транслятори також потрібні розробникам нових машин, які хочуть паралельно з її появою створити програмне забезпечення, яке буде працювати на цій машині.


Обробка модульної програми. З точки зору етапу кодування можна розглянути послідовність обробки програми більш великоблочному, ніж з точки зору трансляції. Ми з вами говорили на початкових лекціях про те що сучасні мови програмування підтримують модульність (програма представляється у вигляді групи модулів і взаємозв'язок між цими модулями здійснюється за рахунок відповідних оголошень в них). Давайте подивимося, що відбувається на етапі обробки програми, написаної на одному з модульних мов.

Нехай є деяка група модулів і є відповідні цим модулям тексти програм, на мовах, що використовуються для програмування. Мовними засобами визначено зв'язки між модулями.

Перший етап, який відбувається - це етап трансляції (або компіляції) кожного з модулів. Після трансляції модуля у вигляді вихідного тексту ми отримуємо об'єктний модуль - це є машинно-орієнтоване представлення програми, в якому присутні фрагменти програми у машинному коді, а також інформація про необхідні зовнішніх зв'язках (посилання на об'єкти в інших модулях). Інформація про необхідні зовнішніх зв'язках (крім інформації про місцезнаходження зовнішніх об'єктів) також включає в себе посилання на ті місця машинного коду, які намагаються використовувати адреси зовнішніх об'єктів, тобто на ті недообработанние команди, які не можна обробити через те, що при трансляції модуля ще не відомо де які об'єкти знаходяться. Тобто об'єктний модуль - це машинне подання програмного коду, в якому ще не дозволені зовнішні зв'язки. Об'єктний модуль може містити додаткову інформацію (наприклад, інформацію, необхідну для налагодження - таблиці імен і т.д.).

Для кожного з вихідних модулів ми отримаємо об'єктний модуль. Після цього всі об'єктні модулі, які складають нашу програму, а також модулі необхідних бібліотек функцій, надходять на вхід редактору зовнішніх зв'язків. Редактор зовнішніх зв'язків моделює розміщення об'єктних модулів в оперативній пам'яті і дозволяє всі зв'язки між ними. У результаті ми отримуємо виконуваний модуль, який може бути запущений як процес. Іноді транслятори як результат трансляції видають модуль на асемблері відповідної машини.

У цю ж схему також часто додається етап оптимізації програми, причому оптимізація може відбуватися до етапу трансляції (тобто в термінах вихідного мови) або / та після трансляції (в термінах машинного коду). Наприклад до трансляції можна обчислити всі константні подвираженія і т.д. Для машин типу PC етап оптимізації може бути не настільки важливий, тому що це питання зазвичай дозволяється покупкою якого-небудь більш швидкого компонента, але є клас машин (mainframe), для яких цей етап необхідний.


Давайте подивимося на проблему кодування з іншого боку. Ми подивимося як влаштований етап трансляції.

Кожен транслятор при обробці програми виконує наступні дії.

  1. Лексичний аналіз.

  2. Синтаксичний аналіз.

  3. Семантичний аналіз та генерація коду.


Лексичний аналіз. Лексичний аналізатор робить аналіз вихідного тексту на предмет правильності запису лексичних одиниць вхідної мови. Потім він переводить програму з нотації вихідного тексту в нотацію лексем.

Лексичні одиниці - це мінімальні конструкції, які можуть бути продекларовані мовою. До лексичним одиницям відносяться:

  • ідентифікатори

  • ключові слова

  • код операції

  • роздільники

  • константи


Речові константи в деяких трансляторах можуть представлятися у вигляді групи лексичних одиниць, кожна з яких є целочисленной константою.

Після цього вихідна програма переводиться в вид лексем. Лексема - це деяка конструкція, що містить два значення - тип лексеми і номер лексеми.


Тип лексеми № лексеми

Тип лексеми - це код, який говорить про те, що дана лексема належить одній з позначених нами груп. наприклад лексема може бути ключовим словом, тоді в поле типу буде стояти відповідний номер. Номер лексеми уточнює конкретне значення цієї лексеми. Якщо, приміром, було ключове слово begin, то номер лексеми буде містити число, відповідне ключовим словом begin. Якщо тип лексеми - ідентифікатор, то номер лексеми буде номером ідентифікатора в таблиці імен яку створить лексичний аналізатор. Якщо тип лексеми - константа, то номер лексеми теж буде посиланням на таблицю з константами.

Після лексичного аналізатора ми отримуємо компактну програму, в якій немає вже нічого зайвого (прогалин, коментарів, і т.д.). Вся програма складена у вигляді таких лексем, і тому вона більш компактна і проста.


Синтаксичний аналіз. Програма у вигляді лексем надходить на вхід синтаксичному аналізатору, який здійснює перевірку програми на предмет правильності з точки зору синтаксичних правил. Результатом роботи синтаксичного аналізатора є яка інформація про те, що в програмі є синтаксичні помилки і вказівка ​​координат цих помилок і їх діагностика, або подання програми в деякому проміжному вигляді. Цим проміжним виглядом може бути, припустимо, бесскобочная запис, або запис у вигляді дерев (хоча одне однозначно зводиться до іншого). Це проміжне представлення, яке є синтаксично і лексично правильною програмою, надходить на вхід семантичному аналізатору.


Семантичний аналіз. Семантика - це все те, що не описується синтаксисом і лексикою мови. Приміром, лексикою і синтаксисом мови складно описати те, що недобре передавати управління в тіло циклу не через початок циклу. Виявлення таких помилок - одна з функцій семантичного аналізу. при цьому семантичний аналізатор ставить у відповідність синтаксично і семантично правильним конструкціям об'єктний код, тобто відбувається генерація коду.


Система програмування і трансляції - дуже наукомістка область програмного забезпечення. Організація трансляторів - це було перше застосування теоретичних досягнень науки, які полягали в наступному. За рахунок можливості використання тих чи інших граматик (наборів формальних правил побудови лексичних конструкцій і синтаксичних правил), можна розділити програмну реалізацію лексичних і синтаксичних аналізаторів на два компоненти. Перший компонент - це програма, яка в загальному випадку нічого не знає про те мовою, який вона буде аналізувати. Другий компонент - це набір даних, що вдає із себе формальний опис властивостей мови, який ми аналізуємо. Поєднання цих двох компонентів, дозволяє автоматизувати процес побудови лексичних і синтаксичних аналізаторів, а також генераторів коду, для різних мов програмування. Сучасні системи програмування в своєму складі мають засоби автоматизації побудови компіляторів. Для ОС UNIX є пакет LEX - пакет генерації лексичних аналізаторів, і є пакет YACC - для генерації синтаксичних аналізаторів. Це все досягається за рахунок можливості формалізації властивостей мови, і використання цього формального опису, як параметрів для тих чи інших інструментальних засобів.

Проходи трансляторів. Ми з вами подивилися на транслятор з точки зору функціональних етапів. Але дуже часто ми чуємо про однопрохідних трансляторах, двопрохідний, трехпроходних, і т.д. З проблемою трансляції пов'язане поняття "прохід". Прохід - це повний перегляд деякого уявлення вихідного тексту програми.

Є транслятори однопрохідні. Це означає, що транслятор переглядає вихідний текст від початку і до кінця, і до кінця перегляду (в разі правильності програми) він отримує об'єктний модуль.

Якщо ми подивимося Сі-компілятор, з яким ви працюєте, то швидше за все він двопрохідний. Перший прохід - це робота препроцесора. Після першого проходу з'являється чистий Сі-програма без всяких препроцесорну команд. На Другому проході відбувається лексичний, синтаксичний і семантичний аналіз, і в підсумку ви отримуєте об'єктну програму у вигляді асемблера.

Кількість проходів у деяких трансляторах пов'язано з кількістю етапів, тобто бувають реалізації, для яких зручно зробити окремий прохід для лексичного аналізу, окремий прохід для синтаксичного аналізу та окремий прохід для семантичного аналізу. Якщо транслятор багатопрохідний, то виникає проблема збереження проміжної нотації програми між проходами.

Make-файл. До цієї ж проблеми кодування відноситься засіб підтримки розробки програмних проектів. Одним з популярних засобів, орієнтованих на роботу одного або декількох програмістів, є т.зв. make-засіб. Назва походить від відповідної команди ОС UNIX. C make-командою пов'язаний т.зв. make-файл, в якому підрядник вказуються взаємозв'язку всіляких файлів, одержуваних при трансляції, редагуванні зв'язків, і т.д., і ті дії, які треба виконати, якщо ці взаємозв'язки порушуються. Зокрема можна сказати, що деякий виконуваний файл залежить від групи об'єктних файлів, і якщо цей зв'язок порушена, то треба виконати команду редагування зв'язків (link ...). Що значить порушення залежності і що значить зв'язок? Make-команда перевіряє існування цих об'єктних файлів. Якщо вони існують, то часи їх створення мають бути більш ранні, ніж час створення виконуваного файлу. У тому випадку, якщо це правило буде порушено (а це перевіряє make-команда), то буде запущений редактор зв'язків (link), який наново створить виконуваний файл. Тим самим такий засіб дозволяє нам працювати з програмою, що складається з великої кількості модулів, і не піклуватися про те, чи відповідає в даний момент часу виконуваний файл набору об'єктних файлів або не відповідає (можна просто запустити make-файл).

Make-файли можуть містити велику кількість такого роду рядків, які таким чином зв'яжуть не тільки об'єктні і виконувані файли, а й кожен з вихідних файлів з відповідним об'єктним файлом, і т.д. Тобто суть така, що після роботи не треба щоразу для кожного файлу запускати компілятор, редактор зв'язків, а можна просто запустити make-файл, а він уже сам визначить і вибере ті файли, які потрібно коригувати, і виконає необхідні дії. Насправді такими коштами зараз володіють майже всі системи програмування.

Система контролю версій. Якщо make-файл - це система, призначена для одного програміста, в кращому разі, для декількох програмістів, то якщо у нас існує великий колектив, який робить великий програмний проект, то використовується т.зв. система контролю версій, яка дозволяє організовувати коректну роботу великих колективів людей над одним і тим же проектом, яка заснована на можливості декларації версій і здійсненні контролю за цими версіями.


Етапи тестування і налагодження

Тестування - це пошук ситуації, в якій програмний продукт не працює. При цьому використовуються набори тестів, що визначають зовнішню навантаження на програмний продукт. Можна сказати, що програма відтестовано на певному наборі тестів. Твердження, що програма відтестовано взагалі в загальному випадку некоректно.

Налагодження - це процес пошуку, локалізації та виправлення помилки. Налагодження здійснюється, коли ми маємо програмну систему, і знаємо, що вона не працює на якомусь з тестів.

Проблеми тестування і налагодження - це є проблеми крайньої важливості. За оцінками, на тестування і налагодження витрачається близько 30% часу розробки проекту. Складність тестування і налагодження залежить від якості проектування і кодування. Тестування найчастіше виконати складно і часто для тестування використовуються модельні навантаження, наприклад ми тестуємо бортову мережу літака, щось ми зможемо зробити на землі, а що-то так чи інакше робиться вже на реальному польоті, коли збираються дані і фіксується працює система або не працює.

Лекція № 21


Тема, яку ми з вами почнемо розглядати буде короткою і простий, і ми позначимо основні больові точки. Деталі й подробиці ви повинні вивчити самі.


Командний мова ОС UNIX CSHELL (CSH)


Для багатьох користувачів програмного забезпечення основним і єдиним властивістю, на яке звертає увагу користувач, є не внутрішній устрій системи, а той інтерфейс, який надається системою користувачеві. Майже кожна система має засоби інтерактивної взаємодії з користувачем, тобто кошти, які дозволяють в тій чи іншій формі вводити запити на виконання дій. З цієї точки зору UNIX підтримує можливість роботи з довільною кількістю інтерпретаторів команд. У файлі / etc / passwd / одне з полів, що відносяться до даного користувачеві, містить повне ім'я інтерпретатора команд, який повинен бути запущений при вході користувача в систему. У загальному випадку, при вході користувача в систему може бути запущена абсолютно будь-яка програма.

Традиційними інтерпретаторами команд у системі UNIX є SH, CSH і BASH. Давайте розглянемо на концептуальному рівні що таке СSH (в принципі всі інтерпретатори команд схожі один на одного і є деяким розширенням SH).

Інтерпретатор команд визначає структуру введеної команди. Команда (для CSH) - це послідовність символів, що закінчується деяким кодом, і яка складається зі слів. Слова - це послідовності символів, що не містять роздільники. Роздільники - це набір фіксованих символів, зокрема звичним для нас роздільником є ​​пробіл. Крім пробілу роздільниками служать коми, знаки <>, і т.д. Кожен з цих роздільників має свою інтерпретацію. Зокрема, символ "|" означає створення конвеєра. Наприклад команда ls | more дозволить уникнути швидке виведення тексту на екран і за екран, і дозволить перегорнути його.

Система UNIX підтримує набір спеціальних символів, які називаються метасимволи. Метасимволи зазвичай зустрічаються в словах команди і інтерпретуються за наперед визначеними правилами. Метасимволів існує багато, зокрема серед них є знайомі нам * і?. Команда rm * видалить всі файли не починаються з точки в поточному каталозі.? Означає, що на місці цього символу може бути один будь-який знак. Метасимволи можуть бути парними. Наприклад всередині квадратних дужок вказується альтернативна група, припустимо, [abc] означає, що замість цієї квадратної дужки може бути один з перерахованих в ній символів (будь-яку цифру можна задати так [0-9]).


CSH дозволяє об'єднувати команди. Для цього також використовуються метасимволи. Якщо всередині круглих дужок перераховані деякі команди, то запуститься ще один інтерпретатор, який виконає цю послідовність команд. Наприклад команда (cd / etc; ls-la | grep pas) змінить каталог та здійснить пошук у цьому каталозі рядка pas.

У чому різниться між тим, виконалася чи ця команда в інтерпретаторі з яким ми працюємо, або якщо був запущений ще один інтерпретатор. Різниця в тому що, в цьому випадку не зміниться поточний каталог, незважаючи на те, що виконалася команда зміни каталогу.

Є можливість об'єднувати команди з використанням {}. Усі команди, перераховані в фігурних дужках будуть запущені зліва направо, але при цьому на стандартний висновок буде покладена об'єднана послідовність стандартних висновків всіх команд. {More tb; more tc}> tt.b - у файлі tt.b виявиться стандартний висновок однієї команди, а потім стандартний висновок інший, ця команда без фігурних дужок помістила б туди стандартний висновок тільки другої команди.


Інтерпретатор команд має набір вбудованих команд. Усі команди поділяються на два типи:

  1. Команди, які реалізовані у вигляді окремих файлів. Це ті команди, які можна модифікувати або додавати нові.

  2. Команди, які вбудовані в інтерпретатор команд, тобто ті команди, які виконує сам інтерпретатор. До таких командам стосується команда kill, за якою здійснюється передача відповідного сигналу від імені інтерпретатора. Є також корисна команда alias, яка використовується для перейменування існуючих команд.


Інтерпретатор команд CSH дозволяє здійснювати роботу з передісторією. Він може організувати буферизацію N останніх команд і організує доступ до списку останніх команд. Зокрема, можна виконувати і редагувати командні рядки зі списку передісторії і знову їх виконувати. CSH має можливість іменувати рядки зі списку передісторії. Посилання на відповідний рядок здійснюється за допомогою команди, яка починається з символу! , За яким слідує деяка суффіксная частина . Посилання!! Виконує останню команду. Посилання виду!! N, де N - деяке число, виконує рядок із с писку передісторії з номером N. Якщо N негативно, то номер рядка відлічується з кінця, наприклад,!! -1 Означає виконання останньої команди. Крім того, можуть бути деякі контекстні посилання виду! <...>.


Змінні CSH

Інтерпретатор команд надає можливість програмування на рівні CSH. Для цього передбачена декларація змінних і можливість присвоєння їм значення, а також набір високорівневих операторів, які за своєю семантикою схожі на оператори мови Сі (звідси і назва інтерпретатора C SH). CSH фактично є високорівнева мову з операторами мови Сі. Оперуючи з змінними CSH можна складати програми, які виконують деякі дії.

Крім усього іншого, є зумовлені імена, які відповідають за налаштування системи, зокрема, про те, скільки рядків передісторії зберігаються. Збереження відбувається в двох іпостасях: перше - це оперативне збереження, є параметр (змінна history), який визначає, скільки рядків має бути збережене протягом останнього сеансу роботи. Друге - є можливість збереження передісторії між сеансами, тобто при черговому вході систему вже буде визначений деякий список передісторії (розмір списку - у змінній savehistory).


Крім змінних, за допомогою яких здійснюється настроювання, і імена яких визначені, є ще один клас змінних CSH - це т.зв. внутрішні змінні, які також є зарезервованими. Це змінні, які мають визначені імена і визначають своє значення через внутрішні функції інтерпретатора команд. Зокрема, є змінна path, це є текстовий масив, в якому знаходяться текстові рядки, що містять повні імена деяких каталогів. Відповідно до вмістом змінної path, CSH здійснює пошук файлів, які є командами, введеними користувачами. Ми з вами говорили, що в UNIX (крім вбудованих команд) спеціальних команд немає, командою є будь-який виконуваний файл. Якщо користувач ввів деякий ім'я NAME, пошук виконуваного файлу з ім'ям NAME буде здійснюватися, по-перше, в поточному каталозі, а по-друге, в каталогах, зазначених у змінній path, у відповідному порядку.


Змінна home - містить ім'я домашнього каталогу.


Змінна ignoreeof - це змінна, установка якої блокує завершення сеансу роботи з уведення символу ^ D (Ctrl-D).

У системі можна варіювати вид запрошення (до введення) за допомогою змінної prompt, причому це запрошення може бути досить інтелектуальним. У ньому, наприклад, може бути присутнім дата і т.п.

Ми з вами розглянули змінну path, вона може визначати багато директорій. Уявіть собі, що я вводжу деяку командний рядок NAME і в поточному каталозі відповідного файлу немає. Це означає, що буде здійснено пошук файлу з ім'ям NAME по всіх каталогах, записаним у змінній path (З усіма витікаючими наслідками). Це може бути довго. А якщо ще врахувати, що ви працюєте в розрахованій на багато користувачів, і кожен постійно вводить якісь команди, то накладні витрати виходять божевільними. Система UNIX розумна система, і одним з правил, яких дотримувалися її розробники було те, що якщо десь щось можна оптимізувати, то треба це зробити. При вході користувача в систему на підставі значення змінної path формується hash-таблиця імен виконуваних файлів, що знаходяться у всіх перерахованих каталогах (природно, враховується порядок каталогів). Пошук команди (якщо вона не знайдена в поточному каталозі) буде полягати в перегляді цього швидкої hash-таблиці. За рахунок цього досягається прискорення доступу до команди, хоча при вході в систему можлива значна затримка, яка викликана формуванням цієї hash-таблиці.

Припустимо, ви увійшли до системи, а потім адміністратор додав команду, яка цьому користувачеві необхідна. Але за рахунок того, що hash-таблиця вже сформувалася, доступ до неї (без набору повного імені) закритий, хоча вона є в каталозі, зазначеному в path. У цьому випадку можна переформувати hash-таблицю за допомогою команди rehash.


Крім всіх цих змінних, CSH має ще одну категорію змінних, які називаються змінними оточення. Якщо ви згадаєте, то при запуску процесу функції main передаються кілька параметрів, серед яких є масив значень змінних оточення. У процес можна передати ті параметри, які характеризують сеанс роботи користувача в даний момент часу. Зокрема можна передати ім'я домашнього каталогу, ім'я поточного каталогу, ім'я терміналу, з якого викликаний даний процес і т.д.

CSH має можливість роботи із змінними оточення (можна їх переглядати, встановлювати і т.п.).


За допомогою засобів CSH можна складати програми. У цих програмах можуть фігурувати імена змінних CSH, які ми можемо інтерпретувати як імена файлів. Засобами CSH можна визначати ряд властивостей, пов'язаних з ім'ям, яке ми інтерпретуємо як ім'я файлу. Зокрема, є можливості перевірки, чи існує такий-то файл. Є можливість перевірки, чи є такий-то файл каталогом або не є. Є можливість перевірки всіх прав доступу. Є можливість визначення розміру файлу. І, нарешті, є можливість запуску файлу як команди. До речі, за допомогою цих коштів реалізовано безліч команд системи. Програми на CSH можна вводити порядково, в цьому випадку CSH грає роль транслятора-інтерпретатора, а можна програму на CSH записати в деякий файл і виконувати його як командний файл (Але все одно буде відбуватися процес інтерпретації).


Спеціальні файли

Будь-командна мова має набір т.зв. профайлів, чи стартових файлів. CSH має два різновиди цих файлів: це файли, які можуть виконуватися при старті CSH, і файли, які виконуються при завершенні роботи.

При старті CSH працює з двома файлами -. Cshrc і. Login. Файл. Cshrc - це командний файл, в якому користувач на свій розсуд може розміщувати довільну кількість команд на CSH, які будуть виконуватися відразу після запуску CSH (наприклад, в цьому файлі може перебувати команда тестування файлової системи і т.д.). Файл. Login запускається при вході користувача в систему. У цьому файлі також може знаходитися будь-яка послідовність команд, наприклад там може бути перевизначення імені команд, найбільш прийнятне для даного користувача (тому що Мнемоніка команд в UNIX досить важка, та і параметрів у кожної команди багато).

При завершенні роботи з CSH запускається файл з ім'ям. Logout в якому також може знаходитися деякий набір команд.

Є стандартний файл, який може утворитися в процесі роботи - це файл. History. Якщо у вас визначена можливість збереження історії, то як раз в цьому файлі буферизується передісторія вашої роботи.


Тепер підіб'ємо підсумок, і я нагадаю в чому ви повинні розібратися самі:

  1. CSH - як мова програмування. Типи змінних CSH. Програмування на CSH.

  2. Угоди, які визначає CSH при роботі з рядками. Розбиття командного рядка на слова. Інтерпретація метасимволів. Можливість посилання на командні рядки передісторії.

  3. Вбудовані команди CSH.

  4. Спеціальні змінні CSH: внутрішні змінні і змінні оточення.

  5. Спеціальні командні файли CSH.

Лекція № 22


Багатомашинні асоціації


Термінальні комплекси


Перші багатомашинні асоціації з'явилися на початку 60-х років і це було пов'язано з двома проблемами. Перша проблема - проблема забезпечення масового доступу до обчислювальних ресурсів деякої обчислювальної системи. Друге - поява завдань, які вимагали можливості залучення для їх вирішення більш ніж однієї обчислювальної системи. З точки зору інтелектуалізації багатомашинних асоціацій, першим типом багатомашинних комплексів був термінальний комплекс. Термінальний комплекс можна визначити як набір програмних і апаратних засобів, призначених для взаємодії користувачів з обчислювальною установкою, через телефонний або телеграфну мережу (або через будь-яку іншу середу, через яку можна забезпечити зв'язок).

Структуру термінального комплексу можна зобразити наступним чином:



Є обчислювальна система, є канал взаємодії із зовнішнім світом, до якого підключено пристрій, який називається мультиплексор. Це пристрій, який забезпечує взаємодію групи зовнішніх пристроїв з обчислювальною системою (ВС) через один канал введення / виводу. До каналів мультиплексора можуть бути підключені локальні термінали.

Крім того може бути підключено пристрій, який називається модемом. Модем дозволяє вийти в телефонний або телеграфну мережу, яка працює в аналоговому режимі, і передавати інформацію (модему, в іншій частині мережі). До модему підключається віддалений термінал. Модем перетворює дискретний сигнал, що надходить від ПС (або терміналу), в аналоговий сигнал, який вже можна передавати по мережі; і назад - аналоговий в дискретний.

Телефонна мережа складається з якогось набору телефонних станцій, і вона надає т.зв. комутований канал. Суть його полягає в тому, що при декількох дзвінках до одного й того ж абонента, раз від разу маршрути комутації (тобто набір проводів, за якими йде повідомлення) відрізняються один від одного, за рахунок того, що кожного разу вибираються вільні канали .

Може бути також багаторівневе мультиплексування. Замість віддаленого терміналу, підключається віддалений мультиплексор, і починаючи від нього може бути продовження цього ж рівня малюнків. Це означає, що ми, працюючи за терміналом другого (або третього, четвертого, і т.д.) рівня суттєво завантажуємо комутовану лінію.

Лінія зв'язку, яка пов'язує один віддалений термінал з комп'ютером, називається лінією зв'язку типу точка-крапка. Ця лінія може бути або орендованої (ми домовляємося з телефонними станціями і фіксуємо комутацію), або комутованій.

Канал може бути багатоточковим. При цьому на вході знаходиться віддалений мультиплексор. Багатоточкові канали також можуть бути або орендуються, або комутованими.


Типи каналів зв'язку:

  1. Симплексних канали - канали, по яких передача інформації ведеться в одному напрямку.

  2. Дуплексні канали - канали, які забезпечують одночасну передачу інформації у двох напрямках.

  3. Напівдуплексні канали - канали, які забезпечують передачу інформації у двох напрямках, але в кожний момент часу лише в одну сторону (подібно рації).


НД має комплекс програм, які забезпечують взаємодію користувачів через всю комунікаційне середовище, з НД В якості локальних і віддалених терміналів можуть бути присутніми як реальні термінальні пристрої, так і комп'ютери, які емулюють роботу терміналу.


Багатомашинні обчислювальні комплекси


Багатомашинні обчислювальні комплекси (ММВК) - це програмно апаратне об'єднання групи обчислювальних машин, в яких:

  1. На кожній з машин працює власна операційна система (ця ознака відрізняє ММВК від багатопроцесорного обчислювального комплексу).

  2. У ММВК є загальні фізичні ресурси (а отже є проблеми синхронізації доступу).


ММВК використовувалися як систем збору і обробки великих наборів даних, і для організації глобальних термінальних комплексів. ММВК з'явилися на початку 60-х і зараз продовжують успішно існувати. Одне з основних застосувань ММВК - це дублювання обчислювальної потужності, прикладом таких систем може служити будь-яка система управління важливими технологічними процесами.


Обчислювальні мережі


І термінальні комплекси, і ММВК можна вважати окремим випадком обчислювальних мереж, однак хронологія розвитку багатомашинних асоціацій була саме такою - спочатку з'явилися термінальні комплекси, потім ММВК, потім обчислювальні мережі.

Припустимо у нас є деяка група обчислювальних машин, які ми будемо називати абонентськими машинами (АМ). Є деяке утворення, що називається комутаційної середовищем. Комутаційна середовище включає канали передачі даних, що забезпечують взаємодію між машинами, спеціальні обчислювальні машини, які ми будемо називати комутаційними машинами. Абонентські машини можуть здійснювати взаємодію один з одним через комутаційну середу, в рамках якої використовуються канали передачі даних і комутаційні машини.

Існує ряд класичних різновидів мереж.

Мережа комутації каналів. Суть її полягає в тому, що якщо треба зв'язати АМ2 з АМ3, то відбувається з'єднання каналів і комутаційних машин між цими АМ. Це з'єднання буде існувати до кінця взаємодії АМ2 і АМ3. Гідність цієї мережі в тому, що швидкість взаємодії між машинами дорівнює швидкості самого повільного компонента мережі, що бере участь в зв'язку (це максимально можлива швидкість). Недолік у тому, що такий зв'язок може блокувати інші сполуки (у даному випадку АМ1 і АМ4 не зв'яжуться до кінця зв'язку між АМ2 і АМ3). Піти від цієї проблеми можна зажадавши від комутаційної середовища великої надмірності, тобто організувати додаткові (дублюючі) канали.

Мережа комутації повідомлень. Якщо комутація каналів - це комутація на час всього сеансу зв'язку, то комутація повідомлень - це зв'язок, при якій весь сеанс поділяється на передачу повідомлень (повідомлення - деяка, логічно завершена, порція даних), і комутація відбувається на період передачі повідомлення. У такій мережі на комунікаційні машини лягають великі навантаження, вони повинні мати можливість буферизації повідомлень у зв'язку з нерівномірною швидкістю передачі на різних ділянках мережі. Переваги - простота логічна і фізична, недоліки - зниження швидкості роботи в мережі, і втрати, пов'язані з буферизацией.

Мережа комутації пакетів. Сеанс розбивається на повідомлення, повідомлення розбиваються на порції даних однакового обсягу - пакети. По мережі переміщаються не повідомлення, а пакети. Тут діє принцип гарячої картоплі: основна дія комутаційної машини - як можна швидше позбутися від пакета, визначивши кому його далі можна перекинути .. Оскільки всі пакети однакового обсягу, не виникає проблем з буферизацією, тому що ми завжди можемо розрахувати необхідну буферну здатність комутаційних машин. Логічно відбувається досить швидке з'єднання, тому що мережа комутації пакетів практично не має ситуацій, коли якісь канали заблоковані. За рахунок того, що відбувається дроблення сеансу на пакети, є можливість оптимізації обробки помилок при передачі даних. Якщо ми отримуємо помилку в режимі комутації каналів, то треба повторювати весь сеанс, якщо в режимі комутації повідомлень, то треба повторювати повідомлення, тут же достатньо повторити передачу пакета, в якому виявлено помилку.



У реальних системах використовуються багаторівневі мережі, які в якихось режимах працюють в режимі комутації каналів, в якихось режимах працюють в режимі комутації повідомлень і т.д. На сьогоднішній день можна сказати, що мереж, що належать суто до одного з перерахованих вище типів, немає.


Стандарт ISO / OSI


Розвиток багатомашинних асоціацій взагалі, і мереж ЕОМ зокрема, визначило виникнення необхідності стандартизації взаємодії, що відбувається в мережі. Тому наприкінці 70-х початку 80-х років ISO (International Standard Organization) запропонувала т.зв. стандарт взаємодії відкритих систем ISO / OSI (Open System Interface).

Була запропонована семирівнева модель організації взаємодії комп'ютерів із середовищем передачі даних, з програмами, що функціонують на різних комп'ютерах, і в загальному випадку організація взаємодії в мережі. Пропонувалися до розгляду сім рівнів взаємодії:

VII Прикладний рівень
VI Представницький рівень
V Сеансовий рівень
IV Транспортний рівень
III Мережевий рівень
II Канальний рівень
I Фізичний рівень
Фізичний рівень або рівень сполучення з фізичним каналом. На цьому рівні вирішуються самі земні питання організації взаємозв'язку: це питання рівнів і типів сигналів, і т.д. Цей рівень визначає конкретну фізичну середу. Припустимо, фізичної середовищем може бути середовище, яке називається "вита пара", або середовище, яка називається "коаксіальний кабель", або середовищем може бути оптоволокно, і т.д. Кожна з цих фізичних середовищ визначає свої правила спілкування через них.

  • Канальний рівень. На цьому рівні формалізуються правила передачі даних через канал. Якщо фізичний рівень пов'язаний безпосередньо з середовищем (з каналом), то канальний рівень пов'язаний з передачею інформації з цього каналу.

  • Мережевий рівень. Цей рівень управляє зв'язком у мережі між машинами. Тут вирішується питання адресації і маршрутизації даних.

  • Транспортний рівень. Цей рівень іноді називають рівнем логічного каналу. На цьому рівні вирішуються проблеми управління передачею даних, і пов'язані з цими проблемами завдання - локалізація і обробка помилок і безпосередньо сервіс передачі даних.

  • Сеансовий рівень забезпечує взаємодію програм (зрозуміло, що машини самі по собі не взаємодіють, а взаємодіють програми). При цьому вирішуються проблеми синхронізації обміну даних, скасування сеансу в результаті фатального результату, підтвердження паролів.

  • Представницький рівень. На цьому рівні вирішується проблема з поданням даних. Зрозуміло, що різні системи мають різні форми представлення даних.

  • Прикладний рівень. На прикладному рівні вирішуються проблеми стандартизації взаємодії з прикладними системами.


    Отже, була запропонована така семирівнева модель, і було запропоновано використовувати цю модель у двох якостях: стандартизація взаємодії в мережі (розробка стандартів) і застосування цієї модель для практичних рішень. Стандарти на фізичний рівень вже розроблені, розробляються стандарти на канальний рівень. На жаль, реальні мережі не відповідають такий семиуровневой моделі, хоча іноді можна знайти деяку відповідність.

    Вважається, що на кожній з ЗС, що функціонують в мережі, існує набір рівнів мережної взаємодії, відповідний такий семиуровневой моделі. При цьому вважається, що гарантовано в мережі існують поспіль йдуть рівні знизу вгору. Тобто якщо є сеансовий рівень, то гарантовано є всі нижчестоящі.

    У нас є дві машини, на кожній з яких реалізована ця семирівнева модель. Система взаємодії передбачає таку взаємодію між машинами, при якому кожен рівень спілкується з собі подібним рівнем. Правило взаємодії систем на однойменних рівнях, називається протоколом передачі даних. При цьому однойменні рівні реально безпосередньо один з одним оперувати не можуть. Вони оперують один з одним через нижчі рівні і фізичне середовище. Будь-який рівень нашої моделі може безпосередньо взаємодіяти тільки із сусіднім рівнем (або сусіднім зверху, або знизу). Правила взаємодії між рівнями називаються інтерфейсом. Якщо один рівень звертається до іншого (в іншій машині) через протокол передачі даних, насправді відбувається звернення через відповідну послідовність інтерфейсів до нижчим рівнями, далі відбувається передача через фізичне середовище, і потім відбувається послідовна передача від нижчестоящого рівня до потрібного.

    Сутність стандартизації полягає в тому, що після прийняття стандарту цих рівнів, можна вже міняти реалізації рівнів або додавати нові рівні, не турбуючись про інтерфейси і протоколах. Стандартизація визначає сумісність.


    Трохи про Інтернет


    Ми з вами поговоримо трохи про Інтернет, але не з точки зору того, що нам говорять по телевізору, причому часто говорять речі відверто дурні, а з точки зору її пристрою.

    Кілька слів передісторії. В кінці 60-х років американське агентство перспективних досліджень в обороні DARPA ухвалило рішення про створення експериментальної мережі з назвою ARPANet. Основною властивістю цієї мережі було те, що передбачалося відсутність будь-якої централізації. Цей проект почав розвиватися. У 70-му році ARPANet стала вважатися діючою мережею США, і зокрема, через цю мережу можна було добиратися до провідних університетських і наукових центрів США. На початку 80-х років почалася стандартизація мов програмування, а потім протоколів взаємодії мереж. Тут є два моменти, що вплинули на появу Інтернет. Перший - це сам факт стандартизації. Друге - поява моделі ISO / OSI. Етогт момент можна вважати початком появи Інтернету.

    Лекція № 23


    Ми почали обговорювати проблеми організації Інтернет і позначили основна якість цієї системи, закладене спочатку - що ця мережа абсолютна симетрична з тієї точки зору, що вона не мала на увазі будь-якої централізації та ієрархії. Це властивість, яке лягло в основу мережі, і створило той бум, який спостерігається зараз, тобто Інтернет може вільно розширюватися.

    Ми з вами розглянули коротко передісторію мережі. Спочатку мережу мала на увазі суто експериментальну роботу і вже в подальшому отримала університетську поширеність, комерція ж прийшла в Інтернет десь у 1994-95 роках.

    Інтернет заснований на протоколах TCP / IP (Transfer Control Protocol / Internet Protocol). Іноді кажуть: "протокол TCP / IP" - але це неправильно, тому що під цією абревіатурою ховається цілий набір протоколів, об'єднаних під однією назвою. До речі, тут є окремо протокол TCP і окремо протокол IP.

    Сімейство TCP / IP будується за чотирирівневої схемою. Розглянемо таблицю відповідності TCP / IP моделі ISO / OSI:


    Рівні TCP / IP

    Рівні ISO / OSI

    I. Прикладних програм
    1. Прикладних програм

    2. Представлення даних

    II. Транспортний
    1. Сеансовий

    2. Транспортний

    III. Міжмережевий
    1. Мережевий

    IV. Доступу до мережі
    1. Канальний

    2. Фізичний


    Рівень доступу до мережі TCP / IP забезпечують апаратні інтерфейси і драйвери цих апаратних інтерфейсів. Приміром, протоколами рівня доступу до мережі є протоколи Ethernet. Їх суть в наступному.

    Ethernet - це система, що забезпечує електроенергією "миттєвий" доступ з "контролем несучої" і виявленням зіткнень. Ethernet - широкомовна мережу, це означає, що будь-яке повідомлення, що виходить з джерела стає видимим всім іншим Ethernet-пристроїв. Ethernet симетрична (немає ніякого фізичного верховенства), вона припускає наявність деякої фізичної середовища (різновиди коаксіального кабелю, кабель "вита пара", СВЧ діапазон та ін), Ethernet-пристрою, який здійснює взаємодію в рамках даного середовища. Так як мережа симетрична, то виникає проблема зіткнення пакетів передаються даних, тобто, коли одночасно надсилаються два пакети даних з різних пристроїв - у цьому випадку відбувається відмову передачі даних в обох пристроїв, після цього вони завмирають на деякий час, а потім роблять ще одну спробу. Це нагадує розмову ввічливих людей в темній кімнаті: якщо одна людина говорить, то інші мовчать; коли, дві людини, починають говорити, то обидва одночасно замовкають і роблять паузу.

    Наступне властивість Ethernet полягає в тому, що кожне з Ethernet-пристроїв має унікальну адресу, ця адреса присвоюється йому при виготовленні. Існує ряд міжнародних правил, які створюють неможливою появу в світі двох Ethernet-пристроїв з однаковим номером, будь-то вже згорілі пристрою або ще перебувають у строю. Ця адреса можна порівняти зі штрих-кодом, який зустрічається на різних продуктах.

    Ще одна властивість Інтернет - широкомовно. Реально, будь-яке повідомлення, надіслане в мережу, проходить через всі Ethernet-пристрої мережі. Відповідно всі повідомлення мають адресацію, і повідомлення можуть надсилатися всіх пристроїв, або якогось окремого, але в будь-якому випадку - повідомлення пройде через всі пристрої, а вже кожне з них сама вирішить - залишити його чи ні.

    Ось у кількох словах про приклад четвертого рівня доступу протоколів TCP / IP, це найбільш поширений варіант. Можна сказати про те, що така мережа проста, але має ряд недоліків, що полягають в тому, що коли в мережі виникає багато активних користувачів, то частішають зіткнення повідомлень і пропускна здатність істотно знижується.

    Слід звернути увагу, що коли ми говоримо Інтернет - мережа, то це також вірно, як і те, що TCP / IP - протокол. Тобто Інтернет - це об'єднання мереж.

    З цієї точки зору можна виділити два види комп'ютерів, які можна виділити в мережі:

    Це хост-комп'ютери (host) і шлюзи (gate). У двох словах покажемо, що є що. Реально, кожний з комп'ютерів, який працює в мережі, може класифікуватися за двома ознаками. Якщо в комп'ютері розташована тільки одна мережна карта або інтерфейс, то це хост-комп'ютер і зазвичай він належить який-небудь однієї мережі. Якщо в комп'ютері знаходяться дві і більше мережевих карт, при цьому кожна з карт підключається до своєї мережі, то такий комп'ютер називається комп'ютером-шлюзом. Відповідно, через шлюзи можна поєднувати мережі.


    Тобто, якщо дивитися з точки зору приналежності до мереж - хост належить одній мережі, а шлюз належить одразу двом або більше мереж. Через шлюзи здійснюється взаємодія між комп'ютерами в різних мережах. І цей механізм об'єднання і доступу є однією з відмінних рис Інтернету, яка базується на межсетевом рівні TCP / IP, який в свою чергу базується на протоколі IP.

    Основна функція протоколу IP - унікальна міжмережний адресація. Одним з основних властивостей або якостей IP-протоколу є IP-адресу. Це адреса, який приписується як конкретної мережі, так і конкретного комп'ютера в мережі. Виходячи з цього, ми можемо сказати, що шлюз - це комп'ютер, що має два або більше IP-адреси (адреса в одній мережі і в іншій мережі), хост - комп'ютер, який має один IP-адресу. Також, у функції IP входить маршрутизація, то є вибір шляху, по якому будуть передаватися повідомлення, визначення базових блоків даних (вони називаються дейтаграми), які передаються, і взаємодія з транспортним рівнем і рівнем доступу до мережі. Відповідно, у зв'язку з цією взаємодією можлива фрагментація і дефрагментація дейтаграм.

    Два слова про IP-адресації. IP-адреса - це чотирьохбайтові код, в якому може розміщуватись інформація про адресу мережі і про адресу комп'ютера в мережі. Існує кілька категорій IP-адрес:


    Клас А.

    0



    1 байт 2 байт 3 байт 4 байт

    Перший байт кодує номер мережі, при цьому його старший біт є нульовим (це ознака класу А), інші біти визначають номер мережі. Мереж класу А може бути 126 штук. Відповідно, останні три байти - номер комп'ютера в мережі. Мережі класу А - гігантські мережі, які можуть належати найбільшим корпораціям.

    Клас B.

    1 0



    1 байт 2 байт 3 байт 4 байт

    Ознака класу B - старші два біти рівні "10". Для нумерації мережі використовується залишок першого і цілком другий байт. 3 і 4 байти - номер комп'ютера в мережі. Це також великі мережі, їх може бути велика кількість, але також обмежене.


    Клас C.

    1 1 0



    1 байт 2 байт 3 байт 4 байт

    Ознака класу C - старші три біти рівні "110". Для нумерації мережі використовуються: залишок першого байта, другий і третій байти цілком. Номер комп'ютера визначається четвертим байтом. Відповідно, клас C представляє гігантську кількість невеликих мереж.


    Є ще два класи - D і Е, але вони досить специфічні, і ми не будемо про них говорити.


    Існує міжнародна організація, яка розподіляє номери мереж. Тут діє певна ієрархія. Організація, що отримала номер мережі може розподіляти номери комп'ютерів в межах цієї мережі на власний розсуд.

    Слід зазначити, що, незважаючи на величезну кількість адрес, яке можна представити чотирма байтами, існує проблема їх вузькості, і йдуть розмови про розширення IP адресації. Це колосальна проблема, яку можна порівняти хіба що з проблемою 2000 року.

    На межсетевом рівні окрім протоколу IP існує ще група допоміжних протоколів. Частина з них залежить від того, чим ми будемо користуватися і що ми будемо робити. У будь-якому випадку - основа для них - протокол IP.


    Наступні протоколи - транспортні. Тут є два типи протоколів - UDP (User Datagram Protocol) і TCP.

    Протокол TCP забезпечує передачу даних з контролем і виправленням помилок. Крім того, TCP гарантує логічне з'єднання. Тобто TCP дозволяє створювати логічні канали, гарантуючи відправку і прийом порцій даних у певному порядку. Протокол жорсткий, так як контролює помилки. Але за все треба платити, і TCP є ресурсоємним протоколом.

    Протокол UDP - це швидка доставка повідомлень без здійснення контролю доставки. Протокол TCP більше розрахований на використання в Інтернеті (для передачі на дальні відстані, де не може гарантуватися безпомилковість передачі). UDP орієнтований на роботу в локальній мережі, де гарантований певний рівень якості передачі даних. Протоколи транспортного рівня спілкуються з прикладними протоколами і міжмережевих протоколами.


    Далі йде рівень прикладних систем. TCP / IP має тим властивістю, що в сімействі цих протоколів стандартизовані протоколи, на яких базуються прикладні системи. Зокрема, FTP (File Transfer Protocol). Реально система FTP присутня в кожній операційній системі і в кожній набір FTP систем може бути значним. Але за рахунок того, що є стандарт FTP, всі ці програми працюють однаково. Є мережевий продукт Telnet - мережева емуляція алфавітно-цифрового термінала.

    Тобто в системі стандартизовані протоколи за допомогою яких організовані прикладні системи. І ми можемо будувати свої додатки FTP або Telnet з наданих цеглинок.

    Різні прикладні системи спілкуються з різними протоколами - хто-то з UDP, хтось з TCP. FTP і Telnet, наприклад, працюють через TCP, а мережева файлова система NFS, яка дозволяє об'єднувати файлові системи різних машин в одну (і бачити їх, як свою локальну), грунтується на UDP, тому що NFS працює в рамках локальної мережі.


    От і все, що можна було сказати про багатомашинних асоціаціях, протоколах і за курсом в цілому.

  • Додати в блог або на сайт

    Цей текст може містити помилки.

    Програмування, комп'ютери, інформатика і кібернетика | Реферат
    168кб. | скачати

    © Усі права захищені
    написати до нас