2009-12-18 3 views
5

Я пытаюсь избежать TIME_WAIT в клиенте. Я подключаюсь, а затем устанавливаю O_NONBLOCK и SO_REUSEADDR. Я вызываю read, пока не вернет 0. Когда read возвращает 0, errno также равно 0. Я интерпретировал это как знак того, что сервер закрыл соединение. Однако, если я позвоню близко, сокет устанавливается в TIME_WAIT, что подтверждается netstat.Избегайте TIME_WAIT

Поскольку я делаю несколько соединений с одним и тем же хостом/портом, я в конечном итоге начинаю видеть ошибки «Адрес в использовании» (см. http://hea-www.harvard.edu/~fine/Tech/addrinuse.html).

Должен ли я быть вызван close после того, как прочитанный возвращает 0? Если я не напишу дескриптор файла?

+0

Sidenote: значение ERRNO неопределен при считывании возвращает 0 - ERRNO определяется только после сбоя. –

ответ

5

Сторона, которая инициировала закрытие соединения, является той, которая заканчивается в состоянии TIME_WAIT. read() Возврат 0 должен указывать, что сервер сначала закрыл сокет, поэтому да - это должно означать, что TIME_WAIT заканчивается на стороне сервера, а клиент проходит через LAST_ACK.

В конце дня вы не можете избежать состояния TIME_WAIT. Даже если вам удастся перенести его с клиента на сервер, вы все равно не сможете повторно использовать этот кортеж (server host, server port, client host, client port) до тех пор, пока не закончится TIME_WAIT (независимо от того, на какой стороне он включен).

Поскольку три части этого кортежа фиксируются в вашем сценарии (server host, server port, client host), вы на самом деле есть только эти варианты:

  • Попробуйте сделать несколько клиентских портов. Некоторые операционные системы используют только небольшой диапазон доступных портов для «эфемерных портов» по ​​умолчанию (я не уверен в OSX в этом отношении). Если это так, посмотрите, можете ли вы изменить диапазон с настройкой конфигурации в ОС или, альтернативно, запустить приложение для рабочего порта с bind()/connect() в цикле до тех пор, пока соединение не будет работать.

  • Развернуть число доступных client host значений, используя несколько IP-адресов на вашем клиенте. Однако вам нужно иметь приложение bind() на один из этих IP-адресов.

  • Расширение количества доступных server host/server port значений с использованием нескольких портов и/или IP-адресов на сервере. Клиенту нужно будет выбрать один для подключения (циклический, случайный и т. Д.).

  • Возможно, лучший вариант, если это выполнимо: отредактируйте свой протокол, чтобы завершившиеся соединения не были закрыты, но переходите в «незанятое» состояние, чтобы их можно было повторно использовать позже, вместо того чтобы открывать новое соединение (например, HTTP keep-alive).

+0

Извините, что прокомментировал старый вопрос, но не должен в первом абзаце этого ответа читать «сторона, в которой ИНИЦИИРОВАЛ закрытие соединения, которое заканчивается в состоянии TIME_WAIT»? Кажется, я помню, что прочитал, что в какой-то книге, а также, похоже, что подразумевается в http://hea-www.harvard.edu/~fine/Tech/addrinuse.html – zentrunix

+0

@ JoséX .: Да, re право. – caf

1

Позже на той же странице упоминается SO_REUSEADDR. Это то, что вам нужно. Вы обязательно хотите закрыть дескриптор прочитанного файла, когда он возвращает нуль.

+0

Извините. Я забыл добавить, что я устанавливаю SO_REUSEADDR. См. В статье, что он не предотвращает ошибки использования Адреса при подключении к одному и тому же порту/хосту. – richcollins

0

Установка SO_REUSEADDR на стороне клиента не помогает на стороне сервера, если он также не устанавливает SO_REUSEADDR

Смежные вопросы