- •Міністерство освіти і науки України
- •Жуковецька с.Л., Шестопалов с.В.
- •Анотація
- •Введення
- •Лабораторна робота №1 Технологія розробки програм у середовищі Linux
- •1. Команди роботи з командним інтерпретатором ос unix
- •2. Створення програми
- •3. Функції введення-виведення.
- •4. Приклад програми
- •5. Основні керуючі конструкції мови с
- •6. Індівідуальні завдання
- •Лабораторна робота № 2. Автоматизація пакетних завдань
- •1. Компіляція багатомодульною програми
- •2. Автоматизація пакетних завдань
- •4. Завдання
- •Лабораторна робота № 3. Взаємодія програми з середовищем виконання
- •1. Аргументи командного рядка
- •2. Змінні оточення
- •3. Індівідуальні завдання
- •Лабораторна робота №4. Контроль виконання програми
- •1. Коди завершення програми
- •2. Функції обробки значення errno
- •3. Функція atexit()
- •4. Макрос asssert()
- •5. Індівідуальні завдання
- •Лабораторна робота №5 Файлові api.
- •1 Основні поняття
- •2. Права доступу до файлів
- •3. Інтерфейси для файлового введення / виводу
- •4. Системні виклики роботи з файлами
- •5. Індівідуальні завдання
- •Варіанти завдань
- •Лабораторна робота №6 Робота з каталогами та посиланнями
- •Методичні вказівки
- •1. Створення та видалення каталогу
- •2. Читання каталогу
- •3. Зміна каталогу
- •4. Управління жорсткими посиланнями
- •5. Управління символічними посиланнями
- •6. Перейменування файлів і каталогів
- •7. Індівідуальні завдання
- •Лабораторна робота №7. Одержання і відображення метаданих файлу.
- •Методичні вказівки
- •1. Механізми управління файлами ос unix
- •2. Отримання даних індексного дескриптору
- •3. Додаткові функції маніпулювання даними індексних дескрипторів
- •4. Отримання даних про відкриті файли
- •5. Індівідуальні завдання
- •Лабораторна робота №8. Керування процесами
- •Методичні вказівки
- •1. Загальні поняття
- •2. Створення поцесу
- •4. Перезавантаження програми процесу
- •5. Завершення виконання процесу
- •6. Системні виклики wait, waitpid
- •7. Індівідуальні завдання
- •Лабораторна робота №9. Використання каналів
- •Методичні вказівки
- •1. Заганьні відомості
- •2. Використання каналів
- •3. Індівідуальні завдання
- •Варіанти завдань
- •Лабораторна робота №10 Використання повідомлень
- •Методичні вказівки
- •1. Загальні відомості
- •2. Використання повідомлень
- •3. Індівідуальні завдання
- •Література
- •Системне програмування Посібник до виконання лабораторних та самостійних робіт
- •65082, Одеса, вул. Дворянська, 1/3
2. Використання каналів
Канал - це засіб зв'язку стандартного висновку одного процесу зі стандартним уведенням іншого. Канали - це найстарший з інструментів IPC, що існує приблизно із часу появи самих ранніх версій оперативної системи UNIX. Вони надають метод однобічних комунікацій (звідси термін half-duplex) між процесами.
Коли процес створює канал, ядро встановлює два файлових дескриптори для користування цим каналом. Один такий дескриптор використовується, щоб відкрити шлях уведення в канал (запис), у той час як іншої застосовується для одержання даних з каналу (читання). Якщо процес посилає дані через канал (fd0), він має можливість одержати цю інформацію з fd1. процес, що створює канал, звичайно породжує дочірній процес. Як тільки дочірній процес успадкує який-небудь відкритий файловий дескриптор від батька, ми одержуємо базу для мультипроцессовой комунікації (між батьком і нащадком). Конструкція каналу виглядає в такий спосіб
in <----- in
Parent Process Kernel Child Process
out <----- out
Рисунок 4 – Конструкція каналу
Створення каналів виконується з використанням функції
#include <unistd.h> int pipe(int *filedes);
Функція повертає два дескриптори:
filedes[0] - для запису;
filedes[1] - для читання.
Обмін інформацією виконується з використання функцій запису й читання API. Канали використовуються для родинних процесів.
Незалежні процеси можуть використовувати іменовані канали. Такі канали створюються функцією.
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t, dev_t dev);
Перший параметр специфицирует ім'я створюваного каналу, параметр mode задає права доступу й тип (для іменованого каналу використовується значення S_IFIFO). Третій параметр ігнорується. Функція повертає ознаку нормального завершення - 0, при помилці вертається значення -1.
Знищення каналу виконується по функції
int unlink(const char *pathname)
Наступний приклад ілюструє передачу короткого повідомлення між родительски й дочірнім процесом.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
int main() {
pid_t childPid;
int flds[2], status;
char buf[]="Message";
// Створення каналу
if (pipe(flds) == -1)
{ perror("Pipe"); exit(1); }
// Розгалуження процесів
switch (childPid=fork())
{ case -1: perror("fork");
exit(2);
case 0:
close(flds[0]);
//Нащадок
printf("Child process %d\n", getpid()); write(flds[1], buf,
strlen(buf));
close(flds[1]); exit(0); }
// Процес - батько
printf("Process %d\n", getpid());
close(flds[1]);
read(flds[0], buf, 80);
printf("String -> %s\n", buf);
close(flds[0]);
wait(&status);
return status;
}
На початку програми створюється канал і формуються два ідентифікатори файлів для цього каналу (flds[0] і flds[1]). Будемо вважати, що в батьківського процесу flds[0] використовується для прийому даних, тому на початку секції батьківського процесу необхідно закрити канал, пов'язаний з файловим ідентифікатором flds[1]. У породженому процесі закривається канал з ідентифікатором flds[0].
Наступний приклад ілюструє обмін даними між двома незалежними процесами через іменований канал.
Перша програма служить сервером, вона створює іменований канал по функції
mkfifo(NAME, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO).
Як перший параметр використовується рядок, певна константою NAME. Другий параметр являє собою комбінацію ключів, що визначають дозвіл повних прав доступу для всіх категорій користувачів. Після створення каналу на стороні сервера він відкривається в режимі читання. Після приходу повідомлення, текст цього повідомлення виводиться на екран і канал закривається. Наприкінці програми функцією unlink(NAME) канал знищується. Відкриття й знищення каналу виконуються з використанням того самого ім'я (константа NAME зі значенням "sfifo.cc").
/* Сервер. Створює FIFO і очікує повідомлення */
#include <iostream.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define NAME "sfifo.cc"
int main() {
int fd;
char buf[80];
unlink(NAME);
if(mkfifo(NAME, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO)) {
perror("Помилка FIFO");
return 1; }
if((fd=open(NAME, O_RDONLY))==-1) {
perror("Помилка відкриття файлу сервера"); }
read(fd, buf, sizeof(buf));
cout<<"Отримано->"<<buf<<endl; close(fd);
unlink(NAME);
return 0;
}
Програма - клієнт виводить на екран текст запиту на уведення повідомлення й після уведення рядка відкриває канал на запис. Після передачі вмісту буфера в канал, останній закривається.
/* Клієнт */
#include <iostream.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#define NAME "sfifo.cc"
int main() {
char text[80];
int fd;
cout<<"Увести ссобщение"<<endl;
cin>>text;
if((fd=open(NAME, O_WRONLY))==-1) {
perror("Помилка відкриття клієнта");
return 1; }
write(fd, text, strlen(text)); close(fd); return 0;
}