Пример работы с сокетами в рамках сети.
В качестве примера работы с сокетами в домене 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) }
Лекция 11. Планирование Основные задачи планирования планирование включает в себя следующие тапы: Планирование очереди процессов на начало обработки (проблема – принципы организации этой очереди) Планирование распределения времени ЦП между процессами (оптимальная загрузка процесса + обеспечение использования ресурсов каждым процессом, приоритеты. По идее, сюда же можно внести обработку прерываний) Планирование свопинга Планирование обработки прерываний Планирование очереди запросов на обмен определение уровнЯ многопроцессности Дисциплина обслуживания очереди:
Основной проблемой планирования все же является планирование распределения времени ЦП между процессами. Раасмотрим основные особенности. Квант времени – непрерывный период процессорного времени. Приоритет процесса – числовое значение, показывающее степень привилегированности процесса при использовании ресурсов ВС (в частности, времени ЦП).
Для грамотного планирования надо решить две задачи: – определить величину кванта – определить стратегию обслуживания очереди готовых к выполнению процессов
Если величина кванта не ограничена – невытесняющая стратегия планирования времени ЦП (применяется в пакетных системах). Никто принудительно не скидывает процесс с ЦП. Разработчики берут на себя функции диспетчера. Вытесняющая стратегия - величина кванта ограничена.
Рассмотрим, как решается проблема с определения кванта времени. Кванты постоянной длины. •Время ожидания кванта процессом ~ q(n-1)
•Параметры: длина очереди и величина кванта. •Дисциплина обслуживания очереди, например, FIFO. •Переключение процессов – операция, требующая времени. Проблема: как определить длину кванта. Слишком маленький – не хватит времени на переключение, большой - некоторые успеют выполниться полностью.
Кванты переменной длины Величина кванта может меняться со временем • Вначале «большой» квант q=A,на следующем шаге q=A-t, q=A-2t,…, до q=B (B<A). Преимущество для коротких задач. • Вначале q=B, далее q=B+t,…, до q=A. Уменьшение накладных расходов на переключение задач, когда несколько задач выполняют длительные вычисления. Если процесс интенсивно пользуется операциями ввода/вывода, то он может использовать выделенный квант не до конца. Алгоритмы, основанные на приоритетах Вычисление приоритета основывается на статических и динамических характеристиках. Изменение приоритета может происходить по инициативе процесса, пользователя, ОС. Правила назначения приоритета процессов определяют эффективность работы системы. Планирование по наивысшему приоритету (highest priority first - HPF). При появлении в очереди готовых процессов процесса с более высоким приоритетом, чем у текущего наступает момент смены процесса. Возможно два варианта:
- относительный приоритет (ожидание исчерпания кванта у текущего процесса)
- абсолютный приоритет (немедленная смена текущего процесса)
Воспользуйтесь поиском по сайту: ©2015 - 2025 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|