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

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

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

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

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

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

Вопрос:

  1. Есть лиспособ избежать этой ошибки?Что-то не так в коде?
  2. Является ли установка значения ulimit -na вредным, скажем, 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 вызовов.Я не знаю почему.

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

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

  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
  }
0 голосов
/ 12 июня 2018

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

...