Подтвердить что ты не робот

Socket accept - "Слишком много открытых файлов"

Я работаю над школьным проектом, где мне приходилось писать многопоточный сервер, и теперь я сравниваю его с apache, запуская некоторые тесты против него. Я использую autobench, чтобы помочь с этим, но после того, как я запустил несколько тестов, или если я дам слишком высокую скорость (около 600+) для подключения, я получаю сообщение "Слишком много открытых файлов".

После того, как я закончил работу с запросом, я всегда делаю close() в сокете. Я также попытался использовать функцию shutdown(), но ничего не помогает. Как это обойти?

4b9b3361

Ответ 1

Есть несколько мест, где Linux может иметь ограничения на количество дескрипторов файлов, которые вы можете открыть.

Вы можете проверить следующее:

cat /proc/sys/fs/file-max

Это даст вам системные ограничения дескрипторов файлов.

На уровне оболочки это скажет вам ваш личный предел:

ulimit -n

Это может быть изменено в /etc/security/limits.conf - это параметр nofile.

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

Ответ 2

У меня была аналогичная проблема. Быстрое решение:

ulimit -n 4096

объяснение выглядит следующим образом: каждое соединение с сервером является файловым дескриптором. В CentOS, Redhat и Fedora, возможно, другие, ограничение на доступ к файлам составляет 1024 - не знаю почему. Это легко увидеть при вводе: ulimit -n

Обратите внимание, что это не имеет большого отношения к файлам системного максимума (/proc/sys/fs/file-max).

В моем случае это была проблема с Redis, поэтому я сделал:

ulimit -n 4096
redis-server -c xxxx

в вашем случае вместо redis, вам нужно запустить свой сервер.

Ответ 3

TCP имеет функцию "TIME_WAIT", которая обеспечивает чистое соединение. Он требует, чтобы один конец соединения продолжал слушать некоторое время после закрытия разъема.

На высокопроизводительном сервере важно, чтобы клиенты, которые вошли в TIME_WAIT, а не сервер. Клиенты могут позволить открыть порт, тогда как занятый сервер может быстро выходить из портов или иметь слишком много открытых FD.

Чтобы достичь этого, сервер никогда не должен закрывать соединение первым - он всегда должен ждать, пока клиент его закроет.

Ответ 4

Используйте lsof -u `whoami` | wc -l, чтобы узнать, сколько открытых файлов у пользователя

Ответ 5

У меня тоже была эта проблема. У вас есть утечка дескриптора файла. Вы можете отладить это, распечатав список всех открытых дескрипторов файлов (в системах POSIX):

void showFDInfo()
{
   s32 numHandles = getdtablesize();

   for ( s32 i = 0; i < numHandles; i++ )
   {
      s32 fd_flags = fcntl( i, F_GETFD ); 
      if ( fd_flags == -1 ) continue;


      showFDInfo( i );
   }
}

void showFDInfo( s32 fd )
{
   char buf[256];

   s32 fd_flags = fcntl( fd, F_GETFD ); 
   if ( fd_flags == -1 ) return;

   s32 fl_flags = fcntl( fd, F_GETFL ); 
   if ( fl_flags == -1 ) return;

   char path[256];
   sprintf( path, "/proc/self/fd/%d", fd );

   memset( &buf[0], 0, 256 );
   ssize_t s = readlink( path, &buf[0], 256 );
   if ( s == -1 )
   {
        cerr << " (" << path << "): " << "not available";
        return;
   }
   cerr << fd << " (" << buf << "): ";

   if ( fd_flags & FD_CLOEXEC )  cerr << "cloexec ";

   // file status
   if ( fl_flags & O_APPEND   )  cerr << "append ";
   if ( fl_flags & O_NONBLOCK )  cerr << "nonblock ";

   // acc mode
   if ( fl_flags & O_RDONLY   )  cerr << "read-only ";
   if ( fl_flags & O_RDWR     )  cerr << "read-write ";
   if ( fl_flags & O_WRONLY   )  cerr << "write-only ";

   if ( fl_flags & O_DSYNC    )  cerr << "dsync ";
   if ( fl_flags & O_RSYNC    )  cerr << "rsync ";
   if ( fl_flags & O_SYNC     )  cerr << "sync ";

   struct flock fl;
   fl.l_type = F_WRLCK;
   fl.l_whence = 0;
   fl.l_start = 0;
   fl.l_len = 0;
   fcntl( fd, F_GETLK, &fl );
   if ( fl.l_type != F_UNLCK )
   {
      if ( fl.l_type == F_WRLCK )
         cerr << "write-locked";
      else
         cerr << "read-locked";
      cerr << "(pid:" << fl.l_pid << ") ";
   }
}

Сбрасывая все открытые файлы, вы быстро выясните, где находится утечка дескриптора файла.

Если ваш сервер порождает подпроцессы. Например. если это сервер типа "fork", или если вы создаете другие процессы (например, через cgi), вы должны обязательно создать свои файлы с помощью "cloexec" - как для реальных файлов, так и для сокетов.

Без cloexec, каждый раз, когда вы используете fork или spawn, все открытые дескрипторы файлов клонируются в дочернем процессе.

Также очень легко не удается закрыть сетевые сокеты - например, просто отказываясь от них, когда удаленная сторона отключается. Это приведет к утечке ручек, таких как сумасшедшие.

Ответ 6

это может занять некоторое время, прежде чем закрытое гнездо действительно освободится.

lsof, чтобы просмотреть открытые файлы

cat /proc/sys/fs/file-max, чтобы увидеть, существует ли системный предел

Ответ 7

Это означает, что максимальное количество одновременно открытых файлов.

Решено:

В конце файла /etc/security/limits.conf вам нужно добавить следующие строки:

* soft nofile 16384
* hard nofile 16384

В текущей консоли от root (sudo не работает):

ulimit -n 16384

Хотя это необязательно, если можно перезагрузить сервер.

В файле /etc/nginx/nginx.conf, чтобы зарегистрировать новое значение worker_connections, равное 16384, делить на значение worker_processes.

Если не было ulimit -n 16384, вам нужно перезагрузиться, тогда проблема отступит.

PS:

Если после ремонта видна в журналах error accept() failed (24: Too many open files):

В конфигурации nginx propevia (например):

worker_processes 2;

worker_rlimit_nofile 16384;

events {
  worker_connections 8192;
}

Ответ 8

Когда ваша программа имеет более открытые дескрипторы, чем открытые файлы ulimit (ulimit -a перечислит это), ядро ​​откажется открыть больше файловых дескрипторов. Убедитесь, что у вас нет утечек дескриптора файла - например, запустив его на некоторое время, затем остановившись и посмотрев, все ли дополнительные фдс все еще открыты, когда он простаивает - и если это все еще проблема, измените nofile ulimit для вашего пользователя в/etc/security/limits.conf

Ответ 9

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

Я могу только предположить сбой оптимизации в компиляторе (gcc в моем случае), предполагается, что вызовы close() не имеют побочных эффектов и могут быть опущены, если их возвращаемые значения не используются.

Ответ 10

Еще одна информация о CentOS. В этом случае при использовании "systemctl" для запуска процесса. Вам необходимо изменить системный файл == > /usr/lib/systemd/system/processName.service .В этой строке в файле:

LimitNOFILE=50000

И просто перезагрузите систему conf:

systemctl daemon-reload