Ошибка: адрес уже используется при привязке сокета с адресом, но номер порта показывается свободным `netstat` - PullRequest
48 голосов
/ 24 февраля 2011

Я попытался привязать свой сокет (сокет сервера) к номеру порта 8000. Это сработало и сделало работу за меня. В конце кода я также закрываю сокет. В следующий момент я снова запускаю свой код, и он показывает, что адрес уже используется. Я напечатал значение значений ошибок strerror(errno);, чтобы проверить, правильно ли работает мой код в каждой точке. Чтобы проверить, свободен ли порт, я проверил его, используя netstat, но он показывает, что номер порта 8000 свободен. Это случалось со мной много раз. Каждый раз, когда я жду еще несколько секунд, он снова начинает работать. Я использую язык c. Так в чем же причина такого поведения моей ОС.

Через несколько секунд я запускаю код, и затем он работает.

anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1348/lighttpd   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      984/sshd        
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1131/cupsd      
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      1211/mysqld     
tcp6       0      0 :::22                   :::*                    LISTEN      984/sshd        
tcp6       0      0 ::1:631                 :::*                    LISTEN      1131/cupsd      
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ 

Ответы [ 8 ]

52 голосов
/ 24 февраля 2011

Я тоже столкнулся с той же проблемой.Это потому, что вы закрываете соединение с сокетом, а не сам сокет.Сокет может войти в состояние TIME_WAIT (чтобы гарантировать, что все данные были переданы, TCP гарантирует доставку, если это возможно) и может занять до 4 минут для освобождения .

или, для ДЕЙСТВИТЕЛЬНО подробного /техническое объяснение, проверьте эту ссылку

Конечно, это может раздражать, но в действительности это не обходится, и это не ошибка.

21 голосов
/ 16 февраля 2016

Я знаю, что прошло много времени с тех пор, как был задан вопрос, но я смог найти решение:

int sockfd;
int option = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

Это позволяет сразу же повторно использовать сокет.

Я прошу прощения, если это "неправильно". Я не очень опытен с розетками

20 голосов
/ 24 февраля 2011

Попробуйте netstat следующим образом: netstat -ntp, без -l. Это покажет TCP-соединение в TIME_WAIT гос.

6 голосов
/ 05 января 2017

Как уже говорилось, ваш сокет, вероятно, входит в состояние TIME_WAIT. Эта проблема хорошо описана Thomas A. Fine здесь .

Подводя итог, процесс закрытия сокета следует следующей схеме:

Socket closing process

Томас говорит:

Глядя на диаграмму выше, становится ясно, что TIME_WAIT может быть избегать, если удаленный конец инициирует закрытие. Так что сервер может избегайте проблем, позволяя клиенту закрыться первым. Приложение Протокол должен быть разработан так, чтобы клиент знал, когда закрывать. сервер может безопасно закрыться в ответ на EOF от клиента, однако он также должен установить таймаут, когда он ожидает EOF в случае клиент покинул сеть изящно. Во многих случаях просто подождать несколько секунд до закрытия сервера будет достаточно.

Обычно в Интернете рекомендуется использовать SO_REUSEADDR, но Thomas add:

Как ни странно, использование SO_REUSEADDR может на самом деле привести к более сложному адресу «уже используется». SO_REUSADDR позволяет использовать порт, который застрял в TIME_WAIT, но вы все еще не можете использовать этот порт для установки подключение к последнему месту, к которому он подключен. Какие? Предположим, я выбираю локальный порт 1010, и подключитесь к порту 300 foobar.com, а затем закройте локально, выходя из этого порта в TIME_WAIT. Я могу повторно использовать локальный порт 1010 сразу для подключения в любом месте, кроме foobar.com порт 300.

6 голосов
/ 14 апреля 2013

Просто наберите

unlink [SOCKET NAME]

в терминале, тогда ошибка больше не должна существовать.

1 голос
/ 01 октября 2015

Даже ответ icfantv на этот вопрос уже совершенен, у меня все еще есть больше результатов в моем тесте.

Как сокет сервера в состоянии прослушивания, если он только в состоянии прослушивания и даже принимает запросы и получает данные со стороны клиента, но без каких-либо действий по отправке данных. Мы все еще можем перезагрузить сервер сразу после его остановки. Но если какое-либо действие по отправке данных происходит на стороне сервера с клиентом, при перезапуске той же службы (с тем же портом) будет эта ошибка: (Адрес уже используется).

Я думаю, что это связано с принципами проектирования TCP / IP. Когда сервер отправляет данные обратно клиенту, он должен обеспечить успешную отправку данных. Для этого ОС (Linux) необходимо контролировать соединение, даже если приложение сервера закрыло этот сокет. Но я все еще верю, что конструктор сокетов ядра мог бы решить эту проблему.

0 голосов
/ 12 декабря 2017

Для AF_UNIX вы можете использовать call unlink (path);после сокета close () в приложении "сервер"

0 голосов
/ 12 декабря 2016

ошибка, которую я получил:

cockpit.socket: Failed to listen on sockets: Address already in use

обнаруженное мной исправление:

  1. Мне пришлось отключить selinux
  2. в / usr/ lib / systemd / system / cockpit service я изменил строку:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t
    

    на:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws 
    

, чтобы вы могли видеть, что я убрал аргументо selinux, тогда я запустил:

systemctl daemon-reload
systemctl start cockpit.service

, затем я просмотрел:

Я принял самозаверяющий сертификат и смог успешно войти в кабину и нормально его использовать.

это все на машине fedora25.порт 9090 уже был добавлен с использованием firewall-cmd

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