close

Вход

Забыли?

вход по аккаунту

?

Отчет пр3

код для вставкиСкачать
 МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное государственное автономное образовательное учреждение высшего профессионального образования
НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ ЯДЕРНЫЙ УНИВЕРСИТЕТ "МИФИ" Димитровградский инженерно-технологический институт - филиал НИЯУ МИФИ
Отчет по практической работе №3
по дисциплине "Технологии программирования в сетях"
Выполнил: студент группы ВТ-51
Улейкин Е.Ю.
Проверил: ст. преподаватель кафедры ИТ
Аленин А. А.
Димитровград, 2012
Задание
Разработать две клиент-серверные пары для передачи файла с сервера клиенту без использования системного вызова sendfile и с ним. Оценить временные характеристики их работы с использованием системных вызовов gettimeofday и times Программа клиент из параметров командной строки узнает адрес сервера и имя файла для чтения, передает имя файла серверу, а затем читает данные из сокета в память без записи на диск и завершает работу.
Программа сервер выполняет следующие действия:
* Ожидает подключение клиента. * После подключения ожидает пока клиент не передаст имя файла. * Передает запрошенный файл клиенту с помощью sendfile. * Завершает соединение, печатает временные характеристики сеанса обмена и переходит в ожидание следующего подключения. Программа "server" ожидает подключений на порту с номером из лабораторных работ 3-4. Размер файла для передачи желательно взять значительным.
По завершении сеанса связи программа server остается работать, в результате вы опять сможете подключиться к ней и запросить другой файл. Если программе передать в качестве имени файла слово "quit", она должна завершит свою работу. Если в вашем распоряжении есть две машины, объединенные сетью, то можете попробовать выполнить передачу файлов через сеть.
Теоретическая часть
Приложения-серверы, такие как web-серверы, тратят огромное количество времени на передачу файлов, хранящихся на жестком диске, клиентам, работающим с сервером через web-браузер. Простой алгоритм передачи данных может выглядеть примерно так:
открыть исходный файл (на диске)
открыть файл назначения (сетевое соединение)
пока файл не передан:
прочитать блок данных из исходного файла в буфер
записать данные из буфера в файл назначения
закрыть оба файла
Процедуры чтения и записи данных обычно используют системные вызовы read и write, соответственно, либо библиотечные функции, которые являются своего рода "обертками" для этих системных вызовов.
Если следовать вышеприведенному алгоритму, то получается так, что данные копируются несколько раз, прежде чем они "уйдут" в сеть. Каждый раз, когда вызывается read, данные копируются с жесткого диска в буфер ядра (обычно посредством DMA). Затем буфер копируется в буфер приложения. Затем вызывается write и данные из буфера приложения опять копируются в буфер ядра и лишь потом этот буфер отправляется в сеть. Каждый раз, когда приложение обращается к системному вызову, происходит переключение контекста между пользовательским режимом и режимом ядра, а это весьма "дорогостоящая" операция. И чем больше в программе будет обращений к системным вызовам read и write, тем больше времени будет потрачено на выполнение переключений контекста исполнения.
Операции копирования данных из области ядра в область приложения и обратно, в данном случае, излишни, поскольку сами данные в приложении не изменяются и не анализируются. Многие операционные системы, такие как Windows NT, FreeBSD и Solaris предоставляют в распоряжение программиста системный вызов, который выполняет передачу файла за одно обращение. Ранние версии Linux часто критиковали за отсутствие подобной возможности, в результате, начиная с версии 2.2.x, такой вызов появился. Теперь он широко используется такими серверными приложениями, как Apache и Samba для ускорения обслуживания большого количества клиентов.
Реализация sendfile различна для разных операционных систем. Поэтому, в данной статье мы будем говорить о версии sendfile в Linux. Обратите внимание: утилита sendfile не то же самое, что системный вызов sendfile.
Вызов sendfile
Для его использования необходимо подключить заголовочный файл <sys/sendfile.h>, в котором находится описание прототипа функции-вызова:
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
Функция принимает следующие входные параметры: out_fd - файловый дескриптор файла назначения, открытого на запись. В этот файл производится запись данных in_fd - файловый дескриптор исходного файла, открытого на чтение. Из этого файла читаются данные offset - смещение от начала исходного файла, с этой точки будет начата передача данных (т.е. значение 0 соответствует началу файла). Это значение изменяется в процессе работы функции и ваше приложение получит его в измененном виде после того, как функция вернет управление. count - количество байт, которое необходимо передать В случае успеха функция возвращает количество переданных байт, и -1 -- в случае ошибки. В Linux файловый дескриптор может соответствовать как обычному файлу так и устройству, например -- сокету. На сегодняшний день, реализация sendfile требует, чтобы исходный файловый дескриптор соответствовал обычному файлу или устройству, поддерживаемому mmap. Это означает, например, что исходный файл не может быть сокетом. Файл назначения может быть и сокетом, и это обстоятельство широко используется приложениями.
Функция gettimeofday - получает текущее время.
Описание
array gettimeofday (void)
Это интерфейс для gettimeofday(2). Она возвращает ассоциативный массив, содержащий данные, возвращённые системным вызовом. "sec" - секунды
"usec" - микросекунды
"minuteswest" - минуты к западу от Greenwich
"dsttime" - тип dst-коррекции
Программа "Клиент":
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#define fatal(x) { perror(x); exit(1); }
main(int argc, char *argv[]){
int s, sz, i;
struct sockaddr_in ssa;
struct sockaddr *sp;
struct hostent *he;
in_addr_t sip;
int block_size=1024;
char buf[1024];
struct timeval tv1,tv2;
sz = sizeof(ssa);
if (argc != 3) {
fprintf(stderr,"Use: %s host file\n", argv[0]);
exit(1);
}
if ((sip = inet_addr(argv[1])) == -1)
{
if ((he = gethostbyname(argv[1])) == NULL)
{
fprintf(stderr,"Unknown host: %s\n", argv[1]);
exit(1);
}
sip = *(int *)he->h_addr_list[0];
}
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) fatal("Create socket fatal");
sp = (struct sockaddr *)&ssa;
ssa.sin_family = AF_INET;
ssa.sin_addr.s_addr = INADDR_ANY;
if (bind(s, sp, sizeof(ssa)) == -1) fatal("Port already used");
ssa.sin_family = AF_INET;
ssa.sin_port = htons(1234);
ssa.sin_addr.s_addr = sip;
if (connect(s, &ssa, sz) == -1) fatal("Connection fatal");
send(s,argv[2],strlen(argv[2]),0);
gettimeofday(&tv1,NULL);
while (recv(s, buf, block_size, 0) > 0);
gettimeofday(&tv2,NULL);
close(s);
printf("%s\n",buf);
}
Программа "Сервер1":
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#define fatal(x) { perror(x); exit(1); }
main()
{
int s, c, sz, size, i,src;
struct sockaddr_in ssa, csa;
struct sockaddr *sp, *cp;
char buf[1024];
int f=1;
int offset=0;
struct stat stat_buf;
int block_size=1024;
struct timeval tv1,tv2;
sp = (struct sockaddr *)&ssa;
cp = (struct sockaddr *)&csa;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) fatal("Create socket fatal");
ssa.sin_family = AF_INET;
ssa.sin_port = htons(1234);
ssa.sin_addr.s_addr = INADDR_ANY;
if (bind(s, sp, sizeof(ssa)) == -1) fatal("Port already used");
if (listen(s, 0) == -1) fatal("Listen fatal");
while (1)
{
sz = sizeof(csa);
if ((c = accept(s, cp, &sz)) == -1)
fatal("Accept socket fatal");
size=recv(c, buf, 100, 0);buf[size]=0;
if (strcmp(buf,"quit")==0){close(c);exit(0);}
src=open(buf,O_RDONLY);
if (src<0) fatal("Can't open file!!!")
fstat(src,&stat_buf);
f = stat_buf.st_size/block_size;
if(stat_buf.st_size % block_size!=0) f++;
gettimeofday(&tv1,NULL);
while (f>0)
{
i = read(src,buf,block_size);
size=send(c, buf, i, 0);
if (size<0) fatal("Send file fatal");
f--;
}
gettimeofday(&tv2,NULL);
close(c);
close(src);
printf("%d\n",(tv2.tv_usec-tv1.tv_usec));
}
}
Результат:
Client
vm:~# c 127.0.0.1 file1
Hello People!!!!!
admsmda
sd'as;dlasdl;as;dl
as/d,./as,d.,mas,.dfm,.asmfksd
asdsa
d
asd
asd
as
Server1
vm:~# s1
66
276
41
48
40
41
59
64
80
Программа "Сервер2":
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#define fatal(x) { perror(x); exit(1); }
main()
{
int s, c, sz, size, i,src;
struct sockaddr_in ssa, csa;
struct sockaddr *sp, *cp;
char buf[1024];
int f=1;
int offset=0;
struct stat stat_buf;
int block_size=1024;
struct timeval tv1,tv2;
sp = (struct sockaddr *)&ssa;
cp = (struct sockaddr *)&csa;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) fatal("Create socket fatal");
ssa.sin_family = AF_INET;
ssa.sin_port = htons(1234);
ssa.sin_addr.s_addr = INADDR_ANY;
if (bind(s, sp, sizeof(ssa)) == -1) fatal("Port already used");
if (listen(s, 0) == -1) fatal("Listen fatal");
while (1)
{
sz = sizeof(csa);
if ((c = accept(s, cp, &sz)) == -1)
fatal("Accept socket fatal");
size=recv(c, buf, 100, 0);buf[size]=0;
if (strcmp(buf,"quit")==0){close(c);exit(0);}
src=open(buf,O_RDONLY);
if (src<0) fatal("Can't open file!!!")
fstat(src,&stat_buf);
f = stat_buf.st_size/block_size;
if(stat_buf.st_size % block_size!=0) f++;
gettimeofday(&tv1,NULL);
while (f>0)
{
i = read(src,buf,block_size);
// size=send(c, buf, i, 0);
off_t offset = 0;
sendfile(c,src,&offset,stat_buf.st_size); if (size<0) fatal("Send file fatal");
f--;
}
gettimeofday(&tv2,NULL);
close(c);
close(src);
printf("%d\n",tv2.tv_usec-tv1.tv_usec);
}
}
Результат:
Server2
vm:~# s2
57
59
42
62
53
53
55
49
46
50
81
В результате сравнения оказалось, что передача данных с помощью системного вызова sendfile происходит быстрее, чем с использованием функции send.
Документ
Категория
Рефераты
Просмотров
31
Размер файла
70 Кб
Теги
пр3, отчет
1/--страниц
Пожаловаться на содержимое документа