Автор работы: Пользователь скрыл имя, 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
Функция handle_connect отвечает за подключения клиентского сокета. Она получает запрос от клиента и проверяет его на наличие запроса HTTP GET. После чего происходит извлечение URL из строки запроса с последующим занесением полученных данных в таблицы.
/* Извлечение URL из строки запроса. */
offset = 4;
while((strncmp(
(strncmp(requestbuf+
(strncmp(requestbuf+
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_
hash_table[hash]->
gettimeofday(&
cached_flag = 0;
cache_count++; }
/* Заносим запись в таблицу кэша. */
hash_table[
strncpy(
hash_table[
gettimeofday
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); }
Если же файлы отсутствуют, то мы создаем их.
strncpy(requested_url, hash_table[hash]->url, MAX_URL_LEN-1);
offset = 7;
while((strncmp(requested_
(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_
waddr.sin_family = AF_INET;
waddr.sin_port = htons(80);
alen
= sizeof(waddr);
if ((wsock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(
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) {
fprint
cachin
send(csock, tmpbuf, retval, 0);
memset(
if (retval < 0) {
fprintf(
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); }
/* Если выбранный
элемент последний в кэш-
соответствующую
запись в хэш-таблице и
if (hash == cache_table[cache_count-1].
{
hash_table[
cache_count-
return(0);
/* Двигаем последний элемент в кэш-таблице на эту позицию. */
memcpy(hash_table[hash],
hash_table[cache_
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_
/* Строим имя файла. */
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+
/* Удаляем существующий файл. */
if (unlink(filename) < 0) {
fprintf(stderr, "Ошибка: не могу удалить файл %s: %s\n", filename, strerror(errno));
exit(
/* Удаляем запись элемента из хэш-таблицы. */
hash_table[
/* Если элемент последний в кэш-таблице, просто отнимаем 1. */
if (i == cache_count-1)
cache_
else {
/* Двигаем последний элемент в кэш-таблице на эту позицию. */
hash_
memcpy
cache_
}
}
else if (cache_table[i].last_access_
oldest_time = cache_table[i].last_access_
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+
/* Удаляем существующий файл. */
if (unlink(filename) < 0) {