Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 11 лет назад пользователемtka4.org
1 Механизм сокетов Средства межпроцессного взаимодействия ОС Unix, представленные в системе IPС, решают проблему взаимодействия процессов, выполняющихся в рамках одной операционной системы. Но необходимы: Унифицированный механизм, позволяющий использовать одни и те же подходы для локального и нелокального взаимодействия. Общий интерфейс, позволяющий пользоваться услугами различных протоколов по выбору пользователя. Эти проблемы решает механизм сокетов (sockets)
2 Сокеты Сокеты представляют собой в определенном смысле обобщение механизма каналов, но с учетом возможных особенностей, возникающих при работе в сети Сокеты предоставляют по сравнению с каналами больше возможностей по передаче сообщений Общая схема работы с сокетами: Каждый из взаимодействующих процессов должен на своей стороне создать и отконфигурировать сокет Процессы должны осуществить соединение с использованием этой пары сокетов По окончании взаимодействия сокеты уничтожаются
3 Средства взаимодействия процессов в сети
4 Типы сокетов. Соединение с использованием виртуального канала Последовательный поток байтов, гарантирующий надежную доставку сообщений с сохранением порядка их следования. Данные начинают передаваться только после того, как виртуальный канал установлен, и канал не разрывается, пока все данные не будут переданы. Датаграммное соединение
5 Типы сокетов. Соединение с использованием виртуального канала Датаграммное соединение Используется для передачи отдельных пакетов, содержащих порции данных – датаграмм. Надежность соединения в этом случае ниже, чем при установлении виртуального канала (для датаграмм не гарантируется доставка в том же порядке, в каком они были посланы, и доставка вообще) Скорость выше, чем у соединений с использованием виртуального канала.
6 Коммуникационный домен. Поскольку сокеты используются как для локального, так и для удаленного взаимодействия, встает вопрос о пространстве адресов сокетов. Коммуникационный домен сокета определяет форматы адресов и правила их интерпретации. Мы будем рассматривать: - домен AF_UNIX (для локального взаимодействия) - домен AF_INET (взаимодействия в рамках сети) Современные системы поддерживают и другие домены, например: - домен AF_NS (использует протоколы удаленного взаимодействия Xerox NS).
7 Создание Сокета #include int socket (int domain, int type, int protocol); domain – коммуникационный домен, к которому должен принадлежать создаваемый сокет AF_UNIX AF_INET type – тип соединения, которым будет пользоваться сокет (тип сокета) SOCK_STREAM виртуальный канал SOCK_DGRAM датаграммы
8 Создание Сокета #include int socket (int domain, int type, int protocol); protocol –протокол, который будет использоваться в рамках данного коммуникационного домена для создания соединения. Если установить значение данного аргумента в 0, система автоматически выберет подходящий протокол. Константы для протокола AF_INET: IPPROTO_TCP – обозначает протокол TCP (корректно при создании сокета типа SOCK_STREAM) IPPROTO_UDP – обозначает протокол UDP (корректно при создании сокета типа SOCK_DGRAM)
9 Создание Сокета #include int socket (int domain, int type, int protocol); В случае успеха функция возвращает положительное целое число – дескриптор сокета (аналог файлового дескриптора). В случае неудачи (например, при некорректном сочетании коммуникационного домена, типа сокета и протокола), функция возвращает –1.
10 Связывание #include int bind (int sockfd, struct sockaddr *myaddr, int addrlen); sockfd – дескриптор сокета myaddr – указатель на структуру, содержащую адрес сокета #include struct sockaddr_un { short sun_family; /* == AF_UNIX */ char sun_path[108]; }; Для домена AF_UNIX
11 Связывание #include int bind (int sockfd, struct sockaddr *myaddr, int addrlen); sockfd – дескриптор сокета myaddr – указатель на структуру, содержащую адрес сокета #include struct sockaddr_in { short sin_family; /* == AF_INET */ u_short sin_port; /* port number */ struct in_addr sin_addr; /* host IP address */ char sin_zero[8]; /* not used */ }; Для домена AF_INET
12 Связывание #include int bind (int sockfd, struct sockaddr *myaddr, int addrlen); addrlen – последний аргумент функции задает реальный размер структуры, на которую указывает myaddr. В случае успешного связывания bind возвращает 0, в случае ошибки – -1.
13 Сокеты с предварительным установлением соединения. Запрос на соединение
14 Запрос на соединение #include int connect (int sockfd, struct sockaddr *serv_addr, int addrlen); sockfd – дескриптор сокета serv_addr – указатель на структуру, содержащую адрес сокета, с которым производится соединение, в формате, который мы обсуждали выше addrlen – реальная длина структуры В случае успешного связывания функция возвращает 0, в случае ошибки – -1. Код ошибки заносится в errno.
15 Прослушивание сокета #include int listen (int sockfd, int backlog); sockfd – дескриптор сокета backlog – максимальный размер очереди запросов на соединение. В большинстве современных систем равен 5 В случае успешного связывания функция возвращает 0, в случае ошибки – -1. Код ошибки заносится в errno.
16 Подтверждение соединения #include int accept (int sockfd, struct sockaddr *addr, int *addrlen); sockfd – дескриптор сокета addr – указатель на структуру, в которой возвращается адрес клиентского сокета, с которым установлено соединение (если адрес клиента не интересует, передается NULL). addrlen – возвращается реальная длина этой структуры. максимальный размер очереди запросов на соединение. Возвращает дескриптор нового сокета, соединенного с сокетом клиентского процесса.
17 Прием и передача данных int send(int sockfd, const void *msg, int len, unsigned int flags); int recv(int sockfd, void *buf, int len, unsigned int flags); #include sockfd - дескриптор сокета, через который передаются данные msg – сообщение len – длина сообщения buf – указатель на буфер для приема данных len – первоначальная длина буфера.
18 Прием и передача данных int send(int sockfd, const void *msg, int len, unsigned int flags); int recv(int sockfd, void *buf, int len, unsigned int flags); #include flags - может содержать комбинацию специальных опций. MSG_OOB - флаг сообщает ОС, что процесс хочет осуществить прием/передачу экстренных сообщений MSG_PEEK – При вызове recv( ) процесс может прочитать порцию данных, не удаляя ее из сокета. Последующий вызов recv вновь вернет те же самые данные.
19 Прием и передача данных int send(int sockfd, const void *msg, int len, unsigned int flags); int recv(int sockfd, void *buf, int len, unsigned int flags); #include Функция возвращает количество переданных байт в случае успеха и -1 в случае неудачи. Код ошибки при этом устанавливается в errno. В случае успеха функция возвращает количество считанных байт, в случае неудачи -1
20 Прием и передача данных Read() Write() В качестве параметра этим функциям передается дескриптор сокета
21 Прием и передача данных int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); #include Такие же, как и у рассмотренных раньше указатель на структуру, содержащую адрес получателя указатель на структуру с адресом отправителя размер структуры to размер структуры from Такие же, как и у рассмотренных раньше
22 Закрытие сокета #include int shutdown (int sockfd, int mode); sockfd – дескриптор сокета mode – режим закрытия соединения = 0, сокет закрывается для чтения = 1, сокет закрывается для записи = 2, сокет закрывается и для чтения, и для записи В случае успеха функция возвращает 0, в случае неудачи -1
23 Закрытие сокета Аналогично файловому дескриптору, дескриптор сокета освобождается системным вызовом close( ). Можно не вызывать shutdown( ), соединение будет прервано. Но если используемый для соединения протокол гарантирует доставку данных (тип сокета – виртуальный канал), то вызов close() будет блокирован до тех пор, пока система будет пытаться доставить все данные, находящиеся «в пути» (если таковые имеются). Shutdown( ) извещает систему о том, что данные не нужны.
24 Схема работы с сокетами с установлением соединения Серверный сокетКлиентский сокет socketbindlistenacceptsendrecvshutdownclose socket bind connectsendrecv shutdown close
25 Схема работы с сокетами без установления соединения bind socket sendto recvfrom close
26 AF_UNIX Пример. Работа с локальными сокетами #include #define SADDRESS "mysocket" #define CADDRESS "clientsocket" #define BUFLEN 40
27 int main(int argc, char **argv) { struct sockaddr_un party_addr, own_addr; int sockfd; int is_server; char buf[BUFLEN]; int party_len; int quitting; if (argc != 2) { printf("Usage: %s client|server.\n", argv[0]); return 0; } … quitting = 1; is_server = !strcmp(argv[1],"server"); memset(&own_addr, 0, sizeof(own_addr)); own_addr.sun_family = AF_UNIX; strcpy(own_addr.sun_path, is_server?SADDRESS:CADDRESS); if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0))
28 unlink(own_addr.sun_path); /* связываем сокет */ if (bind(sockfd, (struct sockaddr *) &own_addr, sizeof(own_addr.sun_family)+ strlen(own_addr.sun_path)) < 0) { printf("can't bind socket!"); return 0; } if (!is_server) { /* это – клиент */ memset(&party_addr, 0, sizeof(party_addr)); party_addr.sun_family = AF_UNIX; strcpy(party_addr.sun_path, SADDRESS); printf("type the string: "); …
29 ... while (gets(buf)) {/* не пора ли выходить? */ quitting = (!strcmp(buf, "quit")); /* считали строку и передаем ее серверу */ if (sendto(sockfd, buf, strlen(buf) + 1, 0, (struct sockaddr *) &party_addr, sizeof(party_addr.sun_family) + strlen(SADDRESS)) != strlen(buf) + 1) { printf("client: error writing socket!\n"); return 0; } if (recvfrom(sockfd, buf, BUFLEN, 0, NULL, 0)
30 ... printf("client: server answered: %s\n", buf); if (quitting) break; printf("type the string: "); }// while close(sockfd); return 0; }// if (!is_server), клиент …
31 ... while (1) { /* получаем строку от клиента и выводим на печать */ party_len = sizeof(party_addr); if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr *) &party_addr, &party_len) < 0) { printf("server: error reading socket!"); return 0; } printf("server: received from client: %s \n", buf); /* не пора ли выходить? */ quitting = (!strcmp(buf, "quit")); if (quitting)strcpy(buf, "quitting now!"); else if (!strcmp(buf, "ping!")) strcpy(buf, "pong!"); elsestrcpy(buf, "wrong string!"); …
32 ... /* посылаем ответ */ if (sendto(sockfd, buf, strlen(buf) + 1, 0, (struct sockaddr *) & party_addr, party_len) != strlen(buf)+1) { printf("server: error writing socket!\n"); return 0; } if (quitting) break; } // while (1) close(sockfd); return 0; }
33 AF_INET GET / GET / Пример. Работа с локальными сокетами #include #define PORTNUM 8080 #define BACKLOG 5 #define BUFLEN 80 #define FNFSTR "404 Error File Not Found " #define BRSTR "Bad Request "
34 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; } …
35 /* связываем сокет */ 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; } … …
36 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; } … …
37 … /* разбираем текст запроса */ 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; } …
38 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; } …
39 /* читаем из файла порции данных и посылаем их клиенту */ 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) }
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.