Самодел 2 (1114717), страница 18
Текст из файла (страница 18)
printf("client: error writing socket!\n");
return 0;
}
if (recvfrom(sockfd, buf, BUFLEN, 0, NULL, 0)<0)
{
printf("client: error reading socket!\n");
return 0;
}
printf("client: server answered: %s\n", buf);
if (quitting) break;
printf("type the string: ");
} // while
close(sockfd);
return 0;
} // if (!is_server), клиент
while (1) { /* получаем строку от клиента и выводим на печать */
party_len = sizeof(party_addr);
if (recvfrom(sockfd, buf, BUFLEN, 0,
(struct sockaddr *) &party_addr, &party_len) < 0)
{
printf("server: error reading socket!");
return 0;
}
printf("server: received from client: %s \n", buf);
/* не пора ли выходить? */
quitting = (!strcmp(buf, "quit"));
if (quitting) strcpy(buf, "quitting now!");
else
if (!strcmp(buf, "ping!")) strcpy(buf, "pong!");
else strcpy(buf, "wrong string!");
/* посылаем ответ */
if (sendto(sockfd, buf, strlen(buf) + 1, 0, (struct sockaddr *) & party_addr, party_len) != strlen(buf)+1)
{
printf("server: error writing socket!\n");
return 0;
}
if (quitting) break;
} // while (1)
close(sockfd);
return 0;
}
Пример. Работа с локальными сокетами
В качестве примера работы с сокетами в домене AF_INET напишем простой web-сервер, который будет понимать только одну команду :
GET /<имя файла>
Сервер запрашивает у системы сокет, связывает его с адресом, считающимся известным, и начинает принимать клиентские запросы. Для обработки каждого запроса порождается отдельный потомок, в то время как родительский процесс продолжает прослушивать сокет. Потомок разбирает текст запроса и отсылает клиенту либо содержимое требуемого файла, либо диагностику (“плохой запрос” или “файл не найден”).
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#define PORTNUM 8080
#define BACKLOG 5
#define BUFLEN 80
#define FNFSTR "404 Error File Not Found "
#define BRSTR "Bad Request "
int main(int argc, char **argv)
{
struct sockaddr_in own_addr, party_addr;
int sockfd, newsockfd, filefd;
int party_len;
char buf[BUFLEN];
int len;
int i;
/* создаем сокет */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("can't create socket\n");
return 0;
}
/* связываем сокет */
memset(&own_addr, 0, sizeof(own_addr));
own_addr.sin_family = AF_INET;
own_addr.sin_addr.s_addr = INADDR_ANY;
own_addr.sin_port = htons(PORTNUM);
if (bind(sockfd, (struct sockaddr *) &own_addr,
sizeof(own_addr)) < 0)
{
printf("can't bind socket!");
return 0;
}
/* начинаем обработку запросов на соединение */
if (listen(sockfd, BACKLOG) < 0) {
printf("can't listen socket!");
return 0;
}
while (1) {
memset(&party_addr, 0, sizeof(party_addr));
party_len = sizeof(party_addr);
/* создаем соединение */
if ((newsockfd = accept(sockfd, (struct sockaddr *)&party_addr,
&party_len)) < 0) {
printf("error accepting connection!");
return 0;
}
if (!fork()) {/*это – сын, он обрабатывает запрос и посылает ответ*/
close(sockfd); /* этот сокет сыну не нужен */
if ((len = recv(newsockfd,&buf,BUFLEN, 0)) < 0) {
printf("error reading socket!");
return 0;
}
/* разбираем текст запроса */
printf("received: %s \n", buf);
if (strncmp(buf, "GET /", 5)) {/*плохой запрос!*/
if (send(newsockfd, BRSTR,
strlen(BRSTR)+ 1, 0) != strlen(BRSTR) + 1)
{
printf("error writing socket!");
return 0;
}
shutdown(newsockfd, 1);
close(newsockfd);
return 0;
}
for (i=5; buf[i] && (buf[i] > ' '); i++);
buf[i] = 0;
/* открываем файл */
if ((filefd = open(buf+5, O_RDONLY)) < 0) {/* нет файла! */
if (send(newsockfd, FNFSTR,
strlen(FNFSTR) + 1, 0) != strlen(FNFSTR) + 1) {
printf("error writing socket!");
return 0;
}
shutdown(newsockfd, 1);
close(newsockfd);
return 0;
}
/* читаем из файла порции данных и посылаем их клиенту */
while (len = read(filefd, &buf, BUFLEN))
if (send(newsockfd, buf, len, 0) < 0) {
printf("error writing socket!");
return 0;
}
close(filefd);
shutdown(newsockfd, 1);
close(newsockfd);
return 0;
} /* процесс – отец. Он закрывает новый сокет и продолжает прослушивать старый */
close(newsockfd);
} // while (1)
}
4. Файловые системы (ФС)
ФС – часть ОС, представляющая собой совокупность организованных наборов данных, хранящихся на ВЗУ, и программных средств, гарантирующих именованный доступ к этим данным и их защиту.
Структурная организация файлов
Бывают однопользовательские системы – они не имеют внутри средств персонификации(комцу принадлежит файл – не известно), в таких системах практически нет защиты данных. Примеры – Dos, Windows95.
Есть и многопользовательские системы, не обеспечивающие защиту данных. В таких системах есть персонификация, но регистрация пользователей даёт только упрощённый спосок доступа к домашнему каталогу. Но там практически нет защиты файлов от несанкционированного доступа.
Есть также и многопользовательские системы, обеспечивающие персонификацию и защиту данных.
Методы подхода к организации ФС.
Существует множество разновидностей структурной
организации файлов. Наиболее популярные:
-
Файл, как последовательность байтов
Простейшая организация, наиболее прагматична. Не предполагает внутренней логической структуры данных. Обмен производится порциями байтов.
-
Файл, как последовательность записей переменной длины
Запись – это порция данных, в терминах которой происходит обмен с файлом. Существует логическая организация данного файла. В записи должно быть 2 типа информации: 1. Содержательная часть. 2. Служебная информация для разметки работы с такими файлами. Практически отсутствует внутренняя фрагментация.
Плюсы: минимизация накладных расходов; нет внутренней фрагментации.
Минусы: проблема с организацией прямого доступа.
-
Файл, как последовательность записей постоянной длины
Здесь не нужна системная информация о размере, нет проблем с прямым доступом.
М инус – внутренняя фрагментация.
-
Иерархическая организация файла (дерево).
Дерево в узлах записи
(возможно переменной длины).
Каждая запись имеет 2 поля: поле ключа и поле данных. Ключ – средство именования записи. Все записи организованы в виде дерева, т.е. есть немного служебной информации. Отсюда следует, что здесь эффективная оптимизация по поиску, удобный доступ, вариация размера записи.
Минус: сложность в системной информации.
Атрибуты файла
Важная характеристика файла – совокупность данных (атрибуты), характеризующие текущее состояние файла:
имя
права доступа
персонификация (создатель, владелец)
тип файла
размер записи
размер файла
указатель чтения / записи
время создания
время последней модификации
время последнего обращения
предельный размер файла
.....
Полный состав атрибутов файла и способ их представления определяется конкретной файловой системой.
Структурная организация атрибутов зависит от ОС.
Основные правила работы с файлами
Каждая из ФС организует работу с файлом по некоторому стандартизованному сценарию.
Операционная система и файловая система обеспечивают регистрацию возможности того или иного процесса работать с содержимым файлов.
«Сеанс работы» с содержимым файла:
1. Начало. Почти всегда существует понятие «открытие» файла (регистрация в системе возможности работы процесса с содержимым файла). Т.е. процесс запрашивает ОС, а та, исходя из характеристик данного файла, принимет решение, «давать» ли данный файл данному процессу. Факт работы процесса с файлом регистрируется в таблицах системы и в самом процессе. Так, создаётся дескриптор файла – актуальная информация о состоянии открытого файла.
2. Работа с содержимым файла, с атрибутами файла. Может идти чтение, запись и т.д.
3. Завершение. «Закрытие» файла – информация системе о завершении работы процесса с «открытым» файлом. Файл необходимо закрыть. Но закрывается, вообще говоря, не файл, а файловый дескриптор. Во многих ОС один процесс может открывать один и тот же файл много раз с различными файловыми дескрипторами.
Файловый дескриптор – системная структура данных, содержащая информацию о актуальном состоянии «открытого» файла.
Типовые программные интерфейсы работы с файлами
Open – открытие / создание файла
close – закрытие
read / write – читать, писать (относительно положения указателя чтения / запись)
delete – удалить файл из файловой системы
seek – позиционирование указателя чтение/запись
rename – переименование файла
read / write _attributes – чтение, модификация атрибутов файла.
Подробнее о позиционировании в файле. Любоая ФС с каждым открытым файлом ассоциирует виртуальный указатель на позицию. Иногда существует 2 указателя: чтения и записи. Обычно при открытии файла ОС позиционирует указатель стандартным образом. Обычно чтение – на первый байт файла, запись – на конец. Существует функция изменения позиционирования – принудительное изменение местнохождения указателя. Без использования этих функций обычно указатель меняется автоматически при каждой операции чтения/записи.
Организация информации о файлах.
Имя файла – самый главный атрибут, иногда его даже выносят из атрибутов. Исходная системная структура данных, в которой находится информация о содержащихся в системе именах файлов – каталог. Реализация каталогов может быть разной. Исторически первый каталог был как зактрытый внутренний системный объект. Вторая модель каталога – это специальный файл.
Модельная организация каталогов файловых систем
Специальные файлы – каталоги.
-
Модель одноуровневой файловой системы.
NAME1 NAME2 NAME3 ……….
Каталог – некотрая закрытая внутренняя система данных ФС, сотоящая из одного корневого каталога, в нём размещены все файлы, которые находятся в ФС. Эта схема использовалась давно. Но здесь возникали проблемы, если было очень много файлов, и также нельзя было иметь два файла с одинаковым именем. Также из-за отсутствия систематизации во всём было тяжело разобраться. Такие ФС можно использовать для специальных примениений, например, в стиральных машинах.
-
Модель двухуровневой файловой системы.
Появилась в многопользовательских ОС. Есть каталоги, где находится информация о домашних каталогах и обо всех остальных. В домашнем каталоге лежат все файлы пользователя.
П ример – простейшие сотовые телефоны.
-
Иерархические файловые системы
имя файла
полное имя файла –
последовательность имен всех
каталогов от корневого до того,
в котором содержится
файл и имя самого файла
например: /A/B/F/B
относительное имя