Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.52/46: Рейтинг темы: голосов - 46, средняя оценка - 4.52
2 / 2 / 0
Регистрация: 06.04.2013
Сообщений: 22

UDP клиент на сокетах - порты, с которых принимает recvfrom

11.07.2013, 16:07. Показов 9571. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Есть вопрос по UDP, постараюсь подробно сформулировать.

Ситуация 1:
На хосте А на порту 666 есть UDP эхо-сервер (возвращающий, что получил, обратно). На хосте Б на порту 667 такой же. На хосте В клиент отправляет ряд датаграмм с помощью sendto по назначениям: АББАББАББ (порты 666 для А и 667 для Б) и затем в бесконечном цикле вызывается recvfrom. Приходят три ответа А и шесть - Б, в перепутанном порядке. В клиенте на хосте В создается сокет, никакие bind не вызываются, сразу sendto.

Ситуация 2:
На хосте А запущен эхо-сервер, который принимает датаграммы на порт 666 и отправляет обратно, но на порт 888. Б и В без изменений. Приходят шесть ответов Б.

Ситуация 3:
На А запущен сервер, отвечающий через 5 секунд, на Б - сразу. Клиент посылает: АБ. Сначала приходит Б, потом А.

Вопрос на миллион - как определить, с каких портов можно получить датаграмму функцией recvfrom?
По второй ситуации можно сделать вывод, что если сначала вызвать sendto на порт X (и, согласно официальным докам, это неявно вызовет bind и привяжет сокет к локальному адресу), то recvfrom затем может получить только с порта X. Но в первой ситуации сначала производится отправка по-очередно на два разных порта, а затем всем скопом выгребаются принятые датаграммы, причем ни одна не теряется и в буфере они находятся вперемешку, полученные на разные порты (ситуация 3 показывает, что не может быть такого, что ответ получен в буфер еще при передаче, до цикла с recvfrom). В то же время bind привязывает сокет только к одному порту, следуя логике выше, в ситуации 3 последним вызывался sendto на Б и ответ с А получен быть не мог. Но, вообще говоря, bind служит для привязывания сетевого интерфейса (ip адреса, если несколько сетевух), но порт, вроде как, тоже надо указывать (по крайней мере во всех виденных примерах это так). sendto что, каким-то образом инициирует порты для приема? Если так, то каким и как это все работает?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
11.07.2013, 16:07
Ответы с готовыми решениями:

Сервер принимает пакеты если клиент указывает неверный порт получателя UDP.
Вот возникла проблема не могу понять почему сервер принимает пакеты если клиент указывает неверный порт получателя UDP. Кто то может...

Recvfrom() не принимает пакеты
Короче говоря в udp-клиенте , когда оставляю его принимать пакеты он просто игнорит всё и считает , что принял пакет. (короче recvfrom()...

UDP Connect не снимает блокировку recvfrom
Как написано у товарища Стивенса, при использовании присоединенного сокета возвращаются асинхронные ошибки. У меня есть клиент, которого...

11
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
11.07.2013, 16:40
Цитата Сообщение от GilAlexander Посмотреть сообщение
как определить, с каких портов можно получить датаграмму функцией recvfrom?
полагаю со всех если искусственно не ограничивать себя при помощи bind. в чем проблема то, что то не работает?

Добавлено через 1 минуту
..т.е. во втором случае у вас куда-то деваются пакеты от А?
0
2 / 2 / 0
Регистрация: 06.04.2013
Сообщений: 22
11.07.2013, 17:42  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
..т.е. во втором случае у вас куда-то деваются пакеты от А?
Да.
В случае TCP, клиент, насколько я понял, не может начать получать данные первым, равно как и сервер (слушающий сокет) не может инициировать передачу первым.
В случае UDP нет слушающих сокетов и соединения не устанавливаются; вообще не понятно, как можно называть что-то клиентом, а что-то сервером. Во всех примерах, что я видел разница только в том, что в серверах делают bind определенного порта, после чего оттуда можно получать датаграммы. Но в силе вопрос про связку sendto/recvfrom - внезапно выяснилось, что можно получать датаграммы сразу с нескольких портов. Непонятен механизм их "окрытия".
0
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
12.07.2013, 09:12
Цитата Сообщение от GilAlexander Посмотреть сообщение
Непонятен механизм их "окрытия"
а его нет. именно поэтому эти функции получают адрес с которого пришел пакет. если иное не задано путем вызова bind (тогда вроде даже можно вызывать send/recv - они будут знать откуда брать, т.е. как бы фильтровать пакеты)
0
2 / 2 / 0
Регистрация: 06.04.2013
Сообщений: 22
12.07.2013, 12:47  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
(тогда вроде даже можно вызывать send/recv - они будут знать откуда брать, т.е. как бы фильтровать пакеты)
Это если сделать connect, явно указав один ip и порт, с которым работать (чтобы не указывать их каждый раз в sendto). Разница в том, что connect фиксирует удаленный интерфейс, а bind - локальный.

Я разобрался. Разгадка такова:
Sendto неявно вызывает bind, привязывая сокет к INADDR_ANY и случайно выбранному свободному порту порядка 50000 (это можно сделать вручную, чтобы порт для приема был известен). Эхо-сервер, описанный в 1 посте, получив на свой 666 порт, отправляет обратно, но не 666 порт клиента, а на этот 50000, вот это я и проглядел. Ответ падает в его буфер (который у каждого порта свой - нельзя слушать больше 1 порта одним сокетом) и забирается recvfrom оттуда (поэтому нельзя вызывать recvfrom до sendto или bind). В ситуации 1 sendto вызывался для двух разных портов - это не важно, потому что локальный порт, с которого все уходило один, фиксированный при первом вызове sendto - 50000, его получали оба эхо-сервера и оба слали обратно на него, поэтому все и доходило.
Если коротко: отправка на 666 порт сервера не осуществляется с локального 666 порта клиента.
1
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
12.07.2013, 13:21
Цитата Сообщение от GilAlexander Посмотреть сообщение
Sendto неявно вызывает bind, привязывая сокет к INADDR_ANY и случайно выбранному свободному порту порядка 50000
однако это странно учитывая то что порт указывается в адресе
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    ...
    WSADATA wsa_data;
    if (WSAStartup(0x101, &wsa_data) || wsa_data.wVersion != 0x101) return -1;
 
    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s == INVALID_SOCKET) return -1;
 
    char buffer[1024];
    int buffer_size = sizeof(buffer);
 
    SOCKADDR_IN sa;
    sa.sin_family = AF_INET;
    sa.sin_port = htons(1024);
    sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
 
    strcpy(buffer, "send to 1024");
 
    if
    (
        sendto
        (
            s,
            buffer, strlen(buffer),
            0,
            (SOCKADDR *)&sa, sizeof(sa)
        ) == SOCKET_ERROR
    )
        return -1;
    ...
