Нейл Мэтью - Основы программирования в Linux
- Название:Основы программирования в Linux
- Автор:
- Жанр:
- Издательство:«БХВ-Петербург»
- Год:2009
- Город:Санкт-Петербург
- ISBN:978-5-9775-0289-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нейл Мэтью - Основы программирования в Linux краткое содержание
В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стандартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым.
Для начинающих Linux-программистов
Основы программирования в Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
sys 0m0.040s
[1]+ Done ./fifo3
Как это работает
Обе программы применяют FIFO в режиме блокировки. Вы запускаете первой программу fifo3 (пишущий процесс/поставщик), которая блокируется, ожидая, когда читающий процесс откроет канал FIFO. Когда программа fifo4 (потребитель) запускается, пишущий процесс разблокируется и начинает записывать данные в канал. В это же время читающий процесс начинает считывать данные из канала.
ОС Linux так организует планирование двух процессов, что они оба выполняются, когда могут, и заблокированы в противном случае. Следовательно, пишущий процесс блокируется, когда канал полон, а читающий — когда канал пуст.
Вывод команды time
показывает, что читающему процессу потребовалось гораздо меньше одной десятой секунды для считывания 10 Мбайт данных в процесс. Это свидетельствует о том, что каналы, по крайней мере, их реализация в современных версиях Linux, могут быть эффективным средством обмена данными между программами.
Более сложная тема: применение каналов FIFO в клиент-серверных приложениях
Заканчивая обсуждение каналов FIFO, давайте рассмотрим возможность построения очень простого клиент-серверного приложения, применяющего именованные каналы. Вы хотите, чтобы один серверный процесс принимал запросы, обрабатывал их и возвращал результирующие данные запрашивающей стороне — клиенту.
Вам нужно разрешить множественным клиентским процессам отправлять данные серверу. Для простоты предположим, что данные, которые нужно обработать, можно разбить на блоки, каждый из которых меньше PIPE_BUF
байтов. Конечно, реализовать такую систему можно разными способами, но мы рассмотрим только один, как иллюстрацию применения именованных каналов.
Поскольку сервер будет обрабатывать только один блок данных в каждый момент времени, кажется логичным создать один канал FIFO, который читается сервером и в который записывают всё клиенты. Если открыть FIFO в блокирующем режиме, сервер и клиенты будут при необходимости блокироваться.
Возвращать обработанные данные клиентам немного сложнее. Вам придется организовать второй канал для возвращаемых данных, один для каждого клиента. Если передавать идентификатор (PID) процесса-клиента в исходных данных, отправляемых на сервер, обе стороны смогут использовать его для генерации уникального имени канала с возвращаемыми данными.
Выполните упражнение 13.13.
1. Прежде всего, вам нужен заголовочный файл client.h, в котором определены данные, общие для серверных и клиентских программ. В приложение также для удобства включены требуемые системные заголовочные файлы.
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVER_FIFO_NAME "/tmp/serv_fifo"
#define CLIENT_FIFO_NAME "/tmp/cli_%d_fifo"
#define BUFFER_SIZE 20
struct data_to_pass_st {
pid_t client_pid;
char some_data[BUFFER_SIZE - 1];
};
2. Теперь займемся серверной программой server.c. В этом разделе вы создаете и затем открываете канал сервера. Он задается в режиме "только для чтения" и с блокировкой. После засыпания (из демонстрационных соображений) сервер читает данные от клиента, у которого есть структура типа data_to_pass_st
.
#include "client.h"
#include
int main() {
int server_fifo_fd, client fifo_fd;
struct data_to_pass_st my_data;
int read_res;
char client_fifo[256];
char *tmp_char_ptr;
mkfifo(SERVER_FIFO_NAME, 0777);
server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);
if (server_fifo_fd == -1) {
fprintf(stderr, "Server fifo failure\n");
exit(EXIT_FAILURE);
}
sleep(10); /* для целей демонстрации разрешает клиентам создать очередь */
do {
read_res = read(server_fifo_fd, &my_data, sizeof(my_data));
if (read res > 0) {
3. На следующем этапе вы выполняете некоторую обработку данных, только что полученных от клиента: преобразуете все символы в некоторых данных в прописные и соединяете CLIENT_FIFO_NAME
с полученным идентификатором client_pid
.
tmp_char_ptr = my_data.some_data;
while (*tmp_char_ptr) {
*tmp_char_ptr = toupper(* tmp_char_ptr);
tmp_char_ptr++;
}
sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid);
4. Далее отправьте обработанные данные назад, открыв канал клиентской программы в режиме "только для записи" и с блокировкой. В заключение закройте серверный FIFO с помощью закрытия файла и отсоединения FIFO.
client_fifo_fd = open(client_fifo, O_WRONLY);
if (client_fifo_fd ! = -1) {
write(client_fifo_fd, &my_data, sizeof(my_data));
close(client_fifo_fd);
}
}
} while (read_res > 0);
close(server_fifo_fd);
unlink(SERVER_FIFO_NAME);
exit(EXIT_SUCCESS);
}
5. Далее приведена клиентская программа client.с. В первой части этой программы FIFO сервера, если он уже существует, открывается как файл. Далее программа получает идентификатор собственного процесса, который формирует некие данные, которые будут отправляться на сервер. Создается FIFO клиента, подготовленный для следующего раздела.
#include "client.h"
#include
int main() {
int server_fifo_fd, client_fifo_fd;
struct data_to_pass_st my_data;
int times_to_send;
char client_fifo[256];
server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY);
if (server_fifo_fd == -1) {
fprintf (stderr, "Sorry, no server\n");
exit(EXIT_FAILURE);
}
my_data.client_pid = getpid();
sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid);
if (mkfifo(client_fifo, 0777) == -1) {
fprintf(stderr, "Sorry, can't make %s\n", client_fifo);
exit(EXIT_FAILURE);
}
6. В каждом из пяти проходов цикла клиентские данные отправляются на сервер. Далее клиентский FIFO открывается (в режиме "только для чтения" с блокировкой) и данные считываются обратно. В конце серверный FIFO закрывается, а клиентский FIFO удаляется из файловой системы.
for (times_to_send = 0; times_to_send < 5; times_to_send++) {
sprintf(my_data.some_data, "Hello from %d", my_data.client_pid);
printf("%d sent %s, ", my_data.client_pid, my_data.some_data);
write(server_fifo_fd, &my_data, sizeof(my_data));
client_fifo_fd = open(client_fifo, O_RDONLY);
if (client_fifo_fd != -1) {
Интервал:
Закладка: