LINUX.ORG.RU

сокеты и wait()


0

0

Возникла следующая проблема: Есть сервер, который создаёт кучу сокетов и ждёт соединений. Данные о параметрах соединений загружаются при старте сервера, создаются сокеты и сервер ждёт. При старте сервер создаёт дочерний процесс. Параметры соединений могут быть изменены, и сервер должен перезапустится: закрыть сокеты, вновь загрузить параметры, вновь создать сокеты.

Вот в чём проблема: если я убиваю дочерний процесс, далее wait(&status); то всё нормально: сокеты вновь создаются и всё работает, но если я не убиваю дочерний процесс, а просто закрываю сокеты, потом их вновь создаю, то вылезает ошибка при вызове bind: perror выводит: Address already in use. То есть порт занят. Но ведь я закрыл сокет! Даже shutdown(sock, SHUT_RDWR) вызвал для него!

Вопрос: как правильно освободить сокет, что бы его можно было сразу же создать, не используя wait

anonymous

1. setsockopt(...SO_REUSEADDR...) -- может, хватит, если shutdown() сделал; не уверен

2. А дочка дескриптор закрыла?

Die-Hard ★★★★★
()

почитай архив. тема не раз обсуждалась.

решается флагами кажись для socket()

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

Дочка сокет не закрывает, но и не использует эти сокеты (создаёт другой). Как я понял, close закрывает сокет и для дочерних процессов. Сейчас попробую setsockopt...

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

anonymous (*) (23.09.2005 15:19:43):

> Как я понял, close закрывает сокет и для дочерних процессов

Без shutdown -- ни разу.

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

Это опять я. Не помогает setsockopt! Вставил в код следующие строки: int sval=0; ......... if((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sval, 4))<0) perror("setsockopt");

тот же глюк

закрытие сокетов частично помогло: Теперь сервер перезапускается при отсутствии соединений, но как только клиент соединяется с к-л портом, всё, порт занят, и при перезапуске блокируется. Хотя я его закрываю.

Получается вот что: пока к сокету не обратились, он перезапускается, после обращения - блокируется.

P.S. Я не мог наврать в setsockopt?

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

anonymous (*) (23.09.2005 17:07:16)

>Я не мог наврать в setsockopt?

Правильно (только за "&sval, 4" надо кое-что отрывать! )

Давай сюда логику поподробнее

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

функция создаёт серверный сокет (здесь возникает ошибка bind):

int sock;
struct sockaddr_in echoServAddr;
int sval=0;

if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
ErrorExit("socket() failed");

....
здесь устанавливаем поля структуры
....

if((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sval, 4))<0) perror("setsockopt");
.....

if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
{
fprintf(stderr, "%d", port);
ErrorExit("bind() failed");
}

далее listen, он работает нормально
}

в main при коннекте порождаются процессы:
for (arm = 0; arm < aset.armcount; arm++)
if (FD_ISSET((aset.armarray)[arm].servSock, &sockSet))
{
if ((processID = fork()) < 0)ErrorExit("fork() failed");
else if (processID == 0)
{
HandleClient(&((aset.armarray)[arm]));
exit(0);
}
}

В HandleClient
вызываем accept, получаем clientSock, работаем с ним, закрываем
серверный сокет не трогаем. Я убрал закрытие сокетов в дочерних процессах - ничего не изменилось. Наверное, не в close дело...


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

Поправил:
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sval, sizeof(int)))
В дочернем процессе я закрываю теперь все сокеты, но это не помогает после подключениия клиента
Не помог даже wait4 - пытался собрать все pid в массив, в цикле вызывать wait4:

for (i= 0; i < proc_count; i++){
wait4(Array_ID[proc_count], &status, WNOHANG, NULL);
}
free(Array_ID);
Array_ID=NULL;
proc_count=0;

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

2anonymous (23.09.2005 19:23:44)

Я тоже скоро ухожу, и, наверное, до понедельника.

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

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

Проверь, что дочка точно закрывает сокеты (через /proc/PID/fd).

Посмотри netstat'ом состояние создоваемых тобой сокетов.

Может в цикле перестарта демона попробовать ввести задержку?

>в main при коннекте порождаются процессы

В этих процессах, вроде надо тоже закрывать лишние сокеты...

Насчет wait4(), ИМХО лучше делать wait4(-1) и если wait4() сказал, что процесс завершился, искать его pid в Array_ID.

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

Для дочки в /proc/PID/fd нет доступа, она всё закрывает, но кажется не в этом дело.
Вот что выяснил: если просканировать порты (пользовался Nmap), то порождается куча дочерних процессов, но сервер перезапускается, при том, что дочерние процессы при этом ничего не закрывают.
Порт блокируется, если использовался для передачи данных, даже если был закрыт.

if ((processID = fork()) < 0)ErrorExit("fork() failed");
else if (processID == 0) /* If this is the child process */
{
printf("Request on port %d: ", (aset.armarray)[arm].client_port);
HandleClient(&((aset.armarray)[arm])); - вылетает при сканировании
close(resetSock);
for (arm = 0; arm < aset.armcount; arm++)
{
close((aset.armarray)[arm].servSock);
}
exit(0); /* Child process terminates */

Вылетает из-за этого:
access_flag=access_flag & AcceptTCPSocket(arm_data);
if(access_flag) access_flag=access_flag & check_MAC(arm_data);
if (access_flag) answptr=answstr7;
else {
answptr=answstr8;
printf(answptr);
}
send_data((*arm_data).clientSock, answptr);

В функции send_data выполняется exit, если send не выполнен
Вопрос: что происходит с сокетом после использования?
Он не отцепляется от порта даже после закрытия

anonymous
()
Ответ на: комментарий от mky

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

/* Create port socket */
i=0;
while(1)
{
(aset.armarray)[arm].servSock = CreateTCPServerSocket((aset.armarray)[arm].client_port);
if((aset.armarray)[arm].servSock!=0) break;
sleep(10);
i++;
if(i>20){running=0; break;}
}

функция создания сокета теперь при неудаче возвращает 0 (а не делает exit)
сокет подключается с 4-5 попыток (причём какой-то один, остальные без задержки)
теперь всё работает, только где-то минута требуется на перезапуск (из-за ожидания)

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

>Оказывается, порт освобождается не сразу

Это известная истина. По всей видимости ты для какогото порта не делаеш setsockopt(...SO_REUSEADDR...)

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

Нет, setsoskopt делается:


if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
ErrorExit("socket() failed");
................
if((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sval, sizeof(int)))<0) perror("setsockopt");

if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) <0)
{
printf("port %d busy\n", port);
close(sock);
return 0;
}

Но не помогает.

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

2 автор топика:

Посыпаю голову пеплом и закапываю ее в песок от стыда! Ты спрашивал про это, а я почему-то проглядел...

int sval=0; ... setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sval, 4);

неверно, надо sval=1.

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

Всё работает, задержка исчезла!!!
Благодарю за помощь

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