В часто задаваемых вопросах по usocket предлагается сделать это следующим образом: чтение из socket-stream
и проверка результата end-of-file
. Это работает в случае, когда у меня есть один активный поток для каждого сокета, но, похоже, это не подходит для случая, когда я пытаюсь обслуживать несколько сокетов в одном потоке.
Рассмотрим что-то вроде
(defparameter *socket* (socket-listen "127.0.0.1" 123456))
(defparameter *client-connections*
(list (socket-accept *socket*)
(socket-accept *socket*)
(socket-accept *socket*)
(socket-accept *socket*)))
В этом упражнении предположим, что у меня на самом деле есть четыре клиента, подключающихся туда. Кажется, что способ обслуживать их из одного потока - это что-то вроде
(wait-for-input *client-connections*)
(loop for sock in *client-connections*
for stream = (socket-stream sock)
when (listen stream)
do (let ((line (read-line stream nil :eof)))
(if (eq line :eof)
(progn (delete sock *client-connections*)
(socket-close sock))
(handle sock line))))
За исключением того, что это не сработает, потому что отключенный сокет по-прежнему возвращает nil
в listen
, а попытка read
из активного сокета без сообщений будет заблокирована, но wait-for-intput
немедленно возвращается, когда есть закрытый сокет в mix, даже если ни у одного другого сокета нет готового сообщения (хотя, похоже, не указано, какие сокеты вызвали его возврат).
В ситуации, когда через некоторое время ни один клиент не говорил, а третий клиент отключился, кажется, что нет хорошего способа выяснить это и закрыть это конкретное соединение сокета. Мне пришлось бы читать их последовательно, за исключением того, что, поскольку read
блокируется без ввода, это заставит поток ждать, пока первые два клиента не отправят сообщение.
Решения, которые я имел в виду, но не нашел после определенного поиска в Google, (в порядке убывания предпочтения):
- Функция, иначе эквивалентная
listen
, которая возвращаетt
, если чтение потока целей вернет маркерend-of-file
. (Заменивlisten
выше этой условной функцией, остальная часть будет работать, как написано) - Функция, эквивалентная
wait-for-input
, которая возвращает список закрытых сокетов, из-за которых она отключается. (В этом случае я мог бы пройтись по списку закрытых сокетов, проверить, действительно ли они закрыты с помощью предложенного методаread
, и закрыть/вытолкнуть их по мере необходимости) - Функция, эквивалентная
wait-for-input
, которая возвращает первый закрытый сокет, вызвавший его срабатывание. (То же, что и № 2, но медленнее, поскольку удаляет не более одного неактивного соединения за итерацию) - Отслеживание того, сколько времени прошло с тех пор, как я получил входные данные от каждого подключения к сокету, и закрытие их независимо от определенного периода бездействия. (Что я, вероятно, хотел бы сделать в любом случае, но просто это могло бы сохранить множество неработающих соединений гораздо дольше, чем необходимо)
- Функция, которая пытается получить
read-char
из потока с мгновенным тайм-аутом, возвращаетt
, если встречает:eof
, иunread-char
s что-либо еще (возвращаяnil
либо после истечения времени ожидания, либо после отмены чтения). (Это крайняя мера, так как кажется, что было бы тривиально легко взломать неочевидным, но смертельным способом).
Кроме того, если я думаю об этом совершенно неправильно, укажите это тоже.
select
на этих сокетах? - person Vsevolod Dyomkin   schedule 22.07.2012select
. - person Inaimathi   schedule 22.07.2012