Московский физико-технический институт
Опубликован: 16.09.2004 | Доступ: свободный | Студентов: 7876 / 1661 | Оценка: 4.44 / 4.28 | Длительность: 15:33:00
Лекция 3:

Организация взаимодействия процессов через pipe и FIFO в UNIX

< Лекция 2 || Лекция 3: 123456 || Лекция 4 >

Системные вызовы read(), write(), close()

Для совершения потоковых операций чтения информации из файла и ее записи в файл применяются системные вызовы read() и write() .

Системные вызовы read и write

Прототипы системных вызовов

#include <sys/types.h>
#include <unistd.h>
size_t read(int fd, void *addr, 
            size_t nbytes);
size_t write(int fd, void *addr, 
             size_t nbytes);

Описание системных вызовов

Системные вызовы read и write предназначены для осуществления потоковых операций ввода (чтения) и вывода (записи) информации над каналами связи, описываемыми файловыми дескрипторами, т.е. для файлов, pipe, FIFO и socket.

Параметр fd является файловым дескриптором созданного ранее потокового канала связи, через который будет отсылаться или получаться информация, т. е. значением, которое вернул один из системных вызовов open() , pipe() или socket().

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

Параметр nbytes для системного вызова write определяет количество байт, которое должно быть передано, начиная с адреса памяти addr. Параметр nbytes для системного вызова read определяет количество байт, которое мы хотим получить из канала связи и разместить в памяти, начиная с адреса addr.

Возвращаемые значения

В случае успешного завершения системный вызов возвращает количество реально посланных или принятых байт. Заметим, что это значение (большее или равное 0 ) может не совпадать с заданным значением параметра nbytes, а быть меньше, чем оно, в силу отсутствия места на диске или в линии связи при передаче данных или отсутствия информации при ее приеме. При возникновении какой-либо ошибки возвращается отрицательное значение.

Особенности поведения при работе с файлами

При работе с файлами информация записывается в файл или читается из файла, начиная с места, определяемого указателем текущей позиции в файле. Значение указателя увеличивается на количество реально прочитанных или записанных байт. При чтении информации из файла она не пропадает из него. Если системный вызов read возвращает значение 0, то это означает, что файл прочитан до конца.

Мы сейчас не акцентируем внимание на понятии указателя текущей позиции в файле и взаимном влиянии значения этого указателя и поведения системных вызовов. Этот вопрос будет обсуждаться в дальнейшем на семинарах 11–12.

После завершения потоковых операций процесс должен выполнить операцию закрытия потока ввода-вывода, во время которой произойдет окончательный сброс буферов на линии связи, освободятся выделенные ресурсы операционной системы, и элемент таблицы открытых файлов, соответствующий файловому дескриптору, будет отмечен как свободный. За эти действия отвечает системный вызов close() . Надо отметить, что при завершении работы процесса (см. семинар 3–4) с помощью явного или неявного вызова функции exit() происходит автоматическое закрытие всех открытых потоков ввода-вывода.

Системный вызов close

Прототип системного вызова

#include <unistd.h>
int close(int fd);

Описание системного вызова

Системный вызов close предназначен для корректного завершения работы с файлами и другими объектами ввода-вывода, которые описываются в операционной системе через файловые дескрипторы: pipe, FIFO, socket.

Параметр fd является дескриптором соответствующего объекта, т. е. значением, которое вернул один из системных вызовов open() , pipe() или socket().

Возвращаемые значения

Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

Прогон программы для записи информации в файл

Для иллюстрации сказанного давайте рассмотрим следующую программу:

/*Программа 05-1.с, иллюстрирующая использование системных вызовов 
open(), write() и close() для записи информации в файл */ 
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
int main(){
    int fd; 
    size_t size;
    char string[] = "Hello, world!";
    /* Обнуляем маску создания файлов текущего процесса для того, 
    чтобы права доступа у создаваемого файла точно соответствовали 
    параметру вызова open() */
    (void)umask(0); 
    /* Попытаемся открыть файл с именем myfile в текущей директории
     только для операций вывода. Если файла не существует, попробуем
     его создать с правами доступа 0666, т. е. read-write для всех
     категорий пользователей */
    if((fd = open("myfile", O_WRONLY | O_CREAT, 
        0666)) < 0){
        /* Если файл открыть не удалось, печатаем об этом сообщение 
        и прекращаем работу */
        printf("Can\'t open file\n");
        exit(-1); 
    } 
    /* Пробуем записать в файл 14 байт из нашего массива, т.е. всю 
    строку "Hello, world!" вместе с признаком конца 
строки */
    size = write(fd, string, 14);
    if(size != 14){
        /* Если записалось меньшее количество байт, сообщаем об 
        ошибке */
        printf("Can\'t write all string\n"); 
        exit(-1); 
    } 
    /* Закрываем файл */
    if(close(fd) < 0){ 
        printf("Can\'t close file\n");
    }
    return 0; 
}
Листинг 5.1. Программа 05-1.с, иллюстрирующая использование системных вызовов open(), write() и close() для записи информации в файл

Наберите, откомпилируйте эту программу и запустите ее на исполнение. Обратите внимание на использование системного вызова umask() с параметром 0 для того, чтобы права доступа к созданному файлу точно соответствовали указанным в системном вызове open() .

Написание, компиляция и запуск программы для чтения информации из файла

Измените программу из предыдущего раздела так, чтобы она читала записанную ранее в файл информацию и печатала ее на экране. Все лишние операторы желательно удалить.

< Лекция 2 || Лекция 3: 123456 || Лекция 4 >
лия логовина
лия логовина

организовать двустороннюю поочередную связь процесса-родителя и процесса-ребенка через pipe, используя для синхронизации сигналы sigusr1 и sigusr2.

Макар Оганесов
Макар Оганесов