Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Sockets: address already in use


Автор: Rickert 16.3.2007, 07:32
Был открыт сокет на определённом порту, программа работала - работала, потом случилось так, что программе понадобилось открыть новое соединение на этом порту, но предыдущее - закрыть не представляется возможным (данные о дескрипторе сокета отсутствуют). При попытке забиндиться программа вернёт "address already in use" есесно.
Вопрос: как мне закрыть старую сессию знаю порт?
Машина локальная.

Автор: ptr 16.3.2007, 18:49
Цитата(Rickert @  16.3.2007,  10:32 Найти цитируемый пост)
(данные о дескрипторе сокета отсутствуют).

Это как? Про это поподробнее.

Автор: SparF 16.3.2007, 20:24
желательно с кодом

Автор: Dude03 17.3.2007, 12:39
Могу предложить грязненький хак:
можно перебрать все идентификаторы сокетов и для каждого получить порт. Если порт - тот самый - действуем...=)

Автор: Rickert 17.3.2007, 13:41
Цитата(ptr @  16.3.2007,  18:49 Найти цитируемый пост)
Это как? Про это поподробнее.

Был дескриптор, потом, например, программу перезапустили, незакрыв сокет - он остался в системе. Через некоторое время ОСь конечно сама его закроет, но меня интересует возможность закрыть самому.

Автор: Dude03 17.3.2007, 15:59
В винде такой проблемы нету=). Указывай в следующий раз свою операционную систему. smile 

Автор: Rickert 17.3.2007, 17:27
 dude
Альт Линукс

Автор: SparF 17.3.2007, 19:14
Цитата(Rickert @  17.3.2007,  13:41 Найти цитируемый пост)
потом, например, программу перезапустили

ну можно и "ручками" (в смысле - в программе учесть) его закрыть в этот момент

Цитата(Rickert @  17.3.2007,  13:41 Найти цитируемый пост)
незакрыв сокет - он остался в системе. Через некоторое время ОСь конечно сама его закроет

По идее освобождение ресурсов происходит сразу же, при закрытии сокета. Но тут можете сыграть злую шутку tcp - сетевая подсистема будет ждать какого-то события, а потом закроет, наконец, соединение по тайм-ауту. Что говорят
Код

#lsof -i -n -P
#netstat -tua
?
Покажите код, а то на пальцах рассуждаем....

Автор: Rickert 18.3.2007, 07:54
Цитата(SparF @  17.3.2007,  19:14 Найти цитируемый пост)
ну можно и "ручками" (в смысле - в программе учесть) его закрыть в этот момент

В деструкторе есесно всё прописано, но я имею ввиду аварийную принудительную остановку.
Цитата(SparF @  17.3.2007,  19:14 Найти цитируемый пост)
Покажите код, а то на пальцах рассуждаем....

Какую его часть именно? создание сокета? Попытка connect()'а?

Автор: SparF 18.3.2007, 08:34
Цитата(Rickert @  18.3.2007,  07:54 Найти цитируемый пост)
аварийную принудительную остановку

аварийная остановка - это именно аварийная остановка, ситуация экстренная. После нее ядру приходится разгребать все то, что когда-то было процессом.
Но и тут есть свои приколы.
Так, к примеру 
Код

kill pid_процесса

всего навсего посылает процессу сигнал SIGTERM, а на него можно повесить обработчик, который уже будет закрывать соединение и т.д. и т.п., иными словами - грамотно освобождать ресурсы.
Если же прога ну совсем висит, то решение одно:
Код

kill -9 pid_процесса

этот посылает уже SIGKILL, его уже не перехватишь, вот это действительно экстренное завершение. Но такое бывает, только если прога написана некорректно. Решение одно - писать надо так, чтобы не зависало)

Автор: Rickert 18.3.2007, 10:38
Да нет, ты меня не понял. Во время выполнения программы нажимаю ctrl + z и всё.
И вообще - это не имеет значения вопрос-то: как закрыть уже открытый сокет, не имея его дескриптора, но зная порт?

Автор: SparF 18.3.2007, 13:07
Цитата(Rickert @  18.3.2007,  10:38 Найти цитируемый пост)
Во время выполнения программы нажимаю ctrl + z и всё.

Так это не должно завершать процесс. Это просто останавливает его, и убирает в фон! (В случае если используется bash)
man bash
Цитата

To facilitate the implementation of the user interface to job control, the operating  system
       maintains  the notion of a current terminal process group ID.  Members of this process group
       (processes whose process group ID is equal to the current terminal process group ID) receive
       keyboard-generated  signals  such  as  SIGINT.   These processes are said to be in the fore-
       ground.  Background processes are those whose process group ID differs from the  terminal's;
       such  processes  are  immune  to  keyboard-generated signals.  Only foreground processes are
       allowed to read from or write to the terminal.  Background processes which attempt  to  read
       from  (write  to)  the  terminal are sent a SIGTTIN (SIGTTOU) signal by the terminal driver,
       which, unless caught, suspends the process.

       If the operating system on which bash is running supports job control, bash contains facili-
       ties  to  use it.  Typing the suspend character (typically ^Z, Control-Z) while a process is
       running causes that process to be stopped and returns control to bash.
  Typing  the  delayed
       suspend  character  (typically  ^Y,  Control-Y)  causes  the  process  to be stopped when it
       attempts to read input from the terminal, and control to be returned to bash.  The user  may
       then  manipulate  the  state  of  this job, using the bg command to continue it in the back-
       ground, the fg command to continue it in the foreground, or the kill command to kill it.   A
       ^Z  takes  effect  immediately, and has the additional side effect of causing pending output
       and typeahead to be discarded.

А это значит, что процесс остается запущенным (просто остановленным) и занимает сокет на законных основаниях.

Цитата(Rickert @  18.3.2007,  10:38 Найти цитируемый пост)
как закрыть уже открытый сокет, не имея его дескриптора, но зная порт? 

посмотреть какой процесс открыл соединение на данном порту и грохнуть процесс.
Цитата

# netstat -atuwnp

выдаст даст PID, который надо убить)

Автор: Rickert 19.3.2007, 04:46
Нет, ты не прав. Даже грохнув процесс - некоторые сокеты всё равно не могут открыться. "Already in use" и всё.

Автор: ptr 21.3.2007, 18:17
Так господа давайте по-порядку.
Если сокет используется несколькими процессами, то он закроется, только когда его закроет последний процесс. Поэтому, чтобы освободить сокет нужно убить процессы, использующие этот сокет.

Цитата(Rickert @  19.3.2007,  07:46 Найти цитируемый пост)
 Даже грохнув процесс - некоторые сокеты всё равно не могут открыться.

Читаем и просвещаемся про TCP и сокеты, а также про SO_REUSEADDR (setsockopt). Например, в Стивенсе и Снейдере.

Автор: SparF 21.3.2007, 20:18
ptr, за SO_REUSEADDR спасибо -  не знал.
А в это время в манах все русским по белому написано))
man 7 ip
Цитата

...
A TCP local socket address that has been bound is unavailable for some time  after  closing,
unless  the SO_REUSEADDR flag has been set.  Care should be taken when using this flag as it
makes TCP less reliable.
...

man 7 socket
Цитата

...
SO_REUSEADDR
              Indicates that the rules used in validating addresses  supplied  in  a  bind(2)  call
              should  allow  reuse of local addresses. For PF_INET sockets this means that a socket
              may bind, except when there is an active listening socket bound to the address.  When
              the  listening socket is bound to INADDR_ANY with a specific port then it is not pos-
              sible to bind to this port for any local address.
...
       Linux will only allow port re-use with the SO_REUSEADDR option when this option was set both
       in the previous program that performed a bind() to the port and in the program that wants to
       re-use the port.  This differs from some implementations  (e.g.,  FreeBSD)  where  only  the
       later program needs to set the SO_REUSEADDR option.  Typically this difference is invisible,
       since, for example, a server program is designed to always set this option.
...

Автор: ptr 22.3.2007, 10:43
И что?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)