Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Поиск resource leak (socket), Прошу помочь найти утечку ресурсов. 
:(
    Опции темы
Zerstroer
Дата 12.11.2015, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: 1
Всего: 3



Здравствуйте, уважаемые!

Достаточно давно и не спеша пишу приложение на "pure" C под Linux.

Предварительная история болезни:

Общий алгоритм работы такой:

В бесконечном цикле:
1. через popen я вызываю внешний fping я пингую устройство, делаю pclose.
2. создаю сетевое соединение к устройству (через socket и connect), опрашиваю его, получаю данные, закрываю сетевое соединение (через close) 
3. после чего через pipe и fork - передаю данные во внешнее приложение и получаю обратно от него результат так же через pipe. Все pipe старательно закрываю при завершении использования в каждом из потоков порожденном fork.
И так далее по кругу в бесконечном цикле.

В определенный момент через длительный период после запуска, при попытке создать pipe приложение падает с ошибкой "Too many open files". (получил из errno при создании pipe).

Воспользовавшись вот этим материалом я получаю дамп открытых файловых дескрипторов на момент падения следующего вида:
Код

0 (/dev/pts/0): read-write 
1 (pipe:[740693603]): write-only 
2 (pipe:[740693603]): write-only 
3 (socket:[741154750]): cloexec read-write 
4 (socket:[740694443]): read-write 
5 (socket:[740693894]): read-write 
6 (socket:[740694792]): read-write 
7 (socket:[740692936]): read-write 
...много-много строк и везде socket...
1014 (socket:[741343642]): read-write 
1015 (socket:[741343645]): read-write 
1016 (socket:[741343647]): read-write 
1017 (socket:[741343652]): read-write 
1018 (socket:[741347779]): read-write 
1019 (socket:[741345080]): read-write 
1020 (socket:[741343930]): read-write 
1021 (pipe:[741348340]): 
1022 (pipe:[741348340]): write-only


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

Но, сокеты я регулярно закрываю после использования и в случае ошибок с помощью close().
Код

int closeSocket(int nSocket) {
    int ret = close(nSocket);
    /*TODO удалить*/
    fprintf(stderr, "STDERR: Socket (%i) close status: %i\n", nSocket, ret);
    printf("STDOUT: Socket (%i) close status: %i\n", nSocket, ret);
    return ret;//close(nSocket);
}


Подскажите, в какую сторону можно копать? С чем может быть связана эта ситуация?

Дополнительная информация, которая может помочь.
1. Создаю я сокеты вот так:

Код

int createSocket(const char* sHostname, const char* sPortnumber) {
    int result = EXIT_FAILURE;
    if (ping(sHostname) != 0) return EC_HOST_DOES_NOT_PINGED;    
    struct hostent* server;
    struct sockaddr_in socketAddress;

    int socketConnection = socket(AF_INET, SOCK_STREAM, 0);
    if (socketConnection < 0) return EC_SOCKET_OPENING;

    server = gethostbyname(sHostname);
    if (server == NULL) return EC_NO_SUCH_HOST;
    
    bzero((char*) &socketAddress, sizeof(socketAddress));
    socketAddress.sin_family = AF_INET;
    bcopy((char*) server->h_addr, (char*) &socketAddress.sin_addr.s_addr, server->h_length);
    socketAddress.sin_port = htons(atoi(sPortnumber));
    if (connect(socketConnection, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
        result = EC_CONNECTING_FAIL;
    } else {
        result = socketConnection;
    }
    return result;



2. У меня уже возникал вопрос, который я задавал на форуме, связанный с тем, как методически верно следует идетифицировать закрытый сокет.

3. Я не использую setsockopt и SO_REUSEADDR - может ли быть ошибка связана с этим?


--------------------
In silico
PM MAIL ICQ   Вверх
feodorv
Дата 12.11.2015, 21:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Zerstroer @  12.11.2015,  19:45 Найти цитируемый пост)
в случае ошибок с помощью close()

Гм. Я лично вижу другую картину:
Цитата(Zerstroer @  12.11.2015,  19:45 Найти цитируемый пост)
    int socketConnection = socket(AF_INET, SOCK_STREAM, 0);
    if (socketConnection < 0) return EC_SOCKET_OPENING;
    server = gethostbyname(sHostname);
    if (server == NULL) return EC_NO_SUCH_HOST;
Где здесь закрытие сокета перед возвратом EC_NO_SUCH_HOST? Аналогично с connect: 
Цитата(Zerstroer @  12.11.2015,  19:45 Найти цитируемый пост)
    if (connect(socketConnection, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
        result = EC_CONNECTING_FAIL;
    } else {
        result = socketConnection;
    }
    return result;
В случае ошибки сокет не закрывается.



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Zerstroer
Дата 13.11.2015, 09:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: 1
Всего: 3



feodorv, отлично!
Спасибо! Мне очень не хватало свежего взгляда. Своими глазами, я этот код уже замылил.
Я так понял, что неоткрывшийся или ошибочно созданный сокет можно закрывать без проблем? Не вывалится ли errno = EBADF "The filedes argument is not a valid file descriptor." ?

Это сообщение отредактировал(а) Zerstroer - 13.11.2015, 10:38


--------------------
In silico
PM MAIL ICQ   Вверх
xvr
Дата 13.11.2015, 14:42 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(Zerstroer @  13.11.2015,  09:13 Найти цитируемый пост)
Я так понял, что неоткрывшийся или ошибочно созданный сокет можно закрывать без проблем?

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

PM MAIL   Вверх
Zerstroer
Дата 13.11.2015, 17:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: 1
Всего: 3



xvr, у меня в createSocket() 3 "аварийных" выхода из функции создания сокета:
1. 
Код

int socketConnection = socket(AF_INET, SOCK_STREAM, 0);
if (socketConnection < 0) return EC_SOCKET_OPENING;

2.
Код

server = gethostbyname(sHostname);
    if (server == NULL) return EC_NO_SUCH_HOST;

3.
Код

    if (connect(socketConnection, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
        result = EC_CONNECTING_FAIL;
    } else {
        result = socketConnection;
    }
    return result;


Случаи №2 и №3 у меня никаких вопросов не вызывают, в них я действительно прошляпил закрытие сокета при аварийном случае.
Мне не ясно с ситуацией №1 - должен ли я вызывать close(socket), если зафейлилось его создание?

Что меня сбивает с панталыку:
На википедии, есть статья "Сокеты Беркли".
В ней, в разделе "Высвобождение ресурсов" написано следующее: 
Цитата

Каждый вызов socket() должен иметь соответствующий вызов close() во всех возможных путях исполнения. 

Откуда у меня вопросы: 
А) В соответствии с путём исполнения когда socket() - выдал ошибку, должен ли я вызвать close()? 
Б) Сокеты Беркли и то, что мы здесь обсуждаем (Сокеты в Линукс) - это одно и то же?



--------------------
In silico
PM MAIL ICQ   Вверх
feodorv
Дата 13.11.2015, 19:38 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Zerstroer @  13.11.2015,  17:22 Найти цитируемый пост)
Мне не ясно с ситуацией №1 - должен ли я вызывать close(socket), если зафейлилось его создание?

А что именно Вы хотите закрывать в этом случае? Файловый дескриптор -1? Сокет не создан, соответственно, закрывать нечего.


Ну, имелось в виду:
Цитата(Zerstroer @  13.11.2015,  17:22 Найти цитируемый пост)
Каждый успешный вызов socket() должен иметь соответствующий вызов close() во всех возможных путях исполнения. 
Тогда не будет утечек файловых дескрипторов.


Цитата(Zerstroer @  13.11.2015,  17:22 Найти цитируемый пост)
А) В соответствии с путём исполнения когда socket() - выдал ошибку, должен ли я вызвать close()? 
Нет)))


