Similar presentations:
Взаимодействие процессов 3 V13
1. Взаимодействие процессов: сокеты
2. Создание сокета
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int socket ( int domain, int type, int protocol ) ;
Параметры
domain — коммуникационный домен:
• AF_UNIX
• AF_INET
type — тип сокета:
• SOCK_STREAM — виртуальный канал
• SOCK_DGRAM — датаграммы
protocol — протокол:
• 0 — автоматический выбор протокола
• IPPROTO_TCP — протокол TCP (AF_INET)
• IPPROTO_UDP — протокол UDP (AF_INET)
3. Связывание
#include <sys/types.h>#include <sys/socket.h>
int bind ( int sockfd, struct sockaddr * myaddr, int
addrlen ) ;
Параметры
sockfd — дескриптор сокета
myaddr — указатель на структуру, содержащую адрес
сокета
Структура
адреса для
домена
AF_UNIX
#include <sys/un.h>
struct sockaddr_un {
short sun_family ;
char sun_path [ 108 ] ;
};
/* == AF_UNIX */
Файл, полное имя которого передается в bind должен отсутствовать
4. Связывание
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd,struct sockaddr * myaddr,int addrlen);
Параметры
sockfd — дескриптор сокета
myaddr — указатель на структуру, содержащую адрес
сокета
#include <netinet/in.h>
Структура
адреса для
домена
AF_INET
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 */
};
struct in_addr {unsigned long s_addr;};
5. Связывание
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int bind ( int sockfd, struct sockaddr * myaddr, int
addrlen ) ;
Параметры
addrlen — размер структуры sockaddr («доменный»
адрес сокета).
Возвращаемое значение
В случае успешного связывания bind возвращает 0, в
случае ошибки — –1.
6. Предварительное установление соединения
серверклиент
socket ()
socket ()
bind ()
bind ()
listen ()
сonnect ()
while (…)
send ()
recv ()
accept ()
shutdown ()
send ()
recv ()
shutdown ()
close ()
клиент
socket ()
close ()
bind ()
7. Прослушивание сокета
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int listen (int sockfd, int backlog);
Параметры
sockfd — дескриптор сокета
backlog — максимальный размер очереди запросов на
соединение
Возвращаемое значение
В случае успешного обращения функция возвращает 0, в
случае ошибки — –1. Код ошибки заносится в errno.
8. Запрос на соединение
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int connect ( int sockfd, struct sockaddr * serv_addr, int addrlen ) ;
Параметры
sockfd — дескриптор сокета
serv_addr — указатель на структуру, содержащую адрес сокета, с
которым производится соединение
addrlen — реальная длина структуры
Возвращаемое значение
0 в случае успешного установления соединения с сервером;
–1 в случае неудачи (например тогда, когда сервер еще «не готов» к
установлению соединений с клиентами - не выполнил обращение к
системному вызову listen ).
Процесс может быть заблокирован до тех пор пока сервер не
обработает запрос на соединение.
9. Предварительное установление соединения
серверклиент
socket ()
socket ()
bind ()
bind ()
listen ()
сonnect ()
while (…)
send ()
recv ()
accept ()
shutdown ()
send ()
recv ()
shutdown ()
close ()
клиент
socket ()
close ()
bind ()
10. Подтверждение соединения
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int accept ( int sockfd, struct sockaddr * addr, int * addrlen ) ;
Параметры
sockfd — дескриптор сокета
addr — указатель на структуру, в которой возвращается адрес
клиентского сокета, с которым установлено соединение (если
адрес клиента не интересует, передается NULL).
addrlen — возвращается реальная длина этой структуры.
Возвращаемое значение
- дескриптор нового сокета, соединенного с сокетом клиентского
процесса.
11. Прием и передача данных
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int send ( int sockfd, const int recv ( int sockfd, void *
buf, int len, unsigned
void * msg, int len,
int flags ) ;
unsigned int flags ) ;
Параметры
sockfd — дескриптор сокета, через который передаются
данные
msg — сообщение
buf — указатель на буфер
для приема данных
len — длина сообщения
len — первоначальная
длина буфера
12. Прием и передача данных
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int send ( int sockfd, const int recv ( int sockfd, void *
buf, int len, unsigned
void * msg, int len,
int flags ) ;
unsigned int flags ) ;
Параметры
flags — может содержать комбинацию специальных опций.
MSG_OOB — флаг сообщает ОС, что процесс хочет осуществить
прием/передачу экстренных сообщений.
MSG_PEEK — При вызове recv () процесс может прочитать
порцию данных, не удаляя ее из сокета. Последующий вызов recv
вновь вернет те же самые данные.
13. Прием и передача данных
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int send ( int sockfd, const int recv ( int sockfd, void *
buf, int len, unsigned
void * msg, int len,
int flags ) ;
unsigned int flags ) ;
Возвращаемое значение
Функция возвращает
В случае успеха функция
количество переданных
возвращает количество
байт в случае успеха и –1 в считанных байт, в случае
случае неудачи. Код
неудачи –1.
ошибки при этом
устанавливается в errno.
14. Прием и передача данных
• read(…)• write(…)
15. Сокеты без предварительного соединения
процесс 1socket ()
процесс 2
socket ()
bind ()
sendto ()
bind ()
recvfrom ()
sendto ()
recvfrom ()
shutdown ()
shutdown ()
close ()
close ()
процесс N
socket ()
bind ()
16. Прием и передача данных
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
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 ) ;
Такие же, как и у
рассмотренных раньше
указатель на структуру,
содержащую адрес получателя
размер структуры to
Такие же, как и у
рассмотренных раньше
указатель на структуру с
адресом отправителя
размер структуры from
17. Завершение работы с сокетом
Необходимые заголовочные файлы и прототип#include <sys/types.h>
#include <sys/socket.h>
int shutdown ( int sockfd, int mode ); - «жесткое»
закрытие сокета, возможно частичное
sockfd — дескриптор сокета
mode — режим закрытия соединения
= 0, сокет закрывается для чтения
= 1, сокет закрывается для записи
= 2, сокет закрывается и для чтения, и для записи
int close (int fd) ; - «мягкое» закрытие (только текущего
дескриптора)
18. Схема работы с сокетами с установлением соединения
Серверный сокетКлиентский сокет
socket
socket
bind
bind
listen
connect
accept
send
send
recv
recv
shutdown
shutdown
close
close
19. Схема работы с сокетами без установления соединения
socketbind
sendto
recvform
close
20. Проблема NUXI - Big-endian и little-endian при вызове вызова bind().
Имя сокета в домене AF_INET имеются многобайтовые поля, которые должныбыть переданы по сети (например, поле IP адреса) – проблема порядка байтов
(например, поле IP адреса). Рассмотрим пример 16 разрядной машины, в памяти
которой в двух машинных словах, начиная с адреса А, размещен UNIX, в двух
16-ти разрядных кодах: в первом коды UN, во втором IX.
Возможны 2 модели представления:
Big-endian прямой порядок байтов – унифицированный СЕТЕВОЙ ПОРЯДОК
Адрес байта:
А
А+1
А+2
А+3
Содержимое:
U
N
I
X
:
little-endian обратный порядок байтов
Адрес байта:
А
А+1
А+2
А+3
Содержимое:
N
U
Х
I
21. Проблема NUXI - Big-endian и little-endian при вызове вызова bind().
Рассмотрим другой пример:Дана 32-х разрядная ЭВМ. По адресу А находится код: 0xD4C3B2A1
В этом случае:
Big-endian прямой порядок байтов – СЕТЕВОЙ ПОРЯДОК
Адрес байта:
А
А+1
А+2
А+3
Содержимое:
D4
C3
B2
А1
little-endian обратный порядок байтов
Адрес байта:
А
А+1
А+2
А+3
Содержимое:
А1
B2
C3
D4
22. Проблема NUXI - Big-endian и little-endian при вызове вызова bind().
#include <arpa/inet.h> /*или <netinet/in.h>*/uint32_t htonl(uint32_t hostint32)
- на входе 32-разрядное целое текущей архитектуры, возвращает 32-разрядное
целое, приведённое к сетевому порядку байт (host-to-network)
uint32_t ntohl(uint32_t netint32)
- на входе 32-разрядное целое в сетевом порядке байт, возвращает 32-разрядное
целое, приведённое к формату текущей архитектуры (network-to-host)
Функции htons и ntohs реализуют аналогичные преобразования для 16разрядных целых.
23. Пример №1 Сетевое взаимодействие через сокеты, с установлением соединения.
Цель:разработать
программную
реализацию
Клиент/Сервера,
взаимодействующего в пространстве домена AF_INET.
Клиент:
•создает свой сокет и через него запрашивает соединение к серверу по
заданному адресу;
•формирует текстовую строку с номером PID’а своего процесса, которую
отправляет на сервер;
•ожидается получения информации в виде текстовой строки от Сервера,
выводит ее на стандартное устройство вывода. Далее закрытие сокета.
Сервер:
•создает свой основной сокет и открывает основной сервер на прослушивание.
•подтверждает запросы на соединение с каждым Клиентом.
•для каждого соединения Сервер формирует отдельный процесс в котором
будет осуществляться взаимодействие с Клиентом.
24. Пример №1 Сетевое взаимодействие через сокеты, с установлением соединения (1)
Особенности программной реализации:Для обеспечения возможности самостоятельного запуска демонстрационного примера
сетевого взаимодействия в рамках одной локальной ВС, в качестве IP адреса Сервера
может использоваться зарезервированный IP адрес 127.0.0.1 – означает, что к серверу
могут обращаться только клиенты, находящие в рамках одной и той же ВС, что Сервер.
При запуске клиент-сервера в рамках реальной сети, потребуется использование
реального IP адреса компьютера (заметим, что у одного компьютера может быть
несколько IP адресов – к примеру, у выполняющего функцию шлюза.
Используемые библиотечные функции:
inet_addr (…) – преобразует IP адрес из строки в число в сетевом представлении;
htons (…) – преобразует 2-байтное число в число в сетевом представлении;
htonl (…) – преобразует 4-байтное число в число в сетевом представлении;
inet_ntoa (…) – преобразует IP адрес из сетевого представления в строку.
INADDR_ANY –предопределенная константа, использование которой обеспечивает
«привязку» ко всем IP адресам данного сервера, включая 127.0.0.1 .
25. Клиент
#include <sys/types.h>#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define PORTNUM 50500
#define BUFLEN 80
int main(int argc, char **argv)
{
struct sockaddr_in addr;
int sockfd;
char buf[BUFLEN];
/*создание сокета*/
sockfd = socket(AF_INET,
SOCK_STREAM, 0);
/*заполнение структуры данных
для подключения к серверу*/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
/*в качестве IP адреса сервера зарезервироанная IPконстанта*/
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(PORTNUM);
/*подключение к серверу*/
connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
/*отсылка данных серверу в виде строкичисла(собственный pid)*/
sprintf(buf, "%d", getpid());
send(sockfd, buf, strlen(buf) + 1, 0);
/*получение ответа от сервера в виде строки*/
recv(sockfd, &buf, BUFLEN, 0);
printf("received: %s \n", buf);
/*закрытие сокета*/
close(sockfd);
}
26. Сервер (1)
#include <sys/types.h>#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define PORTNUM 50500
#define BUFLEN 80
#define QUESIZE 5 /* условный размер очереди запросов на соединение */
int main(int argc, char **argv) {
struct sockaddr_in own_addr, /* основной сокет*/
party_addr;/* «клиентский» сокет – создается после выполнения accept() */
int sockfd, newsockfd;
int party_len, len;
char buf[BUFLEN];
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* создаем основной сокет */
/* заполнение данных для именования основного сокета */
memset(&own_addr, 0, sizeof(own_addr));
own_addr.sin_family = AF_INET;
/* константа INADDR_ANY обеспечивает возможность привязки сокета ко всем IP адресам
компьютера, включая выделенный IP 127.0.0.1 */
own_addr.sin_addr.s_addr = INADDR_ANY;
/* задаём порт, функция ntohs приводит 16-разрядный аргумент к сетевому порядку байт */
own_addr.sin_port = htons(PORTNUM);
27. Сервер (2)
/*связываем основной сокет, приводим типа указателя к фактической структуру данных */bind(sockfd, (struct sockaddr *) &own_addr, sizeof(own_addr));
listen(sockfd, QUESIZE); /*разрешаем обработку запросов на соединение*/
while (1) {/* основной цикл */
memset(&party_addr, 0, sizeof(party_addr)); /*подготавливаем очищенную структуру данных*/
party_len = sizeof(party_addr);
/*создание нового соединения – для каждого клиента в party_addr записывается информация о
нем (IP адрес, порт)*/
newsockfd = accept(sockfd, (struct sockaddr *)&party_addr, &party_len);
/*работа с новым клиентом в отдельном процессе*/
if (!fork()) {
close(sockfd); /* этот сокет сыну не нужен*/
len = recv(newsockfd, &buf, BUFLEN, 0);
/*печатаем информацию о клиенте и переданную им строку*/
printf("received string %s from client %s:%d \n", buf, inet_ntoa(party_addr.sin_addr),
ntohs(party_addr.sin_port));
sprintf(buf, "%d", strlen(buf));//
send(newsockfd, buf, strlen(buf) + 1, 0);/*посылаем клиенту ответ=длина полученной строки */
close(newsockfd); /* закрываем сокет */
return 0;
}
/* отец закрывает новый сокет, продолжает прослушивать старый */
close(newsockfd);
} /* конец основного цикла */
}
28. Пример №1 Сетевое взаимодействие через сокеты, с установлением соединения (2)
Рекомендации:1) Запустить программу, реализующую пример на компьютере.
2) Провести и запустить на компьютере модификации программы, реализующей пример,
в части:
добавления контроля и обработки всех возможных ошибок как в коде клиента, так и в
коде сервера;
использования альтернативного средства закрытия сокета;
реализации клиент-сервера в рамках реальной сети (потребуется использование
фактических IP адресов компьютеров).
29. Пример №2 Взаимодействие без предварительного установления соединения (1)
Цель: разработать программную реализацию демонстрации обмена данными всхеме без предварительного установления соединения.
Процесс1:
•создаёт сокет с фиксированным известным именем («целевой» сокет);
•дожидается поступления данных в свой сокет, печатает их и информацию о
сокете-отправителе;
•посылает сокету-отправителю свой pid и завершается.
Процесс2:
•создаёт свой сокет;
•посылает в целевой сокет свой pid;
•дожидается ответа в свой сокет, печатает его и завершается.
30. AF_INET Процесс1
#include <stdio.h>#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define N_PORT 50500
#define BUFLEN 32
/*создание сокета*/
sockfd = socket(AF_INET,SOCK_DGRAM,0);
/*связывание сокета*/
bind(sockfd, (struct sockaddr *)&addr,
sizeof(addr));
/*получение данных*/
len = sizeof(addr);
recvfrom(sockfd, buf, BUFLEN, 0,
(struct sockaddr *) &addr, &len);
int main(int argc, char **argv) {
int sockfd, len;
char buf[BUFLEN];
struct sockaddr_in addr;
/*инициализация структур данных*/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
/*именование своего сокета*/
addr.sin_addr.s_addr =
inet_addr("127.0.0.1");
addr.sin_port = htons(N_PORT + 1);
printf(“from process %s\n", buf);
/*отсылка данных*/
sprintf(buf, "%d", getpid());
sendto(sockfd, buf, strlen(buf) + 1,
0, (struct sockaddr *) &addr, len);
/*освобождение сокета*/
close(sockfd);
return 0;
}
31. AF_INET Процесс2
#include <stdio.h>#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#define N_PORT 50500
#define BUFLEN 32
int main(int argc, char **argv) {
int sockfd;
char buf[BUFLEN];
struct sockaddr_in addr;
/*инициализация структур данных*/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
/*именование своего сокета*/
addr.sin_addr.s_addr =
inet_addr("127.0.0.1");
addr.sin_port = htons(N_PORT);
}
/*создание сокета*/
sockfd=socket(AF_INET,SOCK_DGRAM,0);
/*связывание сокета*/
bind(sockfd, (struct sockaddr *)
&addr, sizeof(addr));
/*именование целевого сокета*/
addr.sin_port = htons(N_PORT + 1);
/*отсылка данных в виде строки-pid*/
sprintf(buf, "%d", getpid());
sendto(sockfd, buf,strlen(buf)+1, 0,
(struct sockaddr *) &addr,
sizeof(addr));
/*получение ответа*/
recvfrom(sockfd, buf, BUFLEN, 0,
NULL, 0);
printf("answer: %s\n", buf);
close(sockfd);/*освобождение сокета*/
return 0;
32. AF_UNIX Процесс1
#include <stdio.h>#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h>
#define SADDRESS "socket"
#define BUFLEN 32
/*создание сокета*/
sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
/*связывание сокета*/
bind(sockfd, (struct sockaddr *)
&addr, sizeof(addr.sun_family)+
strlen(addr.sun_path));
/*получение данных*/
len = sizeof(addr);
recvfrom(sockfd, buf, BUFLEN, 0,
(struct sockaddr *) &addr, &len);
printf("process %s from socket %s \n",
buf, addr.sun_path);
/*отсылка данных*/
sprintf(buf, "%d", getpid());
sendto(sockfd, buf, strlen(buf) + 1,
0, (struct sockaddr *) &addr, len);
/*освобождение сокета*/
close(sockfd);
return 0;
int main(int argc, char **argv) {
int sockfd, len;
char buf[BUFLEN];
struct sockaddr_un addr;
/*инициализация структур данных*/
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
/*именование своего сокета*/
strcpy(addr.sun_path, SADDRESS);
}
33. AF_UNIX Процесс2
#include <stdio.h>/*связывание сокета*/
#include <sys/types.h>
bind(sockfd,(struct sockaddr*)&addr,
#include <sys/socket.h>
sizeof(addr.sun_family)+
#include <sys/un.h>
strlen(addr.sun_path));
#include <stdio.h>
/*именование целевого сокета*/
#include <string.h>
strcpy(addr.sun_path, SADDRESS);
#define SADDRESS "socket"
#define BUFLEN 32
/*отсылка данных в виде строки-pid*/
int main(int argc, char **argv) {
sprintf(buf, "%d", getpid());
sendto(sockfd,buf,strlen(buf)+1, 0,
int sockfd;
(struct sockaddr *)&addr,
char buf[BUFLEN];
sizeof(addr.sun_family)+strlen(SADDRESS));
struct sockaddr_un addr;
/*получение ответа*/
/*инициализация структур данных*/
recvfrom(sockfd, buf, BUFLEN, 0,
memset(&addr, 0, sizeof(addr));
NULL, 0);
addr.sun_family = AF_UNIX;
printf("answer: %s\n", buf);
/*именование своего сокета*/
close(sockfd);/*освобождение сокета*/
strcpy(addr.sun_path,"my_socket");
return 0;
/*создание сокета*/
sockfd=socket(AF_UNIX, SOCK_DGRAM,0); }
34. Пример №2 Взаимодействие без предварительного установления соединения (2)
Рекомендации:1) Запустить оба варианта программы (и в домене AF_UNIX, и в AF_INET),
реализующую пример, на компьютере.
2) Провести и запустить на компьютере модификации программы, реализующей пример,
в части:
•добавления контроля и обработки всех возможных ошибок в коде обоих процессов;
•обеспечения описанной логики взаимодействия процессов вне зависимости от порядка
их запуска.
programming