Подтвердить что ты не робот

Ошибка: адрес уже используется во время привязки к сокету с адресом, но номер порта отображается бесплатно с помощью `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$ 
4b9b3361

Ответ 1

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

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

Это может быть очень неприятно, но нет никакого реального пути вокруг него, и это не ошибка.

Ответ 2

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

Ответ 3

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

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

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

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

Ответ 4

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

unlink [SOCKET NAME]

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

Ответ 5

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

В сводке процесс закрытия сокетов приведен ниже:

Socket closing process

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

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

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

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

Ответ 6

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

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

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

Ответ 7

полученная ошибка:

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

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

  • Мне пришлось отключить selinux
  • в службе /usr/lib/systemd/system/cockpit я изменил line:

    #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

Ответ 8

Для AF_UNIX вы можете использовать функцию разблокировки вызова (путь); после подключения close() в приложении "server"