2011-12-05 2 views
3

Основной код последовательности я интересно это (псевдокод)Responsing на ICMP в выберите

sendto(some host); // host may be unreachable for now which is normal 
... 
if(select(readfs, timeout)) // there are some data to read 
    recvfrom(); 

С Win2000, ICMP пакет, который отправляется обратно после отправки UDP датаграммы недостижимым порт, триггеры выбора, после что recvfrom не удается с WSAECONNRESET. Такое поведение нежелательно для меня, потому что я хочу, чтобы в этом случае выбор заканчивался таймаутом (нет данных для чтения). В Windows это можно решить с помощью WSAIoctl SIO_UDP_CONNRESET (http://support.microsoft.com/kb/263823).

Мои вопросы:

  1. ли SIO_UDP_CONNRESET лучший способ в этой ситуации?
  2. Есть ли другие способы игнорировать ICMP для «select» или фильтровать его для recvfrom (возможно, игнорируя ошибку WSAECONNRESET в Windows, рассматривая ее как тайм-аут, может ли эта ошибка срабатывать в другом случае)?
  3. Существуют ли подобные проблемы для Linux и Unix (Solaris, OpenBSD)?
+0

Вы будете использовать соединение только один раз? Если нет, как вы узнаете, когда закрыть соединение, если вы никогда не получите сообщение о том, что соединение больше неактивно и должно быть закрыто? –

+0

Я хочу продолжить отправку дейтаграмм до тех пор, пока удаленный хост (на самом деле это некоторая встроенная система) не встанет или пользователь не прекратит это действие. – Yury

+0

Я ударил эту ошибку при переносе приложения из Linux. В моем случае это неблокирующая передача датаграмм UDP, и я не хочу вообще закрывать соединение, если клиент умирает, я начинаю получать ошибки WSAECONNRESET на recv на сервере! Кажется, ошибка не ясна. Исправлено этим SIO_UDP_CONNRESET, но мне кажется, как ошибка в Winsock. – dashesy

ответ

2

select() «s readfds набор действительно просто сообщает, что read() на сокете не будет блокировать - это ничего не говорит о том, есть или нет фактических данных, доступных для чтения не обещают.

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

В справочной странице select_tut(2) во многих системах Linux есть некоторые рекомендации по правильному использованию select(). Вот несколько правил, которые выглядят наиболее по отношению к вашей ситуации:

1. You should always try to use select() without a timeout. 
     Your program should have nothing to do if there is no 
     data available. Code that depends on timeouts is not 
     usually portable and is difficult to debug. 

    ... 

    3. No file descriptor must be added to any set if you do not 
     intend to check its result after the select() call, and 
     respond appropriately. See next rule. 

    4. After select() returns, all file descriptors in all sets 
     should be checked to see if they are ready. 
+0

Я хочу поддерживать нежное прерывание пользователя (на самом деле этот модуль является лишь небольшой частью программного обеспечения), поэтому я периодически вызываю select с некоторым тайм-аутом и recvfrom, если есть данные. Я хочу читать данные, если они доступны, с минимальным таймаутом, поэтому я не могу использовать сон; с другой стороны, если нет данных, не должно быть никаких накладных расходов. Большое спасибо за ответ, я посмотрю. – Yury

+0

Если пользователь «прерывает» доставляется через сокет, вы можете добавить его к вызову 'select' ... – sarnold

+0

Нет, я имею в виду прерывание (= завершение) из пользовательского интерфейса. Этот код работает в специальном потоке, и этот поток управляется из другого модуля. Конечно, можно жестко завершать поток, но мне нужен тщательный и контролируемый выход (для мьютексов и т. Д.). – Yury