
Lab1_5-12IT3-Divin / Отчет
.docxМинистерство образования Республики Беларусь
ПОЛОЦКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
Кафедра вычислительных систем и сетей
Лабораторная работа № 1.5
по курсу «Операционные системы и системное программирование»
«Программирование сокетов в Linux»
Студент группы 12-ИТ-3
Выполнил: Дивин К.П.
Полоцк 2014
ЦЕЛЬ РАБОТЫ:
Создание распределенных сетевых приложений.
ХОД РАБОТЫ
-
Написать программу сервер согласно индивидуальному заданию.
-
Написать программу согласно индивидуальному заданию.
-
Связать работу двух приложений;
Реализовать программу по созданию множества мелких файлов из одного большого, размер маленьких файлов произвольныйю Сервер получает запрос от клиента и возращает ему кусочек файла. Протокол взаимодействия UDP;
Сокет (socket) - это конечная точка сетевых коммуникаций. Он является чем-то вроде "портала", через которое можно отправлять байты во внешний мир. Приложение просто пишет данные в сокет; их дальнейшая буферизация, отправка и транспортировка осуществляется используемым стеком протоколов и сетевой аппаратурой. Чтение данных из сокета происходит аналогичным образом.
Сервер:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "find.h"
#define COUNT 5
int main()
{
int sock;
struct sockaddr_in addr;
char msg1[50], msg2[50];
int bytes_read;
char *tmp = (char*)calloc(1024, sizeof(char));
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(2);
}
while(1)
{
struct sockaddr_in from;
int from_len;
bytes_read = recvfrom(sock, msg1, 50, 0,
(struct sockaddr *)&from, &from_len);
msg1[bytes_read] = '\0';
printf("Get msg: %s\n", msg1);
fflush(stdout);
bytes_read = recvfrom(sock, msg2, 50, 0,
(struct sockaddr *)&from, &from_len);
msg2[bytes_read] = '\0';
printf("Get msg: %s\n", msg2);
fflush(stdout);
int param = 0;
param = atoi(msg2);
tmp = split_file(msg1, COUNT, param);
printf("Sending Results...\n");
fflush(stdout);
sendto(sock, tmp, strlen(tmp), 0,
(struct sockaddr *)&from, from_len);
}
return 0;
}
Подключенная библиотека “find.h”, содержит в себе функцию для разбивания файла на определенное количество кусков. Функция возвращает строку содержащую имя файла, который является тем самым искомым куском файла.
Описание переменных и функций, использованных при написании:
struct sockaddr_in {
short int sin_family; // Семейство адресов
unsigned short int sin_port; // Номер порта
struct in_addr sin_addr; // IP-адрес
unsigned char sin_zero[8]; // "Дополнение" до размера структуры sockaddr
};
Здесь поле sin_family содержит идентификатор домена, в sin_port записывается номер порта, sin_addr - IP-адрес хоста.
s = socket(AF_INET, SOCK_DGRAM, 0) - функция определения сокета (AF_INET – домен Internet; SOCK_DGRAM – способ передачи данных по сети, а именно передача потока данных с помощью датаграмм.
addr.sin_family = AF_INET; - семейство адресов;
addr.sin_port = htons(3425); - номер порта;
addr.sin_addr.s_addr = htonl(INADDR_ANY); - преобразование числа из порядка хоста в сетевой порядок.
int bind(s, (struct sockaddr*)&addr, sizeof(addr)) – функция для явного связывания сокета с некотромы адресом (s – дескриптор сокета; addr – указатель на структуру адреса; sizeof(addr) – длина структуры адреса).
Функция sendto очень похожа на send. Два дополнительных параметра to и tolen используются для указания адреса получателя. Для задания адреса используется структура sockaddr, как и в случае с функцией connect. Функция recvfrom работает аналогично recv. Получив очередное сообщение, она записывает его адрес в структуру, на которую ссылается from, а записанное количество байт - в переменную, адресуемую указателем fromlen. Как мы знаем, аналогичным образом работает функция accept.
Клиент:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char msg1[50];
char msg2[50];
int sock;
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
printf("Enter filename please.\n");
scanf("%s", msg1);
sendto(sock, (const void*)msg1, sizeof(msg1), 0,
(struct sockaddr *)&addr, sizeof(addr));
printf("Enter the number of pieces of the file you want to get.\n");
scanf("%s", msg2);
sendto(sock, (const void*)msg2, sizeof(msg2), 0,
(struct sockaddr *)&addr, sizeof(addr));
char *tmp = (char*)calloc(1024, sizeof(char));;
int bytes_read;
bytes_read = recvfrom(sock, tmp, 1024, 0, NULL, NULL);
tmp[bytes_read] = '\0';
printf("Filename:\n%s\n", tmp);
fflush(stdout);
return 0;
}
Вывод:
Как уже говорилось, датаграммы используются в программах довольно редко. В большинстве случаев надёжность передачи критична для приложения, и вместо изобретения собственного надёжного протокола поверх UDP программисты предпочитают использовать TCP. Тем не менее, иногда датаграммы оказываются полезны. Например, их удобно использовать при транслировании звука или видео по сети в реальном времени, особенно при широковещательном транслировании.
Поскольку для обмена датаграммами не нужно устанавливать соединение, использовать их гораздо проще. Создав сокет с помощью socket и bind, вы можете тут же использовать его для отправки или получения данных. Для этого вам понадобятся функции sendto и recvfrom.