Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
42: &addrLength)) >=0) {
43: printf("---- получение данных\n");
44: copyData(conn, 1);
45: printf("---- готово\n");
46: close(conn);
47: }
48:
49: if (conn < 0)
50: die("accept");
51:
52: close(sock);
53: return 0;
54: }
Несмотря на небольшой размер приведенной программы, она хорошо иллюстрирует, как написать простой серверный процесс. Этот сервер является итеративным, поскольку он обрабатывает только одного клиента за раз. Можно создавать также параллельные серверы, управляющие несколькими клиентами одновременно [124] Исходя из условий реального мира, большинство серверных программ должны быть параллельными. Однако многие из них фактически созданы как итерационные сервера. Например, Web-серверы, в основном, обрабатывают только одно соединение за раз через данный процесс. Для того чтобы разрешить соединение нескольким клиентам, сервер организован в виде множества отдельных процессов. Это делает создание Web-сервера более простым. Если ошибка прерывает работу одного из таких процессов, она затрагивает только одно клиентское соединение.
.
Обратите внимание на то, что функция unlink()
вызывается до связывания сокета. Поскольку функция bind()
прекращает работу, если файл сокета уже существует, то этот шаг позволяет запускать программу более одного раза без необходимости удаления файла сокета вручную.
Серверный код приводит тип указателя struct sockaddr_un
, передаваемого и в bind()
, и в accept()
, к (struct sockaddr *)
. При прототипировании различных системных вызовов, относящихся к сокетам, предполагается, что они принимают указатель на struct sockaddr
. Приведение типа предотвращает появление уведомлений от компилятора о несоответствии типов указателей.
17.4.3. Соединение с сервером
Процесс соединения с сервером через сокет домена Unix состоит из создания сокета и присоединения к требуемому адресу через функцию connect()
. Как только сокет присоединен, он может обрабатываться как любой другой файловый дескриптор.
Следующая программа подключается с тем же самым сокетом, который использовался в примере сервера, и копирует его стандартные входные данные на сервер.
1: /* uclient.c */
2:
3: /* Подключиться к сокету ./sample-socket домена Unix, скопировать stdin
4: в сокет, после этого выйти из программы. */
5:
6: #include
7: #include
8: #include
9:
10: #include "sockutil.h" /* некоторые служебные функции */
11:
12: int main(void) {
13: struct sockaddr_un address;
14: int sock;
15: size_t addrLength;
16:
17: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
18: die("socket");
19:
20: address.sun_family = AF_UNIX; /* сокет домена Unix */
21: strcpy(address.sun_path, "./sample-socket");
22:
23: /* Общая длина адреса, включая элемент
24: sun_family */
25: addrLength = sizeof(address.sun_family) +
26: strlen(address.sun_path);
27:
28: if (connect(sock, (struct sockaddr *) &address, addrLength))
29: die("connect");
30:
31: copyData(0, sock);
32:
33: close(sock);
34:
35: return 0;
36: }
Клиент не особенно отличается от сервера. Единственные изменения состоят в том, что последовательность функций bind()
, listen()
, accept()
заменяется одним вызовом connect()
, при этом копируется немного другой набор данных.
17.4.4. Запуск примеров домена Unix
Две предыдущие программы-примера (серверная и клиентская) сконструированы для совместной работы. Запустите сервер с одного терминала, после этого активизируйте клиента из другого терминала (но в том же самом каталоге). При вводе строк в клиентской программе они автоматически передаются через сокет на сервер. После того, как вы завершите работу клиента, сервер будет ожидать следующего соединения. Вы можете передавать файлы через сокет путем переадресации входных данных в клиентскую программу.
17.4.5. Неименованные сокеты домена Unix
Благодаря тому, что сокеты домена Unix обладают некоторыми преимуществами перед каналами (например, они являются полнодуплексными), они часто используются в качестве механизма IPC. Для того чтобы облегчить этот процесс, вводится системный вызов socketpair()
.
#include
int socketpair(int domain, int type, int protocol, int sockfds[2]);
Первые три параметра совпадают с теми, которые передаются в socket()
. Последний параметр sockfds()
заполняется функцией socketpair()
двумя файловыми дескрипторами (по одному для каждой стороны сокета).
Пример применения socketpair()
показан далее в главе.
17.4.6. Передача файловых дескрипторов
Сокеты домена Unix обладают уникальным свойством: через них могут передаваться файловые дескрипторы. Ни один из прочих механизмов IPC не поддерживает подобную возможность. Она позволяет процессу открыть файл и передать файловый дескриптор в другой (возможно, несвязанный) процесс. Все проверки доступа выполняются при открытии файла, поэтому получающий процесс приобретает те же самые права доступа к файлу, что и исходный процесс.
Файловые дескрипторы передаются как часть более сложного сообщения, которое отправляется с помощью системного вызова sendmsg()
и принимается через recvmsg()
.
#include
int sendmsg(int fd, const struct msghdr * msg, unsigned int flags);
int recvmsg(int fd, struct msghdr * msg, unsigned int flags);
Параметр fd
является файловым дескриптором, через который передается сообщение; второй параметр служит указателем на структуру, описывающую сообщение. Параметр flags
обычно не используется и для большинства приложений должен быть равен нулю. В специализированных книгах по программированию для сетей обсуждаются доступные флаги [33].
Сообщение описывается показанной ниже структурой.
#include
#include
struct msghdr {
void * msg_name; /* дополнительный адрес */
unsigned int msg_namelen; /* размер msg_name */
struct iovec * msg_iov; /* массив для чтения вразброс/сборной записи*/
unsigned int msg_iovlen; /* количество элементов в msg_iov */
void * msg_control; /* вспомогательные данные */
unsigned int msg_controllen;/* длина буфера вспомогательных данных */
int msg_flags; /* флаги на получаемом сообщении */
};
Первые два члена msg_name
и msg_namelen
не используются в потоковых протоколах. Приложения, посылающие сообщения через потоковые сокеты, должны устанавливать для msg_name
значение NULL
, для msg_namelen
— ноль.
msg_iov
и msg_iovlen
описывают набор буферов, которые отправляют или принимают. Чтение вразброс и сборная запись, а также struct iovec
, обсуждаются в конце главы 13. Последний член структуры msg_flags
в настоящее время не используется и должен равняться нулю.
Интервал:
Закладка: