Первое сообщение UDP на определенный удаленный ip-адрес теряется
Я работаю над решением на основе LAN с "сервером" , который должен контролировать ряд " игроков" Мой протокол выбора UDP, потому что его легко, мне не нужны соединения, мой трафик состоит только из коротких команд время от времени, и я хочу использовать смесь широковещательных сообщений для синхронизации и одиночных целевых сообщений для отдельных команд игрока.
многоадресный TCP был бы альтернативой, но его более сложный, не совсем подходящий для задачи и часто не очень хорошо поддерживается.
к сожалению, я сталкиваюсь со странной проблемой:
теряется первая датаграмма, которая отправляется на определенный ip с помощью "sendto". Любая датаграмма, отправленная через короткое время на тот же ip, будет получена. Но если я подожду некоторое время (несколько минут) первая "отправить" снова проиграл.
широковещательные дейтаграммы всегда работает. Локальные отправки (на тот же компьютер) всегда работают.
Я предполагаю, что операционная система или маршрутизатор / коммутатор имеет некоторую таблицу перевода с IP на MAC-адреса, которая забывается, когда не используется в течение нескольких минут, и это, к сожалению, приводит к потере датаграмм. Я мог наблюдать это поведение с различным оборудованием маршрутизатора/коммутатора, поэтому мой подозреваемый-сетевой уровень windows.
Я знаю, что UDP по определению "ненадежен", но я не могу поверить, что это заходит так далеко, что даже если физическое соединение работает, и все хорошо определенные пакеты могут получить потерянный. Тогда это будет в буквальном смысле бесполезно.
технически я открываю UDP-сокет, привяжите его к порту и INADRR_ANY. Затем я использую "sendto"и " recvfrom". Я никогда не подключаюсь - я не хочу, потому что у меня есть несколько игроков. Насколько я знаю, UDP должен работать без подключения.
мой текущий обходной путь заключается в том, что я регулярно отправляю фиктивные датаграммы всем конкретным игрокам ips - это решает проблему, но ее как-то "неудовлетворительно"!--2-->
вопрос: кто-нибудь знает эту проблему? Откуда она берется? Как я могу ее решить?
изменить:
я сварил его до следующей тестовой программы:
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. Запустите это с wireshark, наблюдая за вашим UDP-трафиком, нажмите клавишу, подождите некоторое время и снова нажмите клавишу. Вам не нужен приемник на удаленном IP, не имеет значения, за исключением того, что вы не получите черные помеченные "недоступные" пакеты. Вот что вы получите:
Как вы можете видеть, первая отправка инициировала поиск ARP для IP. В то время как этот поиск ожидался, первые 2 из 3 последовательных отправлений были потеряны. Второе нажатие клавиши (после завершения IP-поиска) правильно отправило 3 сообщения. Теперь вы можете повторить отправку сообщений, и это будет работать, пока вы не дождетесь (около минуты, пока перевод адреса не получит lost again), то вы снова увидите отсева.
это означает: нет буфера отправки при отправке UDP-сообщений, и есть ARP-запросы в ожидании! Все сообщения теряются, кроме последнего. Также "sendto" не блокируется, пока он не будет успешно доставлен, и нет возврата ошибки!
Ну, это удивляет меня и делает меня немного грустным, потому что это означает, что я должен жить с моим текущим обходным путем или реализовать систему ACK, которая отправляет только один сообщение за раз, а затем ждет ответа - что было бы уже нелегко и подразумевает много трудностей.
4 ответов
Я публикую это долго после того, как на него ответили другие, но это напрямую связано.
Winsock отбрасывает UDP-пакеты, если нет записи ARP для адреса назначения (или шлюза для назначения).
таким образом, вполне вероятно, что некоторые из первых UDP - пакетов будут удалены, поскольку в то время нет записи ARP-и, в отличие от большинства других операционных систем, winsock только очереди 1 пакет, пока запрос ARP завершается.
это документально здесь:
ARP очереди только одна исходящая IP-дейтаграмма для указанного назначения адрес в то время как этот IP-адрес решается на MAC-адрес. Если UDP-приложение отправляет несколько IP-датаграмм в один адрес назначения без каких-либо пауз между ними, некоторые из датаграммы могут быть удалены, если уже нет записи кэша ARP подарок. Приложение может компенсировать это, вызвав Iphlpapi.программы DLL SendArp() в создать запись кэша ARP, прежде чем отправки потока пакетов.
такое же поведение можно наблюдать на Mac OS X и FreeBSD:
когда интерфейс запрашивает сопоставление для адреса не в кэше ARP помещает в очередь сообщение, которое требует отображение и передача сообщения на связанное связанное сеть запрашивает сопоставление адресов. Если ответ при условии, новое сопоставление кэшируется и любое ожидающее сообщение переданный. ARP будет стоять в очереди не более одного пакета во время ожидания для ответа на запрос сопоставления; только самый последний "переданный" пакет сохраняется.
UDP-пакеты должны быть буферизованы при получении, но UDP-пакет (или фрейм ethernet, удерживающий его) может быть удален в нескольких точках на данной машине:
- сетевая карта не имеет достаточно места, чтобы принять его,
- сетевой стек ОС не хватает памяти, чтобы скопировать его в буфер,
- firewall / фильтрация пакетов drop-rule match,
- приложение не прослушивает IP-адрес назначения и порт,
- буфера приема прослушивающий сокет приложения.
первые две точки - это слишком много трафика,что маловероятно здесь. Тогда я доверяю этому пункту 4. не применяется, и ваше программное обеспечение ждет данных. Пункт 5. речь идет о том, что ваше приложение не обрабатывает сетевые данные достаточно быстро - также не похоже на дело.
Перевод между MAC и IP-адресами осуществляется через Протокол Разрешения Адреса. Это не вызывает падение пакета, если ваша сеть правильно настроена.
Я бы отключил Брандмауэр Windows и любое антивирусное / глубокое программное обеспечение для проверки пакетов и проверил, что находится на проводе с помощью Wireshark. Это, скорее всего, укажет вам в правильном направлении - если вы можете понюхать эти первые пакеты на "отправленных" машинах, то проверьте локальную конфигурацию (брандмауэр и т. д.); если нет, то проверьте свою сеть - что-то в пути мешает вашему трафику.
надеюсь, что это помогает.
эээ ..... Его компьютер делает запрос ARP. При первом запуске отправки ваш com не знает mac-адрес получателя, поэтому он не может отправлять какие-либо пакеты. Он использует ip-адрес получателя для выполнения запроса ARP для получения mac-адреса. Во время этого процесса любые udp-пакеты, которые вы пытаетесь отправить, не могут быть отправлены, поскольку MAC-адрес назначения все еще не известен.
Как только ваш com получит mac-адрес, он может начать отправку. Однако mac-адрес будет только оставайтесь в ARP-кэше com в течение 2 минут (если между вами и получателем не обнаружено никаких дальнейших действий) или 10 минут (полностью очищено от кэша ARP, даже если соединение активно). Вот почему вы испытываете эту проблему каждые несколько минут.
кто-нибудь знает эту проблему?
на реальные проблема в том, что вы предположили, что отправка пакетов UDP надежна. Это не так.
тот факт, что вы теряете первый пакет с текущей конфигурацией сети, действительно является вторичной проблемой. Возможно, вы сможете это исправить, но в любой момент Вы все еще уязвимы для потерь пакетов.
Если потеря пакетов является проблемой для вас, то вы действительно должны использовать TCP. Вы можете построить надежный протокол на UDP, но если у вас нет очень веской причины сделать это, это не рекомендуется.