Цитата(Zerstroer @  13.11.2015,  17:22 Найти цитируемый пост)
Б) Сокеты Беркли и то, что мы здесь обсуждаем (Сокеты в Линукс) - это одно и то же?
Да.


Скажите, если где-нибудь будет написано так:
Цитата
каждый вызов fopen() должен иметь соответствующий вызов fclose()
то Вы воспримите это в таком духе:
Код
if( (fp = fopen( fileName, "r")) == NULL )
{
   fclose( fp );
   return EC_CANT_OPEN_FILE;
}
Правда, да?



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Zerstroer
Дата 13.11.2015, 23:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: 1
Всего: 3



feodorv, спасибо за ответ.
Я не хочу, что бы казалось, будто бы я оправдываюсь, но, я не стесняюсь задавать настолько глупые вопросы с очевидными ответами, после которых я глупо выгляжу. Формулировка в Википедии вносила малую толику сомнений, за которые я зацепился и задал этот вопрос. Я вообще, очень много сомневаюсь. Я понимаю, что вопрос глупый и я бесконечно благодарен Вам за время, потраченное на ответ. Спасибо. А форум мне всегда помогает, даже задавая здесь вопрос, зачастую, я при формулировке проблемы нахожу ответ. Продолжаю удивляться тому, что Винград продолжает в своём собственном ритме успешно функционировать... Вот такой сентиментальный оффтоп получился.

По поводу задачи:
Отправил на тестирование, по итогам либо задам возникшие вопросы, либо помечу тему как решенную.


--------------------
In silico
PM MAIL ICQ   Вверх
feodorv
Дата 14.11.2015, 02:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Zerstroer, нет, я не хотел Вас задеть, просто вот прослеживается такая аналогия между socket() и fopen(), которую можно учесть при принятии решения. А в Интернете очень много чего пишут, много полезного, много неточного и бестолкового, к сожалению, не всегда есть возможность во всём этом разобраться. Задавайте вопросы, не стесняйтесь, форум для этого и создан  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

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

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0831 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.