21.10. Отправка и получение

21.10. Отправка и получение

Программа для получения анонсов сеанса многоадресной передачи, показанная в предыдущем разделе, могла только получать дейтаграммы многоадресной передачи. Теперь мы создадим простую программу, способную и отправлять, и получать дейтаграммы многоадресной передачи. Наша программа состоит из двух частей. Первая часть отправляет дейтаграмму многоадресной передачи определённой группе каждые 5 с. Эта дейтаграмма содержит имя узла отправителя и идентификатор процесса. Вторая часть программы — это бесконечный цикл, присоединяющийся к той группе, которой первая часть программы отправляет данные. В этом цикле выводится каждая полученная дейтаграмма (содержащая имя узла и идентификатор процесса отправителя). Это позволяет нам запустить программу на множестве узлов в локальной сети и посмотреть, какой узел получает дейтаграммы от каких отправителей.

В листинге 21.8 показана функция main нашей программы.

Листинг 21.8. Создание сокетов, вызов функции fork и запуск отправителя и получателя

//mcast/main.c

 1 #include "unp.h"

 2 void recv_all(int, socklen_t);

 3 void send_all(int. SA *, socklen_t);

 4 int

 5 main(int argc, char **argv)

 6 {

 7  int sendfd, recvfd;

 8  const int on = 1;

 9  socklen_t salen;

10  struct sockaddr *sasend, *sarecv;

11  if (argc != 3)

12   err_quit("usage: sendrecv <IP-multicast-address> <port#>");

13  sendfd = Udp_client(argv[1], argv[2], (void**)&sasend, &salen);

14  recvfd = Socket(sasend->sa_family, SOCK_DGRAM, 0);

15  Setsockopt(recvfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

16  sarecv = Malloc(salen);

17  memcpy(sarecv, sasend, salen);

18  Bind(recvfd, sarecv, salen);

19  Mcast_join(recvfd, sasend, salen, NULL, 0);

20  Mcast_set_loop(sendfd, 0);

21  if (Fork() == 0)

22   recv_all(recvfd, salen); /* дочерний процесс -> получение */

23  send_all(sendfd, sasend, salen); /* родитель -> отправка */

24 }

Мы создаем два сокета, один для отправки и один для получения. Нам нужно, чтобы принимающий сокет связался при помощи функции bind с группой и портом, допустим 239.255.1.2, порт 8888. (Вспомните, что мы могли просто связать универсальный IP-адрес и порт 8888, но связывание с определенным адресом многоадресной передачи предотвращает получение сокетом других дейтаграмм, которые могут прийти на порт получателя 8888.) Далее, нам нужно, чтобы принимающий сокет присоединился к группе. Отправляющий сокет будет отправлять дейтаграммы на этот же адрес многоадресной передачи и этот же порт, то есть на 239.255.1.2, порт 8888. Но если мы попытаемся использовать один сокет и для отправки, и для получения, то адресом отправителя для функции bind будет 239.255.1.2.8888 (здесь используется нотация netstat), а адресом получателя для функции sendto — также 239.255.1.2.8888. Но адрес отправителя, связанный с сокетом, становится IP-адресом отправителя дейтаграммы UDP, a RFC 1122 [10] запрещает дейтаграмме IP иметь IP-адрес отправителя, являющийся адресом многоадресной или широковещательной передачи. (См. также упражнение 21.2.) Следовательно, мы создаем два сокета: один для отправки, другой для получения.

Создание отправляющего сокета

13 Наша функция udp_client создает отправляющий сокет, обрабатывая два аргумента командной строки, которые задают адрес многоадресной передачи и номер порта. Эта функция также возвращает структуру адреса сокета, готовую к вызовам функции sendto, и длину этой структуры.

Создание принимающего сокета и связывание (при помощи функции bind) с адресом многоадресной передачи и портом

14-18 Мы создаем принимающий сокет, используя то же семейство адресов, что и при создании отправляющего сокета, и устанавливаем параметр сокета SO_REUSEADDR, чтобы разрешить множеству экземпляров этой программы одновременно запускаться на узле. Затем мы выделяем в памяти пространство для структуры адреса этого сокета, копируем ее содержимое из структуры адреса отправляющего сокета (адрес и порт которого взяты из аргументов командной строки) и при помощи функции bind связываем адрес многоадресной передачи и порт с принимающим сокетом.

Присоединение к группе и выключение закольцовки

19-20 Мы вызываем нашу функцию mcast_join, чтобы присоединиться к группе на получающем сокете, а также нашу функцию mcast_set_loop, чтобы отключить закольцовку на отправляющем сокете. Для присоединения задаем имя интерфейса в виде пустого указателя и нулевой индекс интерфейса, что указывает ядру на необходимость выбрать интерфейс самостоятельно.

Функция fork и вызов соответствующих функций

21-23 Мы вызываем функцию fork, после чего дочерним процессом становится получающий цикл, а родительским — отправляющий.

Наша функция sendmail, отправляющая по одной дейтаграмме многоадресной передачи каждые 5 с, показана в листинге 21.9. Функция main передает в качестве аргументов дескриптор сокета, указатель на структуру адреса сокета, содержащую адрес получателя многоадресной передачи и порт, и длину структуры.

Листинг 21.9. Отправка дейтаграммы многоадресной передачи каждые 5 с

//mcast/send.c

 1 #include "unp.h"

 2 #include <sys/utsname.h>

 3 #define SENDRATE 5 /* отправка дейтаграмм каждые 5 с */

 4 void

 5 send_all(int sendfd, SA *sadest, socklen_t salen)

 6 {

 7  static char line[MAXLINE]; /* имя узла и идентификатор процесса */

 8  struct utsname myname;

 9  if (uname(&myname) < 0)

10   err_sys("uname error");

11  snprintf(line, sizeof(line), "%s, %d ", myname, nodename, getpid());

12  for (;;) {

13   Sendto(sendfd, line, strlen(line), 0, sadest, salen);

14   sleep(SENDRATE);

15  }

16 }

Получение имени узла и формирование содержимого дейтаграммы

9-11 Мы получаем имя узла из функции uname и создаем строку вывода, содержащую это имя и идентификатор процесса.

Отправка дейтаграммы, переход в режим ожидания

12-15 Мы отправляем дейтаграмму и с помощью функции sleep переходим в состояние ожидания на 5 с.

Функция recv_all, содержащая бесконечный цикл получения, показана в листинге 21.10.

Листинг 21.10. Получение всех дейтаграмм многоадресной передачи для группы, к которой мы присоединились

//mcast/recv.c

 1 #include "unp.h"

 2 void

 3 recv_all(int recvfd, socklen_t salen)

 4 {

 5  int n;

 6  char line[MAXLINE + 1];

 7  socklen_t len;

 8  struct sockaddr *safrom;

 9  safrom = Malloc(salen);

10  for (;;) {

11   len = salen;

12   n = Recvfrom(recvfd, line, MAXLINE, 0, safrom, &len);

13   line[n] = 0; /* завершающий нуль */

14   printf("from %s: %s", Sock_ntop(safrom, len), line);

15  }

16 }

Размещение в памяти структуры адреса сокета

9 При каждом вызове функции recvfrom в памяти выделяется пространство для структуры адреса сокета, в которую записывается адрес отправителя.

Чтение и вывод дейтаграмм

10-15 Каждая дейтаграмма считывается функцией recvfrom, дополняется символом конца строки (то есть нулем) и выводится.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Отправка SMS

Из книги Компьютер + мобильник: эффективное взаимодействие автора Гольцман Виктор Иосифович

Отправка SMS Набирать текст коротких сообщений на клавиатуре компьютера гораздо удобнее, чем на телефоне. Поэтому, находясь рядом со своим компьютером, можно этим воспользоваться. После нажатия кнопки Отправить SMS в главном окне программы на экране компьютера появляется


Отправка SMS

Из книги Skype: бесплатные звонки через Интернет. Начали! автора Гольцман Виктор Иосифович

Отправка SMS Все давно уже привыкли к SMS. В программе Skype сообщения посылаются не только с помощью чата, существует специальная функция отправки SMS. Однако это возможно только для тех контактов, которые содержат номера мобильных телефонов. Для того чтобы иметь возможность


Отправка и получение писем

Из книги Работа в Интернете автора Макарский Дмитрий

Отправка и получение писем Ящик зарегистрирован – самое время начать им пользоваться и написать первое письмо.Думая, кому написать первое письмо, не нужно теряться в догадках, вспоминая адреса почтовых ящиков друзей и знакомых. На тему адресата письма можно задуматься,


Отправка и получение почты в программе Outlook Express

Из книги Системное программирование в среде Windows автора Харт Джонсон М

Отправка и получение почты в программе Outlook Express Работа с письмами в рассматриваемой почтовой программе несложна и не особо отличается от отправки и чтения почты через веб-интерфейс.Создание нового письма начинается с нажатия кнопки Создать, открывающей окно Создать


Отправка и получение данных

Из книги 500 лучших программ для Windows автора Уваров Сергей Сергеевич

Отправка и получение данных Программы, использующие сокеты, обмениваются данными с помощью функций send и recv, прототипы которых почти совпадают (перед указателем буфера функции send помещается модификатор const). Ниже представлен только прототип функции send.  int send(SOCKET s, const char *


Отправка SMS

Из книги Разработка приложений в среде Linux. Второе издание автора Джонсон Майкл К.

Отправка SMS Наличие сотовой связи — несомненный плюс современной жизни. Однако, имея компьютер и доступ в Сеть, можно отправлять SMS на мобильные телефоны с помощью Интернета и некоторых рассматриваемых в этом разделе программ.SMS-ka Производитель Тип ОС Язык Размер,


17.6.2. Отправка и получение дейтаграмм

Из книги Работа в Интернете. Энциклопедия автора Ташков Петр Андреевич

17.6.2. Отправка и получение дейтаграмм Для отправки и получения UDP-пакетов обычно используются четыре системных вызова[141]: send(), sendto(), recv(), recvfrom()[142].#include <sys/types.h>#include <sys/sockets.h>int send(int s, const void * data, size_t len, int flags);int sendto(int s, const void * data, size_t len, int flags, const struct sockaddr * to, socklen_t toLen);int recv(int


Отправка и получение писем

Из книги Социальные сети без страха для тех, кому за... автора Виннер Марина

Отправка и получение писем Ящик зарегистрирован, самое время начать им пользоваться и написать первое письмо.Думая, кому написать первое письмо, не нужно теряться в догадках, вспоминая адреса почтовых ящиков друзей и знакомых. На тему адресата письма можно задуматься,


15.1. Отправка уведомлений

Из книги автора

15.1. Отправка уведомлений Постановка задачи Требуется разграничить части вашего приложения и отправить уведомление, которое может быть подхвачено другим компонентом


Отправка по TCP

Из книги автора

Отправка по TCP Приняв все вышеизложенные термины и определения, посмотрим на рис. 2.15, где показано, что происходит, когда приложение записывает данные в сокет TCP. Рис. 2.15. Этапы записи данных в сокет TCP и буферы, используемые при этой записиУ каждого сокета TCP есть буфер


Отправка по UDP

Из книги автора

Отправка по UDP На рис. 2.16 показано, что происходит, когда приложение записывает данные в сокет UDP. Рис. 2.16. Отправка данных через сокет UDPНа этот раз буфер отправки сокета изображен пунктирными линиями, поскольку он (буфер) на самом деле не существует. У сокета UDP есть размер


Получение, создание и отправка писем

Из книги автора

Получение, создание и отправка писем Чтобы написать письмо в Outlook Express, нужно нажать кнопку Создать сообщение на панели инструментов. Откроется чистый бланк письма, который нужно будет заполнить. Чистый бланк письма, который вы будете заполнятьПоле От заполняется