На практике система не может знать время окончания, потому что HTTP является протоколом без сохранения состояния. Сеансы PHP (и аналогичные функции в других языках веб-сценариев) - это хак для реализации чего-то, что выглядит с состоянием, но такие хаки не могут полностью преодолеть природу HTTP без состояния. Например, как вы обнаружили, у сервера нет возможности узнать, что пользователь вышел из системы, если он не прошел процесс выхода из системы.
Вы можете использовать AJAX для проверки связи с пользователем, но, как вы сказали, это использует пропускную способность. Он также не сможет функционировать, если у пользователя отключена поддержка javascript.
Единственный разумный вариант - регистрировать временную метку для пользователя каждый раз, когда он попадает на страницу в вашей системе, и смотреть, сколько времени прошло с момента обновления временной метки. Если он превышает разумный предел, скажем, 20 минут, вы можете сделать предположение, что пользователь больше не находится на вашем сайте. Опять же, это не совсем идеально, так как пользователь, возможно, только что вышел из-за дыма или чего-то еще, но, поскольку HTTP не имеет состояния, ни одно решение, которое вы можете реализовать, не является полностью идеальным.