• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

could not create socket: Too many open files

Object Storage Arubacloud
0 głosów
295 wizyt
pytanie zadane 7 marca 2023 w C i C++ przez scared Początkujący (260 p.)
edycja 7 marca 2023 przez scared

Cześć,

napisałem oprogramowanie w c++ które uruchamiam na raspberry, Program otwiera pliki, zaczytuje lub loguje dane i je zamyka. Używam też komunikacji tcp z dwoma urządzeniami. Po pewnym czasie działania programu dostaje komunikat: "could not create socket: Too many open files"

 

Czy zamykam gdzieś błędnie jakiś plik lub socket? Program działa w kilku wątkach i kilka wątków też odwołuje się np do jednego logera i pliku, czy powienienem to jakoś zabezpieczyć?

Dla użytkownika aktualnie ustawiony jest limit otwartych plików na 1024. Jest to bardzo dużo i nie rozumiem w jaki sposób aktualnie jestem w stanie to wypełnić.

 

Kod logera:

inline string get_current_date_time(string arg_s) {
    time_t l_now = time(0);
    struct tm  l_tstruct;
    char  l_buf[80];
    l_tstruct = *localtime(&l_now);
    if (arg_s == "now")
        strftime(l_buf, sizeof(l_buf), "%Y-%m-%d %X", &l_tstruct);
    else if (arg_s == "date")
        strftime(l_buf, sizeof(l_buf), "%Y-%m-%d", &l_tstruct);
    return string(l_buf);
};
inline void logger(string arg_log_msg) {
    try {
        string filePath = get_current_date_time("date") + ".txt";
        string now = get_current_date_time("now");
        ofstream ofs(filePath.c_str(), std::ios_base::out | std::ios_base::app);
        ofs << now << " [" + g_raspberry_temp + "] " << arg_log_msg << '\n';
        ofs.close();
    }
    catch (...) {
        cout << "Logger ERROR" << endl;
    }
}

Kod czytający temperature cpu raspberry:

string raspberry_temp() {
    FILE* l_temperature_file;
    double l_T;
    l_temperature_file = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
    if (l_temperature_file == NULL) {
        throw 4;
    }
    fscanf(l_temperature_file, "%lf", &l_T);
    l_T /= 1000;
    // printf("The temperature is %6.3f C.\n", T);
    fclose(l_temperature_file);
    string l_tmp = to_string(l_T);
    return l_tmp.substr(0, l_tmp.find(".") + 3);
}

Kod połączenia tcp:

int tcp_client(char* arg_message, int &sock) {
    int l_valread, l_client_fd;
    struct sockaddr_in l_serv_addr;
    try {
        if (sock < 0) {
            if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                logger(" Socket creation error");
                throw 101;
            }
            l_serv_addr.sin_family = AF_INET;
            l_serv_addr.sin_port = htons(strtol(g_config_frontrnd_port.c_str(), NULL, 0));
            if (inet_pton(AF_INET, g_config_frontend_ip.data(), &l_serv_addr.sin_addr)
                <= 0) {
                logger("Invalid address/ Address not supported");
                throw 102;
            }
            if ((l_client_fd
                = connect(sock, (struct sockaddr*)&l_serv_addr,
                    sizeof(l_serv_addr)))
                < 0) {
                logger("Connection Failed");
                throw 103;
            }
            logger("Polaczono z frontendem");
        }
        if(send(sock, arg_message, strlen(arg_message), 0) < 0) throw 104;;
    }
    catch (int e) {
        close(sock);
        sock = -1;
        if (e == 101) logger("CANT CONNECT TO FRONTEND : Exception Nr. 1");
        else if (e == 102) logger("CANT CONNECT TO FRONTEND : Exception Nr. 2");
        else if (e == 103) logger("CANT CONNECT TO FRONTEND : Exception Nr. 3");
        else if (e == 104) logger("CANT CONNECT TO FRONTEND : BORKEN PIPE");
        else logger("CANT CONNECT TO FRONTEND : Exception Nr. " + to_string(e));
        logger("Utracono polaczenie z frontendem");
        return e;
    }

}

Kod czytania json

void read_language(string arg_file) {
    logger("Zaczytanie konfiguracji z pliku " + arg_file);
    std::ifstream l_t(arg_file);
    std::stringstream l_buffer;
    l_buffer << l_t.rdbuf();
    l_t.close();
    Json::Reader reader;
    Json::Value obj;
    reader.parse(l_buffer, obj);

    g_prss_button1 = obj["Test_button_1"].asString();
    g_prss_button2 = obj["Test_button_2"].asString();
    g_prss_button3 = obj["Test_button_3"].asString();

 }

 

1 odpowiedź

