LINUX.ORG.RU

Как правильно закрывать сокетное соединение?


0

0

Здравствуйте!

Вопрос такой: имеется приложение-сервер, слушает сетевые запросы с помощью сокета. Сокет создается (socket), привязывается к хосту и порту (bind), включается прослушка (listen) и отменяется блокирование (через fcntl ставится O_NONBLOCK), чтобы accept в случае отсутствия запросов не блокировал работу приложения (есть работа кроме слушания).

Соответственно, при подключении клиента создается новый сокет, из него чего-то читается, в него чего-то пишется, потом он закрывается. На стороне сервера. Чтобы клиент не ждал вечно новых сообщений от сервера, мне приходится делать shutdown для сокета - это нормально? Пробовал от сервера слать EOF, закрывать close'ом - клиент все равно ждал до бесконечности.

Далее. Когда я прибиваю сервер и пытаюсь запустить его по новой, bind отваливается с кодом ошибки EINVAL (в руководстве расшифровка - "сокет уже привязан к этому адресу"). Если подождать некоторое время, то вновь становится возможным запускать сервер на тот же хост/порт.

Прибиваю сервер я сигналом SIG_TERM, а обработчик написать поленился и, соответственно, close для сокета не делаю. Проблема в этом? Разве при завершении процесса его ресурсы не должны освобождаться сами?

anonymous

Re: Как правильно закрывать сокетное соединение?

Понятия сокетное соединение не существует
выражайся коректнее о каком протоколе идет речь,
когда у тебя подключен клиент и на серваке ты делаешь close(sd)
система посылает клиенту ресет и клиент это должен видеть
если конешно связь не нарушена, проверь правильно ли ты отслеживаешь
состояние сокета на клиенте.
когда SIG_KILL тогда освобождется все...
всунуть в обработчик пару close(sd) не так трудно не ленись

anonymous ()

Re: Как правильно закрывать сокетное соединение?

close() надо делать в любом случае

anonymous ()

Re: Как правильно закрывать сокетное соединение?

> Чтобы клиент не ждал вечно новых сообщений от сервера, мне приходится
> делать shutdown для сокета - это нормально?

shutdown() закрывает канал, close() - файл. если больше ссылок
на этот файл нету, close() влечет shutdown(). раз close()
недостаточно - значит, где-то еще есть дескриптор, ссылающийся
на этот файл. например, после accept() вы делаете fork(), и
parent process не закрыл созданный socket.

> Пробовал от сервера слать EOF,

это что значит ?????

> Когда я прибиваю сервер и пытаюсь запустить его по новой, bind
> отваливается с кодом ошибки EINVAL

SO_REUSEADDR перед bind().

> когда SIG_KILL тогда освобождется все...

нет. абсолютно все равно, по какой причине завершается
процесс, разницы в освобождении ресурсов никакой.

idle ★★★★★ ()

Re: Re: Как правильно закрывать сокетное соединение?

Спасибо за ответы!

>>shutdown() закрывает канал, close() - файл. если больше ссылок на этот файл нету, close() влечет shutdown(). раз close() недостаточно - значит, где-то еще есть дескриптор, ссылающийся на этот файл. например, после accept() вы делаете fork(), и parent process не закрыл созданный socket.

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

>>это что значит ?????

Ну, я работаю с каналом как с файлом, C-шными функциями (переоткрываю его fdopen'ом) и пробовал записывать в поток символ конца файла, в надежде, что клиент посчитает это "концом канала" (там у меня есть проверка на EOF).

>>SO_REUSEADDR перед bind()

А почему при завершении процесса привязка не освобождается? Разве это не ресурс процесса?

anonymous ()

Re: Re: Re: Как правильно закрывать сокетное соединение?

>SO_REUSEADDR перед bind()

>А почему при завершении процесса привязка не освобождается? Разве это не ресурс процесса?

Так уж сложилось. Без этого флажка ресурс будет освобожден, но через длительное время.

Dead ★★★★ ()

Re: Re: Re: Как правильно закрывать сокетное соединение?

> пробовал записывать в поток символ конца файла, в надежде, что
> клиент посчитает это "концом канала"

ну вы даете. EOF может работать только с функциями типа getc()
потому, что они по семантике возвращают char, а тип возврата
у них int. поэтому EOF == -1 не может быть "спутан" ни с каким
символом данных. учите С!

> > SO_REUSEADDR перед bind()
>
> А почему при завершении процесса привязка не освобождается?
> Разве это не ресурс процесса?

освобождается. SO_REUSEADDR влияет не на освобождение ресурсов,
а на поведение bind(). после того, как соедининение закрыто
(процессом, или в результате завершения процесса) оно принадлежит
ядру, и будет находиться 60 сек (кажется) в состоянии TIME_WAIT.
в течение этого времени попытка сделать bind() на этот порт
не будет работать без SO_REUSEADDR.

idle ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.