Как решить проблему открытия слишком большого количества файлов из Socket Program без установки ulimit -n

В настоящее время я пишу сокет-сервер и клиент на C ++. Моя цель состоит в том, чтобы сервер продолжал работать, в то время как клиенты должны завершать работу, когда он отправляет и получает сообщение от сервера.

Все работает хорошо, пока клиент не вызывается около 1000 раз, и вылетает с ошибкой слишком большого количества открытых файлов. Я обнаружил, что причина заключается в настройке ulimit -n, чье значение по умолчанию 1024.

Большинство решений, которые я нашел, говорят нам, чтобы установить более высокое значение ulimit. Тем не менее, я не уверен, что это правильно:

  1. это может означать, что в моем коде есть ошибка
  2. ulimit предназначен для защиты нашей машины, слишком высокая установка аналогична отключению защиты
  3. еще есть шанс достичь предела, если сервер работает неделями или месяцами, проблема не решена

Я пробовал несколько примеров сокетов в Интернете, но у них есть похожие проблемы, скажем Вот например.

Вопрос:

  1. Есть ли способ избежать этой ошибки? Что-то не так в коде?
  2. Является ли настройка ulimit -n высоким значением вредной, скажем, 1048576?

Спасибо.

Мои рабочие коды следующие:

server.cpp:

#include <iostream>
#include <string.h>
#include <sys/socket.h> //sockaddr
#include <sys/un.h> //for sockadder_un
#include <errno.h>
#include <unistd.h> //unlink
#include <signal.h> //for catching ctrl+c

bool keep_running = true;
void terminate(int i) {
keep_running = false;
}

int main(int argc, char** argv[]) {

//--catch ctrl+c signal
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = terminate;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);

//--create socket
int socket_fd_server = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_fd_server >= 0) {
std::cout << "Server socket created" << std::endl;
}
else {
std::cout << "Server socket failed to create, errno: " << errno << std::endl;
}

//--bind server
sockaddr_un address_server;
address_server.sun_family = AF_UNIX;
strcpy(address_server.sun_path, "./socket-server");
unlink(address_server.sun_path); //delete socket file if exists

//will create a socket file, if already exist, errno=98
if (bind(socket_fd_server, (sockaddr*)&address_server, sizeof(address_server)) >= 0) {
std::cout << "Server bound" << std::endl;
}
else {
std::cout << "Server failed to bind, errno: " << errno << std::endl;
return 1;
}

//--mark socket as passive socket (listen)
if (listen(socket_fd_server, 100) >= 0) {
std::cout << "Start to listen" << std::endl;
}
else {
std::cout << "Failed to listen, errno: " << errno << std::endl;
}

//--
sockaddr_un address_client;
char message_sent[] = {"message from server to client"};
char message_received[100] = {};
while (keep_running) {
unsigned int len = sizeof(address_client);
int socket_fd_client = accept(socket_fd_server, (sockaddr*)&address_client, &len);
send(socket_fd_client, message_sent, sizeof(message_sent), 0);
std::cout << "Server sent message: " <<message_sent << std::endl;
recv(socket_fd_client, message_received, sizeof(message_received), 0);
std::cout << "Server received message: " <<message_received << std::endl;
}
std::cout << "Leave while loop" << std::endl;
unlink(address_server.sun_path);
close(socket_fd_server);
return 0;
}

client.cpp:

#include <iostream>
#include <string.h>
#include <sys/types.h> //see NOTES in http://www.linuxhowtos.org/manpages/2/connect.htm
#include <sys/socket.h> //sockaddr
#include <sys/un.h> //for sockadder_un
//#include <netinet/in.h> //for sockadder_in
#include <unistd.h> //close
#include <errno.h>

int main(int argc, char** argv[]) {

//--create socket
int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_fd >= 0) {
std::cout << "Client socket created" << std::endl;
}
else {
std::cout << "Client socket failed to create, errno: " << errno << std::endl;
}

//--connection
sockaddr_un address_un;
address_un.sun_family = AF_UNIX;
//address_un.sun_path = "./SocketServer";
strcpy(address_un.sun_path, "../SocketServer/socket-server");
if (connect(socket_fd, (sockaddr*)&address_un, sizeof(address_un)) == 0) {
std::cout << "Client connected" << std::endl;
}
else {
std::cout << "Client failed to connect, errno: " << errno << std::endl;
}

//--send message
//char message_sent[] = {"test send message"};
std::string message_sent = "test send message";
if (send(socket_fd, message_sent.c_str(), sizeof(message_sent), 0) > 0) {
std::cout << "Message: " << message_sent << " sent" << std::endl;
}
else {
std::cout << "Message: " << message_sent << " not sent, errno: " << errno << std::endl;
}

//--receive message_sent
char message_received[100] = {}; // = "test receive message";
if (recv(socket_fd, message_received, sizeof(message_received), 0) > 0) {
std::cout << "Message: " << message_received << " received" << std::endl;
}
else {
std::cout << "Message: " << message_received << " not received, errno: " << errno << std::endl;
}

//--close
close(socket_fd);

return 0;
}

Кстати, это происходит только тогда, когда сервер работает в Bash. Если сервер работает в отладчике Eclipse, он может превышать 1024 вызовов. Я не знаю почему.

1

Решение

на сервере вы не закрываете файловые дескрипторы клиента, которого вы принимаете для этого

  while (keep_running) {
unsigned int len = sizeof(address_client);
int socket_fd_client = accept(socket_fd_server, (sockaddr*)&address_client, &len);
send(socket_fd_client, message_sent, sizeof(message_sent), 0);
std::cout << "Server sent message: " <<message_sent << std::endl;
recv(socket_fd_client, message_received, sizeof(message_received), 0);
std::cout << "Server received message: " <<message_received << std::endl;
close(socket_fd_client); //close the file descriptor
}
1

Другие решения

Вы протекаете сокеты. Попробуйте проверить ошибки. Здесь не достаточно Если recv() возвращает ноль, закройте сокет. Если он возвращает -1 и errnoне является EAGAIN/EWOULDBLOCKзакройте розетку. Если send() возвращает -1, закройте сокет.

2

По вопросам рекламы [email protected]