0
2 / 2 / 0
Регистрация: 06.04.2013
Сообщений: 22
12.07.2013, 13:29  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
однако это странно учитывая то что порт указывается в адресе
Порт сервера, но не локальный порт, с которого посылает sendto.

Вызовите в конце getsockname, который возвращает, к чему привязан сокет:
C++
1
2
3
int size = sizeof(sa);
getsockname(s, (sockaddr*)&sa, &size);
printf("%d", ntohs(sa.sin_port) );
И увидите локальный порт, с которого произошла отправка.
0
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
12.07.2013, 14:30
Цитата Сообщение от GilAlexander Посмотреть сообщение
Порт сервера, но не локальный порт, с которого посылает sendto.
локальный порт назначается системой и это не является секретом
0
2 / 2 / 0
Регистрация: 06.04.2013
Сообщений: 22
12.07.2013, 14:47  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
локальный порт назначается системой и это не является секретом
Ответ, который приходит от сервера, должен прийти именно на него. Recvfrom в данном случае читает буфер этого порта.
0
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
12.07.2013, 15:10
Цитата Сообщение от GilAlexander Посмотреть сообщение
Ответ, который приходит от сервера, должен прийти именно на него. Recvfrom в данном случае читает буфер этого порта
смысл в том что сервер ммм как бы сам должен знать на какой порт ему будут слать (даже если он не вызывает никаких дополнительных функций). порт в адресе полученном от recvfrom является локальным. сервер не должен считать данный порт портом отправителя. вообще порт отправителя всегда не определен. в TCP сервер подключая клиента видит что ему назначен непонятно какой локальный порт и это нормально ибо клиенты не могут все сидеть на одном порту. в UDP тоже самое. просто технология такая.
0
2 / 2 / 0
Регистрация: 06.04.2013
Сообщений: 22
12.07.2013, 15:26  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
порт в адресе полученном от recvfrom является локальным. сервер не должен считать данный порт портом отправителя. вообще порт отправителя всегда не определен.
Это будет порт, с которого клиент отправил данные на какой-то (другой) порт сервера, который жестко задан и не меняется. Локальный для клиента, на него надо отвечать.
Допустим, браузер шлет запрос на удаленный http сервер на порт 80 со своего порта 54321. Сервер видит, что пришло с такого-то ip с порта 54321, и отправляет страницу туда-же на порт 54321. Порт 54321 слушается браузером, пока не будет убит соответствующий открытый сокет. Клиенту открывать свой порт 80 не надо.
0
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
12.07.2013, 16:08
Цитата Сообщение от GilAlexander Посмотреть сообщение
Это будет порт, с которого клиент отправил данные на какой-то (другой) порт сервера, который жестко задан и не меняется. Локальный для клиента, на него надо отвечать.
Допустим, браузер шлет запрос на удаленный http сервер на порт 80 со своего порта 54321. Сервер видит, что пришло с такого-то ip с порта 54321, и отправляет страницу туда-же на порт 54321. Порт 54321 слушается браузером, пока не будет убит соответствующий открытый сокет. Клиенту открывать свой порт 80 не надо.
все верно. это и имелось ввиду. таким образом - никаких чудес в вашем случае не происходит.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
12.07.2013, 16:08
Помогаю со студенческими работами здесь

Вызовы sento и recvfrom в получении udp пакетов
Код отвечающий за системные вызовы sento и recvfrom %define FAST_MESSAGE_MAX_SIZE 2048 %define SYS_SENDTO 44 %define...

Таймер ожидания для recvfrom (сокеты, UDP)
Как установить таймер ожидания для функции recvfrom?

Асинхронный сервер на UDP-сокетах
Хай. Я как-то писал асинх. сервер с использованием TCP-протокола и все получилось очень круто, потому что там есть понятие соединения, и...

Клиент и сервера на сокетах
Пытаюсь изучить Winsock, вот написал клиент и сервер. Сервер не дожидаясь запроса на подключение закрывается, и клиент тоже закрывается и...

Клиент-сервер на сокетах
Задача стоит в написании некого подобия чата. Получение на сервер работает, но хотелось бы сделать возможность обмена сообщениями...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru