Не удается назначить запрошенный адрес - возможные причины?

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

Изучив журналы, я обнаружил, что ведомое устройство может отправить только одно обновление статуса на сервер, а затем никогда не может отправить другое обновление, всегда терпя неудачу при вызове connect () «Невозможно назначить запрошенный адрес (99).

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

Чтобы уточнить, вот как я подключаюсь:

struct sockaddr *sa; // parameter
size_t           sa_size; //parameter
int              i = 1;
int              stream;

stream = socket(AF_INET,SOCK_STREAM,0);
setsockopt(stream,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
bindresvport(stream,NULL);
connect(stream,sa,sa_size);

Этот код находится в функции для получения соединения с другим сервером, и сбой любого из этих 4 вызовов приводит к сбою функции.


person dbeer    schedule 03.10.2011    source источник
comment
Я проверил, что порт и IP-адрес верны.   -  person dbeer    schedule 04.10.2011


Ответы (5)


Может быть, здесь поможет SO_REUSEADDR? http://www.unixguide.net/network/socketfaq/4.5.shtml

person Michel    schedule 03.10.2011
comment
SO_REUSEADDR устанавливается для всех подключений. - person dbeer; 04.10.2011
comment
@ dmh2000 dmh2000 - я просмотрел этот пример перед публикацией, и мне не удалось изучить эти факторы. Мне интересно, нужно ли мне просто продолжать искать или есть что-то, что я не принимаю во внимание. - person dbeer; 04.10.2011
comment
Эта функция, о которой вы говорите, выполняется несколько раз? Вы закрываете сокет перед повторным вызовом connect? Можете ли вы объяснить разницу между обновлениями статуса и другими обновлениями в вашем вопросе? Я не понимаю, почему вы говорите... ведомое устройство может отправлять только одно обновление статуса... а затем... ведомое устройство может отправлять несколько других обновлений.... - person Michel; 04.10.2011
comment
@Michel - соединение закрывается сразу после отправки обновления и получения подтверждения о его получении. «Другие обновления» в основном сообщают о задачах, которые сервер попросил выполнить ведомое устройство. Ведомый может связаться с сервером для такого рода отчетов, но не для обновления своего статуса. Это озадачивает. Другие обновления в основном записываются в сокет, открытый с главного сервера, и для этих обновлений подчиненный открывает соединение. - person dbeer; 05.10.2011

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

РЕДАКТИРОВАТЬ: если быть точным, проблемы с обработкой наших сетевых коммуникаций заключались в том, что эти обновления состояния постоянно повторно отправлялись, если первое не удавалось. Это был только вопрос времени, когда каждый распределенный ведомый сервер будет пытаться отправить обновление своего статуса одновременно, что перенасыщало нашу сеть.

person dbeer    schedule 04.10.2011
comment
Я хотел бы уточнить «занято», если это является причиной той же ошибки здесь, в моем собственном коде — вы имеете в виду «сервер, принимающий соединения, имел слишком длинную очередь сокетов, ожидающих accept () для другого соединения с пустить в очередь?» Или другое обстоятельство? Спасибо! - person Brandon Rhodes; 07.03.2013
comment
@BrandonRhodes наша проблема заключалась в том, что у нас были повторные попытки без надлежащего алгоритма отсрочки, поэтому у нас были сотни или более попыток подключения к одному и тому же сокету каждую секунду. Этот спор был причиной нашего провала. Внедрение надлежащего алгоритма отсрочки имело решающее значение для решения этой проблемы. - person dbeer; 07.03.2013

это просто выстрел в темноту: когда вы сначала вызываете соединение без привязки, система выделяет ваш локальный порт, и если у вас есть несколько потоков, соединяющихся и отключающихся, она может попытаться выделить уже используемый порт. исходный файл ядра inet_connection_sock.c намекает на это условие. просто в качестве эксперимента попробуйте сначала выполнить привязку к локальному порту, убедившись, что каждая привязка/подключение использует другой номер локального порта.

person dmh2000    schedule 03.10.2011
comment
Извините, я не смотрел на свой код, когда публиковал это. Я вызываю привязку перед подключением. Я обновлю свой вопрос, чтобы лучше показать, что я делаю. - person dbeer; 04.10.2011

Хорошо, моя проблема была не в порте, а в адресе привязки. У моего сервера есть внутренний адрес (10.0.0.4) и внешний адрес (52.175.223.XX). Когда я попытался подключиться с помощью:

$sock = @stream_socket_server('tcp://52.175.223.XX:123', $errNo, $errStr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN);

Это не удалось, потому что локальный сокет был 10.0.0.4, а не внешний 52.175.223.XX. Вы можете проверить локальные доступные интерфейсы с помощью sudo ifconfig.

person Dallas Clarke    schedule 15.12.2020

person    schedule
comment
Без объяснения этот ответ не имеет никакого значения. - person Pavel Šimerda; 17.06.2016