it-roy-ru.com

Ошибка: адрес уже используется при привязке сокета с адресом, но номер порта показывается свободным `netstat`

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

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

[email protected]:~/Desktop/testing$ Sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
[email protected]:~/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      
[email protected]:~/Desktop/testing$ Sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
[email protected]:~/Desktop/testing$ 
47
Durin

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

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

Это может быть раздражающим, чтобы быть уверенным, но нет никакого реального способа обойти это, и это не ошибка.

50
icfantv

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

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

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

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

20
Supamee

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

18
hipe

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

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

 Socket closing process

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

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

Использование SO_REUSEADDR обычно предлагается в Интернете, но Thomas добавляет:

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

6
Jezz

Просто введите

unlink [SOCKET NAME]

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

5
programmer

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

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

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

1
Clock ZHONG

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

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

0
JamesAD-0

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

0
dr_begemot