- •3 Практические вопросы
- •3.1 Системное программное обеспечение
- •1. В чем особенность создания нового процесса в unix?
- •2. Предположим, что ядро выполняет отложенную запись блока. Что произойдет, когда другой процесс выберет этот блок из его хешочереди ? Из списка свободных буферов ?
- •4. Известно, что в иноде unix-подобных ос не содержится имя файла. Где его хранит система?
- •5. Назовите причины назначения разного уровня приоритетов у прерываний? Как эти приоритеты сказываются на работе системы со стеком контекстных слоев?
- •6. Поясните, какая угроза безопасности хранения данных возникает, если программа изменения прав пользователя не защищена от записи.
- •7. Что следует предпринять программе обработки отказов в том случае, если в системе исчерпаны страницы памяти?
- •8 К файлам терминалов обычно устанавливаются следующие права доступа
- •9. Какие функции unix доступны программисту для создания tcp-соединения? Чем протокол tcp отличается от udp?
- •10. Напишите сценарий для shell меняющий расширения в именах файлов текущего каталога '.C' на '.Cc'
8 К файлам терминалов обычно устанавливаются следующие права доступа
crw--w--w- 2 mjb lus 33,11 Oct 25 20:27 tty61 при входе пользователя в систему. То есть, чтение и запись разрешаются пользователю с именем "mjb", а остальным пользователям разрешена только запись. Почему ?
Для других пользователей запись в этот файл необходима для обмена сообщениями.
Это делается для того, чтобы пользователи, работающее в системе, могли писать друг другу сообщения, не прибегая к использованию E-Mail или чего-либо еще. Сообщения можно писать прямо в терминал другого пользователя примерно так:
cat > /dev/tty61
сообщение для другого пользователя
EOF
9. Какие функции unix доступны программисту для создания tcp-соединения? Чем протокол tcp отличается от udp?
Для создания ТСР-соединения используются сокеты.
Создание сокета int socket (домен, тип, протокол) , где int domain; /*AF_UNIX или AF_INET*/, int type; /*SOCK_STREAM или SOCK_DGRAM*/, int protocole; /*поставить ноль – протокол по умолчанию, другие цифры обычно берутся в документации*/
SOCK_STREAM. Передача потока данных с предварительной установкой соединения. Обеспечивается надёжный канал передачи данных, при котором фрагменты отправленного блока не теряются, не переупорядочиваются и не дублируются. Поскольку этот тип сокетов является самым распространённым, до конца раздела мы будем говорить только о нём. Остальным типам будут посвящены отдельные разделы.
SOCK_DGRAM. Передача данных в виде отдельных сообщений (датаграмм). Предварительная установка соединения не требуется. Обмен данными происходит быстрее, но является ненадёжным: сообщения могут теряться в пути, дублироваться и переупорядочиваться. Допускается передача сообщения нескольким получателям (multicasting) и широковещательная передача (broadcasting).
Обратите внимание, что не все домены допускают задание произвольного типа сокета. Например, совместно с доменом Unix используется только тип SOCK_STREAM. С другой стороны, для Internet-домена можно задавать любой из перечисленных типов. В этом случае для реализации SOCK_STREAM используется протокол TCP, для реализации SOCK_DGRAM - протокол UDP, а тип SOCK_RAW используется для низкоуровневой работы с протоколами IP, ICMP и т. д.
Примитив возвращает используемый сокет-дескриптор для следующих вызовов.
- Binding (связывание) int bind (sock, localaddr, addrlen), где int sock;/*сокет-дескриптор*/, struct sockaddr *localaddr; /*локальный сокет-адрес*/, int addrlen; /*длина адреса*/
Соединение клиента c сервером
int connect (sock, servaddr, addrlen), где int sock; /*сокет-дескриптор*/, struct sockaddr *servaddr; /*адрес сервера*/, int addrlen; /*длина адреса*/
установка сервера в режим "прослушивания" int listen (sock, qlen), где int sock; /*сокет-дескриптор*/ int qlen; /*макс. число необработ. подсоединений*/
Согласие сервера на соединение
int accept (sock, addrdistant, addrlen), где int sock; /*сокет-дескриптор*/, struct sockaddr *addrdistant; /*адрес телекоммуник.*/, int *addrlen; /*длина адреса*/
Позволяют перейти от адреса Internet в форме символов (состояние,в котором он находился в файле /etc/hosts) к адресу в форме 4-х байтов и наоборот.
u_long inet_addr (адрес) char *адрес /*адрес в ASCII-символах*/
char *inet_ntoa (inadresse) struct in_addr inadresse; /*адрес в форме целого*/
Считывание и запись Примитивы readv() и writev() позволяют осуществлять считывание и запись c помощью нескольких несмежных буферов. Этим можно пользоваться, например, для записи общего заголовка, находящегося в постоянном буфере и данных, находящихся в переменном буфере. Эти два примитива не характерны для сокетов. Примитивы sendmsg() и recvmsg() позволяют осуществлять считывание и запись в самом общем виде и используются со всеми опциями.
Управление окончанием соединения Функция shutdown () позволяет управлять окончанием соединения.
int shutdown () (sock, controle) int sock;/*сокет-дескриптор*/ int controle; Аргумент controle может принимать следующие значения: 0: больше нельзя получать данные на сокете; 1: больше нельзя посылать данные на сокет; 2: больше нельзя ни посылать, ни принимать данные на сокет.
Определение параметров сокета Параметры сокетов устанавливаются примитивом setsockopt(). Для установки некоторых опций можно использовать также функции fcntl () или ioctl (). Текущие значения параметров можно определить с помощью примитива getsockopt (). Пример:
##### Client ######### #include <sys/type.h> #include <sys/socket.h> #include <netinet/in.h> main() { int sd; struct sockaddr_in tss_addr; sd=socket(AF_INET,SOCK_STREAM,0); tss_addr.sin_family=AF_INET; tss_addr.sin_port=htons(45000); //номер порта tss_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); connect(sd,&tss_addr,sizeof(tss_addr)); write(sd, ”hello” ,6 ) ; } |
##### Server ######### main() { int sd, ns; int buf_ben; char buff[256] ; struct sockaddr_in s; struct sockaddr_in c; int c_len; sd=socket(AF_INET, SOCK_STREAM, 0); s.sin_family = AF_INET; s.sin_port = htons( 45000 ); s.sin_addr.s_addr=inet_addr("127.0.0.1"); bind(sd,&s,sizeof(s)); listen(sd,1); for(;;) ns = accept(sd, &s, &c_len) if ( fork()==0) { close(sd); read(ns, buff,256 ); printf("%s",buff); exit(1); } close(ns); } } |
Протокол UDP. Поскольку для обмена датаграммами не нужно устанавливать соединение, использовать их гораздо проще. Создав сокет с помощью socket и bind, вы можете тут же использовать его для отправки или получения данных. Для этого вам понадобятся функции sendto и recvfrom.
int sendto(int sockfd, const void *msg, int len, unsigned int flags,const struct sockaddr *to, int tolen);
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
Для задания адреса используется структура sockaddr, как и в случае с функцией connect. Функция recvfrom, Получив очередное сообщение, записывает его адрес в структуру, на которую ссылается from, а записанное количество байт - в переменную, адресуемую указателем fromlen. Как мы знаем, аналогичным образом работает функция accept.
Некоторую путаницу вносят присоединённые датаграммные сокеты (connected datagram sockets). Дело в том, что для сокета с типом SOCK_DGRAM тоже можно вызвать функцию connect, а затем использовать send и recv для обмена данными. Нужно понимать, что никакого соединения при этом не устанавливается. Операционная система просто запоминает адрес, который вы передали функции connect, а затем использует его при отправке данных. Обратите внимание, что присоединённый сокет может получать данные только от сокета, с которым он соединён.
