Проводя стресс-тест на некотором серверном коде, который я написал, я заметил, что хотя я вызываю close () для дескриптора дескриптора (и проверяю результат на наличие ошибок), дескриптор не освобождается, что в конечном итоге заставляет accept () возвращать ошибка «Слишком много открытых файлов».
Теперь я понимаю, что это из-за ulimit, но я не понимаю, почему я нажимаю его, если вызываю close () после каждого синхронного цикла принятия / чтения / отправки?
Я проверяю, что дескрипторы на самом деле там, запустив часы с lsof:
ctsvr 9733 майк 1017u носок 0,7 0t0 3323579 не может идентифицировать протокол ctsvr 9733 майк 1018u носок 0,7 0t0 3323581 не может идентифицировать протокол ...
И, конечно же, их около 1000. Более того, проверяя с помощью netstat, я вижу, что нет никаких зависающих состояний TCP (ни WAIT, ни STOPPED, ни чего-либо).
Если я просто выполняю единственное соединение / отправку / запись с клиента, я замечаю, что сокет остается в списке в lsof; так что это даже не проблема загрузки.
Сервер работает на 64-битной машине с Ubuntu Linux.
Какие-нибудь мысли?
Поэтому, используя strace (спасибо Gearoid), без которого я понятия не имею, как я вообще жил, я заметил, что фактически закрываю дескрипторы.
Тем не мение. И ради потомства я обнажил свою глупую ошибку:
Socket::Socket() : impl(new Impl) {
impl->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
....
}
Socket::ptr_t Socket::accept() {
auto r = ::accept(impl->fd, NULL, NULL);
...
ptr_t s(new Socket);
s->impl->fd = r;
return s;
}
Как видите, мой конструктор сразу выделил сокет, а затем я заменил дескриптор на тот, который был возвращен методом accept — создав утечку. Я изменил код принятия из автономного класса Acceptor в класс Socket, не меняя его.
Используя strace, я легко мог видеть, что socket () запускался каждый раз, что приводило к моменту моей лампочки.
Спасибо всем за помощь!
Вы когда-нибудь вызывали perror () после close ()?
Я думаю, что возвращенная строка поможет вам;
Вы, скорее всего, висит на recv()
или же send()
команда. Рассмотрите возможность установки таймаута с помощью setsockopt
,
Я заметил похожий вывод на lsof, когда сокет был закрыт на другом конце, но мой поток держал сокет открытым, висящим на recv()
Команда ожидает данных.