LINUX.ORG.RU

Закрыть сокет после fork()'a


0

0

В общем, проблема закрытия сокета.
Программа слушает порт:

listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int x = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
и т.д.

при коннекте, получает дескриптор:
clientfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);

потом clientfd передается процессу, запущенному через fork().
он его пытается закрыть через close(clientfd). Результат - состояние "CLOSE_WAIT" соединения.

Как я понимаю, close(clientfd) не работает из-за fork()'a. Если запустить fork() в родительском потоке - все нормально закроется.
Я читал про то, что дочерный процесс не может изменять данные родителя - ядро ему делает только копию родителя. Но, если у него копия данных родителя, то почему не работает системный вызов ? Ведь, номер дескриптора не изменился.

Возможно ли в принципе закрыть сокет, который был передан родительским процессом дочерному ?


Что-то не въехал в объяснения...

Если закроешь оба дескриптора, то соединение оборвется. Если один останется, то и соединение останется. И fork() тут не при чем, можешь просто дескриптор сдублировать.

> Но, если у него копия данных родителя, то почему не работает системный вызов ? Ведь, номер дескриптора не изменился.

Если ты передал дескриптор дочке, открытый _после_ форка, то его номер может измениться.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>>Если закроешь оба дескриптора, то соединение оборвется.

в том то и дело, что на стороне клиента сокет зыкрывается правильно, а со стороны дочерного процесса - нет, т.е. как будто дочерный процесс не вызывал close(fd)

>>Если ты передал дескриптор дочке, открытый _после_ форка, то его номер может измениться.

дескриптор "открываю" до форка.

nial
() автор топика
Ответ на: комментарий от Die-Hard

2Die-Hard:

istenfd = socket()

clientfd = accept(istenfd)

if(fork())
close(clientfd);
else
...;

Вот как раз close(clientfd); у дочки и не работает.
Если вместо дочки родитель будет закрывать сокет - все ОК

Логика как раз такая.

nial
() автор топика
Ответ на: комментарий от roller

>>shutdown - не катит.

Если вы зададите мне вопрос, а почему бы родителю не закрывать сокет, отвечу: у меня чет типа сервера: много дочерных потоков, и родителю не известно когда дочка закончит "болтать".
Она может узнать что дочка закончила работу через сигнал SIGCHLD (сигнал когда дочерный поток зывершился), но какой сокет был у дочки я не могу знать, т.е. я не могу идентифицировать дочку - она ведь не может изменять область данных родителя со своей стороны !

nial
() автор топика
Ответ на: комментарий от nial

> Если вы зададите мне вопрос, а почему бы родителю не закрывать сокет, отвечу: у меня чет типа сервера: много дочерных потоков, и родителю не известно когда дочка закончит "болтать".

в качестве домашнего задания:
1) что произойдёт, если после вызова fork() родительский процесс закроет дескриптор, полученный из accept() через close() ?
2) -//- но вызовет shutdown() перед close()?

правильно решив домашнее задание вы сами ответите на свой вопрос.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от nial

2nial:

> ...у меня чет типа сервера: много дочерных потоков, и родителю не известно когда дочка закончит "болтать".

Ну, я примерно так и думал.

Я бы прислушался к совету klalafuda (22.09.2005 10:41:05)

Die-Hard ★★★★★
()
Ответ на: комментарий от klalafuda

1) что произойдёт, если после вызова fork() родительский процесс закроет дескриптор, полученный из accept() через close() ?

то что я и хотел )
спасибо.

2) -//- но вызовет shutdown() перед close()?
сокет, на который ссылается переданный дочерному процессу дескриптор, будет "закрыт" родительским процессом.

как я понял, close() в первом примере не закрывает сокет потому что он "активен" ?
а shutdown() во втором примере делает свое дело не обращая внимание на открытый сокет ?

тогда, если можно, вопрос: есть ли смылсл в close(), если мы говорим о сетевых сокетах ?

nial
() автор топика
Ответ на: комментарий от nial

>тогда, если можно, вопрос: есть ли смылсл в close(), если мы говорим о сетевых сокетах ?

да - освобождаются ресурсы ядра.

cvv ★★★★★
()
Ответ на: комментарий от cvv

В общем, насколько я понял, на конкретное соединение может указывать несколько сокетов. close() только закрывает сокет, но не соединение. Соединение закрывается только если close() закрывает последний сокет при вязанный к нему. А shutdown() действует именно на соединение, т.е. принудительно его обрывает.

Все верно?

UncleAndy ★★★
()
Ответ на: комментарий от UncleAndy

UncleAndy :

> close() только закрывает сокет, но не соединение. Соединение закрывается только если close() закрывает последний сокет при вязанный к нему.

Верно

> А shutdown() действует именно на соединение, т.е. принудительно его обрывает.

Не совсем.

shutdown() -- более гибкий механизм разрыва соединения, там еще есть флажок, какую линию разрывать ( туда, сюда или обе, men 2 shutdown).

А ресурсы только close() освобождает.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>close() только закрывает сокет, но не соединение.

а может просто освобождает файловый дескриптор а soсket один на соединение???

cvv ★★★★★
()
Ответ на: комментарий от Die-Hard

>Буквоед! :-)

вы имели ввиду что я придрался??

вообщето одному соединению может соответсвовать несколько сокетов каждому из которых может соответсвовать несколько файловых дескрипторов.

насколько я помню fork() сокеты не размножает а только привязывает к сокету ещё один файловый дескриптор.

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