Нейл Мэтью - Основы программирования в Linux
- Название:Основы программирования в Linux
- Автор:
- Жанр:
- Издательство:«БХВ-Петербург»
- Год:2009
- Город:Санкт-Петербург
- ISBN:978-5-9775-0289-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нейл Мэтью - Основы программирования в Linux краткое содержание
В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стандартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым.
Для начинающих Linux-программистов
Основы программирования в Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Выполните упражнение 15.9.
1. В финальный пример программы server5.с вы включите заголовочные файлы sys/time.h и sys/ioctl.h вместо signal.h, использованного в предыдущей программе, и объявите несколько дополнительных переменных для работы с вызовом select
:
#include
#include
#include
#include
#include
#include
#include
#include
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
int result;
fd_set readfds, testfds;
2. Создайте сокет для сервера и присвойте ему имя:
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(serversockfd, (struct sockaddr *)&server_address, server_len);
3. Создайте очередь запросов на соединение и инициализируйте множество readfds
для обработки ввода с сокета server_sockfd
:
listen(server_sockfd, 5);
FD_ZERO(&readfds);
FD_SET(server_sockfd, &readfds);
4. Теперь ждите запросы от клиентов. Поскольку вы передали пустой указатель как параметр timeout
, не будет наступать истечения времени ожидания. Программа завершится и сообщит об ошибке, если select
возвращает значение, меньшее 1.
while(1) {
char ch;
int fd;
int nread;
testfds = readfds;
printf("server waiting\n");
result = select(FD_SETSIZE, &testfds, (fd_set *)0,
(fd_set *)0, (struct timeval *)0);
if (result < 1) {
perror("server5");
exit(1);
}
5. После того как вы определили, что есть активность, можно выяснить, какой из дескрипторов активен, проверяя каждый из них по очереди с помощью макроса FD_ISSET
:
for (fd = 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, &testfds)) {
6. Если зафиксирована активность на server_sockfd
, это может быть запрос на новое соединение, и вы добавляете в множество дескрипторов соответствующий client_sockfd
:
if (fd == server_sockfd) {
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr*)&client_address, &client_len);
FD_SET(client_sockfd, &readfds);
printf("adding client on fd %d\n", client_sockfd);
}
Если активен не сервер, значит, активность проявляет клиент. Если получен close
, клиент исчезает, и можно удалить его из множества дескрипторов. В противном случае вы "обслуживаете" клиента, как и в предыдущих примерах.
else {
ioctl(fd, FIONREAD, &nread);
if (nread == 0) {
close(fd);
FD_CLR(fd, &readfds);
printf("removing client on fd %d\n", fd);
} else {
read(fd, &ch, 1);
sleep(5);
printf("serving client on fd %d\n", fd);
ch++;
write(fd, &ch, 1);
}
}
}
}
}
}
В реальную программу было бы неплохо вставить переменную, содержащую наибольший подключенный номер fd
(необязательно самый последний подключенный номер fd
). Это помешает просмотру в цикле тысяч номеров fd
, которые даже не подсоединены и потенциально не могут быть готовы к чтению. Мы пропустили этот фрагмент кода для краткости и простоты примера.
При запуске этой версии сервера многочисленные клиенты будут обрабатываться последовательно в единственном процессе.
$ ./server5 &
[1] 26686
server waiting
$ ./client3 & ./client3 & ./client3 & ps x
[2] 26689
[3] 26690
adding client on fd 4
server waiting
[4] 26691
PID TTY STAT TIME COMMAND
26686 pts/1 S 0:00 ./server5
26689 pts/1 S 0:00 ./client3
26690 pts/1 S 0:00 ./client3
26691 pts/1 S 0:00 ./client3
26692 pts/1 R+ 0:00 ps x
$ serving client on fd 4
server waiting
adding client on fd 5
server waiting
adding client on fd 6
char from server = В
serving client on fd 5
server waiting
removing client on fd 4
char from server = В
serving client on fd 6
server waiting
removing client on fd 5
server waiting
char from server = В
removing client on fd 6
server waiting
[2] Done ./client3
[3]- Done ./client3
[4]+ Done ./client3
Для полноты аналогии, упомянутой в начале главы, в табл. 15.5 приведены параллели между соединениями на базе сокетов и телефонными переговорами.
Таблица 15.5
Телефон | Сетевые сокеты |
---|---|
Звонок в компанию по номеру 555-0828 | Подключение к IP-адресу 127.0.0.1 |
Ответ на звонок секретаря приемной | Установка соединения с remote host |
Просьба соединить с финансовым отделом. | Маршрутизация с помощью заданного порта (9734) |
Ответ на звонок администратора финансового отдела | Вызов select вернул управление серверу |
Звонок переадресован свободному менеджеру по работе с корпоративными заказчиками | Сервер вызывает accept , создавая новый сокет на добавочный номер 456 |
Дейтаграммы
В этой главе мы сосредоточились на программировании приложений, поддерживающих связь со своими клиентами с помощью TCP-соединений на базе сокетов. Существуют ситуации, в которых затраты на установку и поддержку соединения с помощью сокетов излишни.
Хорошим примером может служить сервис daytime
, использованный ранее в программе getdate.c. Вы создаете сокет, выполняете соединение, читаете единственный ответ и разрываете соединение. Столько операций для простого получения даты!
Сервис daytime
так же доступен с помощью UDP-соединений, применяющих дейтаграммы. Для того чтобы воспользоваться им, просто пошлите сервису одну дейтаграмму и получите в ответ единственную дейтаграмму, содержащую дату и время. Все просто.
Сервисы, предоставляемые по UDP-протоколу, применяются в тех случаях, когда клиенту нужно создать короткий запрос к серверу, и он ожидает единственный короткий ответ. Если стоимость времени процессора достаточно низкая, сервер способен обеспечить такой сервис, обрабатывая запросы клиентов по одному и разрешая операционной системе хранить очередь входящих запросов. Такой подход упрощает программирование сервера.
Поскольку UDP — не дающий гарантий сервис, вы можете столкнуться с потерей вашей дейтаграммы или ответа сервера. Если данные важны для вас, возможно, придется тщательно программировать ваших UDP-клиентов, проверяя ошибки и при необходимости повторяя попытки. На практике в локальных сетях UDP-дейтаграммы очень надежны.
Для доступа к сервису, обеспечиваемому UDP-протоколом, вам следует применять системные вызовы socket
и close
, но вместо использования вызовов read
и write
для сокета вы применяете два системных вызова, характерных для дейтаграмм: sendto
и recvfrom
.
Далее приведена модифицированная версия программы getdate.c, которая получает дату с помощью сервиса UDP-дейтаграмм. Изменения по сравнению с предыдущей версией выделены цветом.
Читать дальшеИнтервал:
Закладка: