Кэширующий прокси-сервер

Автор работы: Пользователь скрыл имя, 10 Октября 2011 в 19:40, дипломная работа

Описание

Данный вид прокси-серверов так же используется и провайдерами. Как говорилось выше, Интернет состоит из большого количества серверов. Некоторые из них содержат веб-сайты, а некоторые являются лишь транспортными узлами, перенаправляющими трафик от пользователя к веб-сайту и обратно. Провайдеры заинтересованы в уменьшении объема трафика. Для этого они применяют технологию кэширования на своих серверах, чтобы отвечать на часть пользовательских запросов, не пересылая их дальше внутренней сети. Данный метод описан в RFC 2616, позволяющий сообщить прокси-серверам, что содержимое желательно кэшировать (Cache-Control: public).

Содержание

Введение………………….………………………………………………………3

1.ПОСТАНОВКА ЗАДАЧИ……………………………………………………..5

2.ОБЗОР СЕТЕЙ И ПРОКСИ-СЕРВЕРОВ…………………………………….6

2.1. Локальная сеть………………………………………………………..6

2.2. Функции различных прокси-серверов………………………………8

2.3. Сравнение «Кэширующего прокси-сервера» с другими прокси-серверами……………..……………………………………………….…..22

2.3.1. Squid………………………………………………………….22

2.3.2. DeleGate……………………...……………...………………..24

2.3.3. WinGate…………………………………………………........26

2.3.4. UserGate………………………………………………………27

2.3.5. Traffic Inspector……………………………………………....28

3. АРХИТЕКТУРА ПРИЛОЖЕНИЯ…………………………………………....30

3.1. Обоснование выбора языка программирования…………………….30

3.2. Протокол TCP…………………………………………………………31

3.3. Формат заголовка HTTP……………………………………………...35

3.4. Сокеты…………………………………………………………………38

3.5. Разработка структуры приложения………………………………....40

4.СОЗДАНИЕ ПРОГРАММЫ «КЭШИРУЮЩИЙ ПРОКСИ-СЕРВЕР» ...…42

4.1 Библиотеки и компоненты, которые использовались при разработке программы……………..……………………………………………….....42

4.2 Реализация функций программы «Кэширующий прокси-сервер»...47

5. КРАТКАЯ ИНСТРУКЦИЯ ПОЛЬЗОВАТЕЛЯ…………………...………...56

Заключение……………………………………………………………………….60

Список литературы…..…………………………………………………………..61

Работа состоит из  2 файла

Диплом-текст.doc

— 873.50 Кб (Скачать документ)

     Функция handle_connect отвечает за подключения клиентского сокета. Она получает запрос от клиента и проверяет его на наличие запроса HTTP GET. После чего происходит извлечение URL из строки запроса с последующим занесением полученных данных в таблицы.

      /* Извлечение URL из строки запроса.  */

      offset = 4;

      while((strncmp(requestbuf+offset, " ", 1) != 0) &&

      (strncmp(requestbuf+offset, "\0", 1) != 0) &&

      (strncmp(requestbuf+offset, "\r", 1) != 0))

      offset++;

      if (offset > MAX_URL_LEN+3) {

      fprintf(stderr, "Ошибка, слишком длинный URL-запрос \n");

      return(1); }

      strncpy(requested_url, requestbuf+4, offset-4);

      (DEBUG) && fprintf(stderr, "*** Клиент запросил: %s\n", requested_url); 

      /* Вычисляем хэш URL. */

      hash = calculate_hash(requested_url); 

      /* Очистка кэша. */

            cache_count = clean_cache(-1); 

            /* Создаем запись  в кэш-таблице. */

            hash_table[hash] = &cache_table[cache_count];

            strncpy(hash_table[hash]->url, requested_url, strlen(requested_url)+1);

            hash_table[hash]->hash_value = hash;

            gettimeofday(&hash_table[hash]->last_access_time, NULL);

            cached_flag = 0;

            cache_count++; } 

                  /* Заносим запись в таблицу кэша. */

                  hash_table[hash] = &cache_table[cache_count];

                  strncpy(hash_table[hash]->url, requested_url, strlen(requested_url)+1);

                  hash_table[hash]->hash_value = hash;

                  gettimeofday(&hash_table[hash]->last_access_time, NULL);

                  cached_flag = 0;

                  cache_count++;  } 

     Далее происходит создание файла для скэшированных данных.  

if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) {

fprintf(stderr, "Ошибка открытия файла %s для записи: %s\n", filename, strerror(errno)); 

     В случае, если имеется похожий файл, то он сравнивается с вновь полученным. Если имеющийся файл существенно старше вновь полученного или имеющийся поврежден, то файл из кэша будет удален вместе с соответствующими записями в таблице, а затем будет создан новый вместе с записями в таблице.

     Здесь же создается дочерний процесс, который будет функции handle_request. Родительский процесс передает дочернему процессу имя файла, запрошенный URL, имя веб-сервера, буффер запроса и буффер с данными.

     Когда клиент отправляет запрос, то впервую  очередь проверяется локальный кэш на наличие уже скэшированных файлов. Если таковые имеются, то они передаются клиенту. 

while ((retval = read(fd, tmpbuf, BUFFER_LEN)) > 0) {

      send(csock, tmpbuf, retval, 0);

      memset(tmpbuf, '\0', BUFFER_LEN);  } 

     Если  же файлы отсутствуют, то мы создаем их.

  • Сначала программа получает URL из кэш-таблицы

      strncpy(requested_url, hash_table[hash]->url, MAX_URL_LEN-1);

  • Затем происходит извлечение имени веб-сервера из URL
 

     offset = 7;

     while((strncmp(requested_url+offset, "/", 1) != 0) &&

      (strncmp(requested_url+offset, " ", 1) != 0))

     offset++;

     strncpy(server_name, requested_url+7, offset-7);

  • Программа ищет веб-сервер

      if ((servdata = gethostbyname(server_name)) == NULL) {

      fprintf(stderr, "Ошибка поиска сервера %s: %s\n", server_name, hstrerror(h_errno));

                  send(csock, "HTTP/1.0 500 Server Error\r\n\r\n", 29, 0);

                  close(csock);

                  return(hash);  } 

  • Происходит  установка адреса сокета для удаленного веб-сервера   

            memcpy(&waddr.sin_addr, servdata->h_addr, servdata->h_length);

            waddr.sin_family = AF_INET;

            waddr.sin_port = htons(80);       

         alen = sizeof(waddr); 

  • Подключение к веб-серверу
 

            if ((wsock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {

                  fprintf(stderr, "Ошибка создания сокета: %s\n", strerror(errno));

                  send(csock, "HTTP/1.0 500 Server Error\r\n\r\n", 29, 0);

                  close(csock);

                  return(hash);  }

            if ((connect(wsock, &waddr, alen)) < 0) {

      fprintf(stderr, "Ошибка подключения к серверу %s: %s\n", server_name, strerror(errno));

                  send(csock, "HTTP/1.0 500 Server Error\r\n\r\n", 29, 0);

                  close(wsock);

                  close(csock);

                  return(hash);  } 

  • Построение  строки запроса и отправка   
 

         strcat(requestbuf, "GET ");

            strcat(requestbuf, requested_url);

            strcat(requestbuf, " HTTP/1.0\r\n\r\n");

            send(wsock, requestbuf, strlen(requestbuf), 0); 

  • Создание  файла для скэшированных данных
 

      if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) {

      fprintf(stderr, "Ошибка открытия файла %s для записи: %s\n", filename, strerror(errno));  } 

  • Считывание  ответных данных от веб-сервера и запись полученных данных в кэш-файл
 

            while ((retval = read(wsock, tmpbuf, BUFFER_LEN)) > 0) { 

                  if ((caching == 1) && (write(fd, tmpbuf, retval)) < 0) {

                        fprintf(stderr, "Ошибка записи в %s: %s\n", filename, strerror(errno));

                        caching == 0;   }

  • Программа отправляет полученные данные клиенту.
 

                  send(csock, tmpbuf, retval, 0);

                  memset(tmpbuf, '\0', BUFFER_LEN);  }

            if (retval < 0) {

                  fprintf(stderr, "Ошибка чтения данных сервера: %s\n", strerror(errno));

                  send(csock, tmpbuf, strlen(tmpbuf), 0);

                  close(fd);

                  close(wsock);

                  close(csock);

                  return(hash);  } 

            close(fd);

            close(wsock);

            close(csock); } 

     Функция очистки кэша (clean_cache) необходима для удаления устаревших данных и их записей из таблиц. Так же она помогает устранить некоторые проблемы, которые возникают при получении файлов и помогает устранять частные случаи коллизий.

  • Удаление существующего файла

            if (unlink(filename) < 0) {

            fprintf(stderr, "Ошибка: не могу удалить файл %s: %s\n", filename, strerror(errno));

                  exit(1);  }

  • Удаляем выбранный элемент из таблиц
 

            /* Если выбранный  элемент последний в кэш-таблице,  просто удаляем

               соответствующую  запись в хэш-таблице и отнимаем 1 от общего кол-ва. */

            if (hash == cache_table[cache_count-1].hash_value)

           {

                  hash_table[hash] = NULL;

                  cache_count--;

                  return(0);  } 

            /* Двигаем последний  элемент в кэш-таблице на эту  позицию. */

      memcpy(hash_table[hash],&cache_table[cache_count-1], sizeof(cache_table[cache_count-1]));

            hash_table[cache_table[cache_count-1].hash_value] = hash_table[hash];

            hash_table[hash] = NULL;

            cache_count--;

            return(0); } 

  • Удаление  просроченных элементов кэша
 

      gettimeofday(&now, NULL);

      time_to_die = now.tv_sec - (MAX_AGE * 60);

      oldest_time = now.tv_sec; 

      /* Удаляем все скэшированные элементы которые старше чем MAX_AGE. */

      for (i=0; i < cache_count; i++) {

            if (cache_table[i].last_access_time.tv_sec <= time_to_die) { 

                  /* Строим имя файла. */

            memset(filename, '\0', NAME_MAX);

            hash = cache_table[i].hash_value;

            strncat(filename, DIR, strlen(DIR));

            strcat(filename, "/");

            strncat(filename, FILENAME_PREFIX, strlen(FILENAME_PREFIX));

            snprintf(filename+strlen(filename), NAME_MAX-strlen(filename), "%i.%i", pid, hash); 

            /* Удаляем существующий  файл. */

                  if (unlink(filename) < 0) {

            fprintf(stderr, "Ошибка: не могу удалить файл %s: %s\n", filename, strerror(errno));

                        exit(1);   } 

                  /* Удаляем запись  элемента из хэш-таблицы. */

                  hash_table[cache_table[i].hash_value] = NULL; 
 

           /* Если элемент последний в кэш-таблице, просто отнимаем 1. */

                  if (i == cache_count-1)

                        cache_count--; 

                  else { 

                        /* Двигаем последний  элемент в кэш-таблице на эту  позицию. */

                        hash_table[cache_table[cache_count-1].hash_value] = &cache_table[i];

                        memcpy(&cache_table[i], &cache_table[cache_count-1], sizeof(cache_table[i]));

                        cache_count--;

                  }

            }

  • Необходимо отслеживать элементы, у которых почти истек срок годности  

                  else if (cache_table[i].last_access_time.tv_sec <= oldest_time) {

                  oldest_time = cache_table[i].last_access_time.tv_sec;

                  oldest_index = i;  } }

  • В случае, если превышено число записей в кэше, то мы удаляем устаревшие элементы
 

      if (cache_count >= MAX_ENTRIES) {

            i = oldest_index;

            /* строим имя файла. */

            memset(filename, '\0', NAME_MAX);

            hash = cache_table[i].hash_value;

            strncat(filename, DIR, strlen(DIR));

            strcat(filename, "/");

            strncat(filename, FILENAME_PREFIX, strlen(FILENAME_PREFIX));

            snprintf(filename+strlen(filename), NAME_MAX-strlen(filename), "%i.%i", pid, hash); 

            /* Удаляем существующий  файл. */

            if (unlink(filename) < 0) {

Титульный лист.doc

— 30.00 Кб (Открыть документ, Скачать документ)

Информация о работе Кэширующий прокси-сервер