+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 91.69 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

Интерфейс прикладного программирования Socket API, Часть 4: Датаграммы"

20.07.2012 13:45
Н.Ромоданов

Оригинал: "The Socket API, Part 4: Datagrams " 
Автор: Pankaj Tanwar 
Дата публикации: November 1, 2011 
Перевод: Н.Ромоданов 
Дата перевода: июль 2012 г.

Давайте попробуем разработать клиентские программы для серверов, использующие протокол UDP - протокол, лежащий в основе некоторых важных сервисов, таких как DNS, NFS и т.д.

Протокол UDP, User Datagram Protocol - протокол пользовательских датаграмм, является протоколом без установления соединения. Это означает, что вы перед тем, как начать передачу данных (например, тройного подтверждения для TCP), соединение не устанавливаете; вы просто отправляете данные в виде датаграммы на требуемый адрес. Именно поэтому мы называем этот протокол ненадежным, поскольку мы не знаем или нам все равно, достигла ли датаграмма получателя или нет.

Код

Теперь, давайте, как мы обычно это делаем, перейдем к программе. Код в этой статье представляет собой модифицированную версию эхо-программ сервера/клиентов, взятых из книги UNIX Network Programming by Stevens et al (Сетевое программирование для UNIX, Стивенс и др.). Этот файл с именем udpserver.c:

#include <stdio.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
 
int main()
{
    int sfd, n;
    socklen_t len;
    char line[128];
    struct sockaddr_in saddr, caddr;
 
    sfd = socket(AF_INET, SOCK_DGRAM, 0);   
 
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(2910);
 
    bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr));
 
    printf("Server running\n");
    for(;;) {
        len=sizeof(caddr);
        n=recvfrom(sfd, line, 128, 0, (struct sockaddr *)&caddr, &len);
        sendto(sfd, line, n, 0, (struct sockaddr *)&caddr, len);
    }
 
    return 0;
}

Этот код почти похож на предыдущий; давайте рассмотрим различия. Во-первых, вызов socket(): SOCK_STREAM для TCP/SCTP заменяется на SOCK_DGRAM. Затем мы делали связывание bind() с адресом и портом, и сервер был готов к приему данных от клиента (которые в конкретном случае были просто текстом, который помещается в один пакет).

Далее вы видите, что вызов listen() отсутствует. Вместо этого вы с помощью команды recvform() ожидаете приема данных и когда вы их получаете, вы с помощью sendto() отправляете эти данные обратно клиенту в виде эхо-ответа.

Прежде, чем подробнее рассматривать эти функции, обратите внимание на то, что в вашем сервере для обслуживания каждого из запросов не используется функция fork() - запросы обслуживаются в итеративном режиме в бесконечном цикле. Это объясняется тем, что в протоколе TCP вы должны поддерживать связь с каждым клиентом, а для это требуются отдельные потоки; в протоколе UDP вы каждый раз просто отвечаете одному клиенту и вам не нужно на следующей итерации принимать данные от этого клиента.

Таким образом, вы видите, что на сервере нам нужен буфер, в котором данные, поступающие от клиентов, будут запоминаться в виде очереди с обслуживанием вида "первым пришел - первым обслужили". В большинстве серверов TCP используется параллельная обработка, а в серверах UDP - итеративная.

Отсылка и прием данных

Давайте рассмотрим новые функции, используемые для датаграмм; сначала функция recvfrom():

#include <sys/socket.h>
ssize_t recvfrom (int sockfd, void *buf, size_t nbytes,
    int flags, struct sockaddr *from, socklen_t *addrlen);

Эта функция блокирует сервер до тех пор, пока не получит некоторые данные в sockfd из адреса, указанного в аргументе *from и не запишет nbytes байтов в буфер *buf. Аргумент flags формируется с помощью операции ИЛИ (OR) над одним или несколькими значениями, но мы не используем его, так что он равен 0. Последний аргумент, *addrlen, является указателем на размер структуры, содержащей адрес сокета.

Теперь отправим данные с помощью sendto():

#include <sys/socket.h>
ssize_t sendto (int sockfd, const void *buf, size_t nbytes,
    int flags, const struct sockaddr *to, socklen_t addrlen);

Эта функция отправляет данные из буфера *buf в количестве, равном nbytes байтов, через сокет sockfd по адресу, который хранится в структуре *to. Ее размер составляет addrlen, и нужно отметить, что это не ссылка, как это было в recvfrom(). Аргумент flags точно такой же, как и в recvfrom(). Обе функции возвращают количество прочитанных/записанных байтов.

А код для клиентской программы udpclient.c выглядит следующим образом:

/**
 
#include 
 
ssize_t recvfrom (int sockfd, void *buff, size_t nbytes,
    int flags, struct sockaddr *from, socklen_t *addrlen);
 
ssize_t sendto (int sockfd, const void *buff, size_t nbytes,
    int flags, const struct sockaddr *to, socklen_t addrlen);
 
**/
 
 
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#define MAX 100
 
int main(int argc, char** argv)
{
    int sfd, n;
    socklen_t len;
    char sline[MAX], rline[MAX+1];
    struct sockaddr_in saddr;
 
    if(argc!=2) {
        printf("Usage: %s ipaddress\n", argv[0]);
        return -1;
    }
 
    sfd = socket(AF_INET, SOCK_DGRAM, 0);   
 
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &saddr.sin_addr);
    saddr.sin_port = htons(2910);
 
    printf("Client Running\n");
    while(fgets(sline, MAX, stdin)!=NULL) {
        len=sizeof(saddr);
        sendto(sfd, sline, strlen(sline), 0, (struct sockaddr *)&saddr, len);
        n=recvfrom(sfd, rline, MAX, 0, NULL, NULL);
        rline[n]=0;
        fputs(rline, stdout);
    }
 
    return 0;
}

Клиентская программа очень проста - она с помощью команды sendto() просто пересылает строку, прочитанную из стандартного ввода, на сервер и читает ответ от сервера с помощью команды recvfrom().

Здесь не указывается ни адрес, ни порт, откуда вы получаете данные, поэтому любой случайный клиент/сервер, если он знает номер порта, присвоенный вашему клиенту, может передавать вам данные. Если вы заинтересованы в ответах от конкретного сервера, вы можете сохранить структуру, возвращаемую изrecvfrom(), и сравнить ее со структурой, которая используется в sendto().

Это может быть проблемой в случае, если ваш сервер находится в нескольких сетях (с несколькими IP-адресами), и сервер не связывается с адресом так, как мы это обычно делали с помощью INADDR_ANY.

Рис.1: Запуск сервера

Рис.2: Работа клиентской программы

Перед тем как завершить, давайте взглянем на некоторые проблемы, касающиеся протокола UDP.

Во-первых, никак нельзя узнать, достигли ли ваши датаграммы получателя. Вы не можете узнать, был ли потерян запрос или ответ. Для сервера это нормально, но ваш клиент может продолжать ожидать ответа. В этом случае, вы можете в вызове recvfrom задать тайм-аут для того, чтобы не ждать вечно.

И здесь, я заканчиваю статью, подписавшись с моим обычным "FOSS - это круто!"

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года