0 głosów
odpowiedź 7 marca 2023 przez tangarr Mędrzec (154,860 p.)
wybrane 8 marca 2023 przez scared
 
Najlepsza
Nie widzę zamknięcia socketu po udanym wysłaniu wiadomości
2
komentarz 7 marca 2023 przez Oscar Nałogowiec (29,320 p.)

Zmienna sock jest przekazywane przez referencje, więc może być używana na zewnątrz funkcji. Po co inaczej byłaby parametrem.

Natomiast nie ma zwracanej wartości, że się wszystko udało.

Poprosimy wynik polecenia

netstat -ntpa

w trakcie działania programu.

1
komentarz 7 marca 2023 przez tangarr Mędrzec (154,860 p.)
@Oscar Racja.
Zobacz w jaki sposób używasz funkcji tcp_client. Być może gubisz otwarte deskryptory. Jeżeli możesz debugować program w trakcie działania to dodaj sobie jakieś logowanie na tworzenie nowego socketu. Może wielokrotnie tworzysz socket dla tego samego klienta.
komentarz 7 marca 2023 przez scared Początkujący (260 p.)

sock jest przekazywany przez referencje, i caly czas działam na jednym sokecie, jest zamykany dopiero jak stracę połączenie tcp i otwierany nowy.

za pomocą polecenia  cat /proc/sys/fs/file-nr

widzę jak stopniowo rosną otwarte pliki, ąż do maksymalnej wartości 1024

komentarz 7 marca 2023 przez scared Początkujący (260 p.)

Może nie sprecyzowałem w pytaniu, aplikacja łączy się tylko z 2 urządzeniami, sock jest otwierany w momęcię połączenia i komunikacja cały czas działa na jednym. Zmieniany jest dopiero gdy aplikacja staci połączenie, próbuje je odzyskać na nowym sock.

 

problem z could not create socket: Too many open files tak naprawdę zaczął się gdy zaczynam w aplikacji co 1s czytać plik json (zawiera on tłumaczenia aplikacji na inne języki) 

1
komentarz 7 marca 2023 przez tangarr Mędrzec (154,860 p.)
Więc wrzuć kod odpowiedzialny za wczytywanie tego pliku.
komentarz 7 marca 2023 przez scared Początkujący (260 p.)

Przepraszam bardzo, byłem przekonany że dodałem to w poście :/

void read_language(string arg_file) {
    logger("Zaczytanie konfiguracji z pliku " + arg_file);
    std::ifstream l_t(arg_file);
    std::stringstream l_buffer;
    l_buffer << l_t.rdbuf();
    l_t.close();
    Json::Reader reader;
    Json::Value obj;
    reader.parse(l_buffer, obj);

    g_prss_button1 = obj["Test_button_1"].asString();
    g_prss_button2 = obj["Test_button_2"].asString();
    g_prss_button3 = obj["Test_button_3"].asString();

}

 

1
komentarz 7 marca 2023 przez tangarr Mędrzec (154,860 p.)

Nie potrafię zlokalizować problemu w tym kodzie.
Spróbuj uruchomić program pod valgrindem z flagami do monitorowania deskryptorów plików

valgrind -q --tool=none --track-fds=yes ./program

 

1
komentarz 8 marca 2023 przez mokrowski Mędrzec (155,460 p.)
Obsługa gniazd, nie jest bezpieczna wielowątkowo. Warto przeprojektować aplikację tak, aby obsługę gniazd, realizował jeden i tylko jeden wątek. Do niego należy zlecać wykonanie jakichkolwiek operacji otwarcia/wysłania/przyjęcia/zamknięcia/... danych na gnieździe. Jeśli "boli" przeprojektowanie, to rozwiązaniem zastępczym jest mutex który będzie bronił dostępu do operacji na gnieździe. Ale to... mniej wydajne i ... nieeleganckie :P
komentarz 8 marca 2023 przez scared Początkujący (260 p.)
dziękuję, przeprojektuje aplikacje tak żeby tylko jeden wątek obsługiwał gnizada
komentarz 8 marca 2023 przez scared Początkujący (260 p.)
Dziękujebardzo!!!, uruchomienie programu pod valgrindem bardzo mi pomogło. Udało mi się znaleźć błąd. Jeden z czujników temperatury który był obsługiwany pod 1-wire nie zamykał gniazda.

 

Logi z valgrind bardzo przejrzyście pokazały problem.

Podobne pytania

0 głosów
1 odpowiedź 98 wizyt
0 głosów
1 odpowiedź 122 wizyt
pytanie zadane 6 czerwca 2020 w C i C++ przez tonn204 Mądrala (7,440 p.)
0 głosów
0 odpowiedzi 150 wizyt
pytanie zadane 29 kwietnia 2016 w Systemy operacyjne, programy przez Damian Sobieski Początkujący (440 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...