Intereting Posts
матричное умножение в ARM-сборке Это неопределенное поведение в C / C ++ Ошибка репликации Makefile Есть ли функция в c, которая вернет индекс символа в массиве char? Как скомпилировать и запустить файлы C из Notepad ++ с помощью плагина NppExec? Неожиданное поведение при печати массива char в C Найти подмножество размера k таким образом, чтобы минимальное расстояние между значениями было максимальным Config.h – нет такого файла или каталога Возвращаемое значение булевого выражения в C Общее количество возможных треугольников из n чисел Какую справочную карту cscope вы используете? Используя C, я правильно понимаю, что литералы, начинающиеся с нескольких нhive, считаются восьмеричными? c программа для обратных цифр Модули тестирования модhive для кода микроcontrollerа C Генерация гауссовских распределенных случайных чисел в C – как сохранить значения от 0 до 1

Первое сообщение UDP на конкретный удаленный ip теряется

Я работаю над решением на базе локальной сети с «сервером», которому нужно управлять несколькими «игроками». Мой протокол выбора – UDP, потому что его легко, мне не нужны соединения, мой трафик состоит только из коротких команд время от времени и я хочу использовать сочетание широковещательных сообщений для синхронизации и одиночных целевых сообщений для отдельных команд проигрывателя.

Многоадресный TCP был бы альтернативой, но более сложным, не совсем подходящим для задачи и часто не поддерживаемым аппаратным обеспечением.

К сожалению, у меня возникает странная проблема:

Первая датаграмма, которая отправляется на конкретный ip с использованием «sendto», теряется. Любая датаграмма, отправленная короткое время после этого на тот же ip, получена. Но если я подожду какое-то время (несколько минут), то первое «sendto» снова потеряется.

Широковещательные датаграммы всегда работают. Локальные отправки (на тот же компьютер) всегда работают.

Я предполагаю, что операционная система или маршрутизатор / коммутатор имеет некоторую таблицу перевода с IP на MAC-адреса, которые забываются, когда их не используют в течение нескольких минут, и что, к сожалению, приводит к утере датаграмм. Я мог наблюдать это поведение с помощью другого оборудования маршрутизатора / коммутатора, поэтому мой подозреваемый является сетевым слоем Windows.

Я знаю, что UDP по определению является «ненадежным», но я не могу поверить, что это так далеко, что даже если физическое соединение работает и все хорошо определено, пакеты могут потеряться. Тогда это будет буквально бесполезно.

Технически я открываю UDP Socket, привязываю его к порту и INADRR_ANY. Затем я использую «sendto» и «recvfrom». Я никогда не подключаюсь – я не хочу, потому что у меня есть несколько игроков. Насколько я знаю, UDP должен работать без подключения.

Моим текущим обходным путем является то, что я регулярно отправляю фиктивные дейтаграммы всем конкретным игрокам ips – это решает проблему, но ее как-то «неудовлетворительно»,

Вопрос: Кто-нибудь знает эту проблему? Откуда это взялось? Как я могу это решить?

Редактировать:

Я ввернул его в следующую тестовую программу:

int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); SOCKADDR_IN Local = {0}; Local.sin_family = AF_INET; Local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); Local.sin_port = htons(1234); bind(Sock, (SOCKADDR*)&Local, sizeof(Local)); printf("Press any key to send...\n"); int Ret, i = 0; char Buf[4096]; SOCKADDR_IN Remote = {0}; Remote.sin_family = AF_INET; Remote.sin_addr.S_un.S_addr = inet_addr("192.168.1.12"); // Replace this with a valid LAN IP which is not the hosts one Remote.sin_port = htons(1235); while(true) { _getch(); sprintf(Buf, "ping %d", ++i); printf("Multiple sending \"%s\"\n", Buf); // Ret = connect(Sock, (SOCKADDR*)&Remote, sizeof(Remote)); // if (Ret == SOCKET_ERROR) printf("Connect Error!\n", Buf); Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote)); if (Ret != strlen(Buf)) printf("Send Error!\n", Buf); Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote)); if (Ret != strlen(Buf)) printf("Send Error!\n", Buf); Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote)); if (Ret != strlen(Buf)) printf("Send Error!\n", Buf); } return 0; 

Программа открывает UDP-сокет и отправляет по 3 дейтаграммы в строке на каждое нажатие клавиши на определенный IP-адрес. Запустите прокси-сервер, наблюдая за вашим UDP-трафиком, нажмите клавишу, подождите некоторое время и снова нажмите клавишу. Вам не нужен приемник на удаленном IP-адресе, не имеет значения, за исключением того, что вы не получите черные отмеченные «недоступные» пакеты. Это то, что ты получаешь:

Снимок Wireshark

Как вы видите, первая отправка инициировала ARP-поиск для IP-адреса. Пока этот поиск ожидал, первые 2 из трех последовательных отправлений были потеряны. Второе нажатие клавиши (после завершения поиска по IP) правильно отправило 3 сообщения. Теперь вы можете повторить отправку сообщений, и это будет работать до тех пор, пока вы не подождете (примерно через минуту, пока перевод адресата не будет снова потерян), после чего вы снова увидите отсева.

Это означает: при отправке сообщений UDP буфера отправки нет и ожидаются запросы ARP! Все сообщения теряются, кроме последнего. Также «sendto» не блокируется, пока он не будет успешно доставлен, и нет возврата ошибки!

Это меня удивляет, и мне немного грустно, потому что это означает, что я должен жить с моим текущим обходным решением или внедрять систему ACK, которая посылает только одно сообщение, а затем ждет ответа – что будет нелегко больше и подразумевает множество трудностей.

Я публикую это долго после того, как другие получили ответы, но это напрямую связано.

Winsock переносит пакеты UDP, если нет записи ARP для адреса назначения (или шлюза для адресата).

Таким образом, вполне вероятно, что некоторые из первых пакетов UDP упали, так как в то время нет записи ARP – и в отличие от большинства других операционных систем, winsock отправляет только 1 пакет, пока запрос ARP завершается.

Это описано здесь :

ARP ставит в очередь только одну исходящую IP-дейтаграмму для указанного адреса назначения, пока этот IP-адрес разрешается MAC-адресу. Если приложение на основе UDP отправляет несколько IP-дейтаграмм на один адрес назначения без каких-либо пауз между ними, некоторые из датаграмм могут быть удалены, если уже нет записи ARP-кэша. Приложение может компенсировать это, вызывая процедуру IArlpapi.dll SendArp () для установки записи кэша ARP перед отправкой streamа пакетов.

Такое же поведение наблюдается в Mac OS X и FreeBSD :

Когда интерфейс запрашивает сопоставление для адреса, не входящего в кеш, ARP ставит в очередь сообщение, которое требует сопоставления и передает сообщение в связанной с ним сети, запрашивающей адресное сопоставление. Если предоставляется ответ, новое сопоставление кэшируется и передается любое ожидающее сообщение. ARP будет стоять в очереди не более одного пакета, ожидая ответа на запрос сопоставления; сохраняется только последний пакет “ переданный ”.

Предполагается, что UDP-пакеты должны буферизироваться при получении, но пакет UDP (или поддерживающий его Ethernet-порт) может быть сброшен в нескольких точках на заданной машине:

  1. сетевой карте недостаточно места для ее принятия,
  2. Сетевой стек ОС не имеет достаточной буферной памяти для его копирования,
  3. соответствие шаблону фильтрации брандмауэра / пакетной фильтрации,
  4. приложение не прослушивает IP-адрес и порт назначения,
  5. приемный буфер сокета для прослушивания заполнен.

Первые два момента касаются слишком большого количества трафика, что вряд ли имеет место здесь. Тогда я надеюсь, что пункт 4. не применим, и ваше программное обеспечение ожидает данных. В пункте 5. речь идет о том, что ваше приложение недостаточно быстро обрабатывает сетевые данные – также не похоже на это.

Перевод между MAC и IP-адресами осуществляется через протокол разрешения адресов . Это не приводит к отказу пакетов, если ваша сеть настроена правильно.

Я бы отключил брандмауэр Windows и любое антивирусное / глубокое программное обеспечение для проверки пакетов и проверил, что находится на проводе с wirehark . Это, скорее всего, укажет вам в правильном направлении – если вы сможете обнюхать эти первые пакеты на «отправленных» машинах, тогда проверьте локальную конфигурацию (брандмауэр и т. Д.); если вы этого не сделаете, тогда проверьте свою сеть – что-то в пути мешает вашему трафику.

Надеюсь это поможет.

erm ….. Его компьютер делает запрос ARP. Когда вы впервые начинаете отправку, ваш com не знает адрес получателя, поэтому он не может отправлять какие-либо пакеты. Он использует IP-адрес получателя для выполнения запроса ARP для получения адреса mac. Во время этого процесса любые пакеты udp, которые вы пытаетесь отправить, не могут быть отправлены, так как целевой MAC-адрес еще неизвестен.

Как только ваш com получит адрес mac, он может начать отправку. Тем не менее, адрес mac останется только в ARP-кеке com вашего компьютера за 2 минуты (если никаких дальнейших действий не обнаружено между вами и получателем) или 10 минут (полностью очищается от кеша ARP, даже если соединение активно). Вот почему вы испытываете эту проблему каждые несколько минут.

Кто-нибудь знает эту проблему?

Реальная проблема заключается в том, что вы предположили, что отправка пакетов UDP является надежной. Это не так.

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

Если потеря пакетов является для вас проблемой, вы действительно должны использовать TCP. Вы можете создать надежный протокол в UDP, но если у вас нет веских оснований для этого, это не рекомендуется.