anonymous@RULINUX.NET~# Last login: 2024-11-25 05:15:00
Регистрация Вход Новости | Разметка | Пользователи | Галерея | Форум | Статьи | Неподтвержденное | Трекер | Правила форума | F.A.Q. | Ссылки | Поиск
[#] [Добавить метку] [Редактировать]
Скрыть

CL, usocket и timeout

Надо же разбавить сие болото.

Вот, допустим, у меня есть такой код (упрощённый):

lisp

(let* ((socket (usocket:socket-connect server port :timeout timeout))
       (stream (make-stream socket encoding)))
  (do ((line
        (read-line stream nil)
        (read-line stream nil)))
      ((not line))
    (do-something-with-line)))
 
Всё отлично, но возникают редкие ситуации, когда соединение хитрым образом рвётся, а цикл остаётся висеть на read-line до окончания времён.

Как я понимаю, timeout срабатывает только на установление соединения, а сам read-line спокойно может заблокировать текущий поток на неопределённое время (ну или я совсем что-то не то делаю). Предполагаю, что нужен какой-то таймаут на чтение, после которого можно будет всё это дело прервать и переконнектиться. Вопрос, собственно, в том, как его кроссплатформенно (SBCL, CCL, ECL, чем больше - тем лучше) реализовать наиболее красивым способом.

Сходу находится какой-то trivial-timeout, но он страшный, мёртвый и, по заверением разработчиков, может не работать. Второй вариант - решение из comp.lang.lisp с бесконечным циклом и sleep. Вроде бы должно сработать, но бесконечные циклы со sleep меня пугают (хотя можно, если прижмёт).Третье - поиграть с usocket:wait-for-input, но все его применяют для серверных вещей, а у меня типа клиентское.

Также в качестве извращённого варианта можно предложить какой-нибудь watchdog thread (у меня и так многопоточная штука), который будет проверять время последнего сработавшего read-line и рестартить треды по необходимости. Но это немного странно выглядит, да и надо хэш-таблицу с локами делать.

Может кто подскажет самое изящное и простое решение?

SystemV(*) (2016-03-11 14:54:32)

Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0

[Ответить на это сообщение]
[#] [Добавить метку] [Редактировать] Ответ на: CL, usocket и timeout от SystemV 2016-03-11 14:54:32
avatar
Скрыть

Re:CL, usocket и timeout

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

anonymous(*)(2016-03-11 15:49:10)

[#] [Добавить метку] [Редактировать] Ответ на: Re:CL, usocket и timeout от anonymous 2016-03-11 15:49:10
avatar
Скрыть

Re:CL, usocket и timeout

Хочется обойтись read-line ради простоты кода, конечно.

Так там сходу есть read-char-no-hang, который, впрочем, потребует того же sleep. Конкретно в стандарте CL я не нашёл чтения с таймаутом (стандарт-то от 94-го года, а составлялся, по сути, лет на 10 раньше).

В конкретных реализациях (тот же SBCL) есть и таймауты, и всё, что нужно, но мой извращённый ум почему-то решил, что стоит поискать что-то универсальное, хоть в чудесном мире общелиспа привязка к реализации является вполне нормальным и адекватным решением по множеству причин.

SystemV(*)(2016-03-11 16:08:32)

Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0
[#] [Добавить метку] [Редактировать] Ответ на: CL, usocket и timeout от SystemV 2016-03-11 14:54:32
avatar
Скрыть

Re:CL, usocket и timeout

когда соединение хитрым образом рвётся - надо использовать TCP Keepalive

anonymous(*)(2016-03-11 17:12:11)

Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0
[#] [Добавить метку] [Редактировать] Ответ на: CL, usocket и timeout от SystemV 2016-03-11 14:54:32
avatar
Скрыть

Re:CL, usocket и timeout

Щас постараюсь ответить, как я делал. usocket говно, кстати, лучше iolib

Vasily(*)(2016-03-11 20:15:33)

Mozilla/5.0 (X11; FreeBSD amd64; rv:40.0) Gecko/20100101 Firefox/40.0
[#] [Добавить метку] [Редактировать] Ответ на: Re:CL, usocket и timeout от Vasily 2016-03-11 20:15:33Фильтры
avatar
  • матерные выражения
Скрыть

Re:CL, usocket и timeout

А вот хуй я сам знаю!

Первое, что приходит на ум, воспользоваться стандартной функцией read-char-no-hang и делить на строки вручную. И так же вручную сделать таймаут. Но это тупо как-то.

lisp

(defpackage test
  (:use #:cl)
  (:export #:run))

(in-package :test)

(defun process (socket)
  (unwind-protect
       (format t "Received ~A~%"
               (coerce
                (loop for char = (read-char-no-hang socket)
                   while char collect char) 'string))
    (close socket)))

(defun run (port)
  (bordeaux-threads:make-thread
   (lambda ()
     (let ((socket (sockets:make-socket :address-family :internet
                                        :type :stream
                                        :connect :passive
                                        :local-host #(127 0 0 1)
                                        :local-port port)))
       (loop while t do
            (let ((connection
                   (sockets:accept-connection socket)))
              (process connection)))
       (close socket)))))
 


А лучше напиши автору, как сделать read-line с таймаутом. Может подскажет

https://github.com/sionescu/iolib

У себя я делал с помощью receive-from в массив октетов, с последующим преобразованием в строку и с I/O multiplexer'ом, где можно и таймаут обработать.

Vasily(*)(2016-03-11 21:52:17)
Отредактировано Vasily по причине "не указана"
Mozilla/5.0 (X11; FreeBSD amd64; rv:40.0) Gecko/20100101 Firefox/40.0
[#] [Добавить метку] [Редактировать] Ответ на: Re:CL, usocket и timeout от Vasily 2016-03-11 21:52:17
avatar
Скрыть

Re:CL, usocket и timeout

Спасибо.

>А лучше напиши автору, как сделать read-line с таймаутом. Может подскажет
Я решил не тревожить автора из-за такой мелочи. Посмотрел на iolib - в моём случае то же самое, что и usocket, только ещё дополнительно библиотеку какую-то компилировать, решил не трогать то, что работает.

В общем, попробовал всякие разные способы, попытался именно read-line использовать - всё как-то криво, то eof не поймаешь, то ещё чего. Плюнул, задумался, посмотрел, как люди делают, и утащил решение из hunchentoot, которое только для сокетов подойдёт, а не для произвольного стрима:

lisp

(defun set-read-timeout (socket stream timeout)
  "Set timeout for read operations on stream. Taken from hunchentoot code."
  (declare (ignorable socket stream))
  #+:ecl
  (setf (sb-bsd-sockets:sockopt-receive-timeout socket) timeout)
  #+:openmcl
  (setf (ccl:stream-input-timeout socket) timeout)
  #+:cmu
  (setf (lisp::fd-stream-timeout stream) (coerce timeout 'integer))
  #+:sbcl
  (setf (sb-impl::fd-stream-timeout stream) (coerce timeout 'single-float))
  #+:abcl
  (java:jcall (java:jmethod "java.net.Socket" "setSoTimeout"  "int")
              socket
              (* 1000 timeout)))
 


Наверное сразу надо было в эту сторону смотреть. Впрочем, потом оказалось, что у меня с ABCL и ECL проект не работает даже, ну да и ладно.

SystemV(*)(2016-03-13 04:17:41)

Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
[#] [Добавить метку] [Редактировать] Ответ на: Re:CL, usocket и timeout от SystemV 2016-03-13 04:17:41
avatar
Скрыть

Re:CL, usocket и timeout

С помощью iolib это делается ещё проще:

(setf (sockets:socket-option socket :receive-timeout) n)

Только будет ли read-line и другие методы для потоков корректно обрабатывать эти таймауты или это только для низкоуровщины? По-моему read-line пофиг на таймауты.

Я usocket не трогаю, т.к. он скорее мертв, чем жив.

Vasily(*)(2016-03-15 20:28:15)

Mozilla/5.0 (X11; FreeBSD amd64; rv:40.0) Gecko/20100101 Firefox/40.0
[#] [Добавить метку] [Редактировать] Ответ на: Re:CL, usocket и timeout от Vasily 2016-03-15 20:28:15
avatar
Скрыть

Re:CL, usocket и timeout

>(setf (sockets:socket-option socket :receive-timeout) n)
receive-timeout это SO_RCVTIMEO, судя по коду.

В usocket этот таймаут можно задать при создании сокета, что я и делал в первом посте, но, судя по всему, он не срабатывал на чтение, видимо только на установку соединения работает. Или в usocket там что-то придумали странное с ним, даже не знаю.

SystemV(*)(2016-03-15 22:36:04)

Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Этот тред читают 1 пользователь:
Анонимных: 1
Зарегистрированных: 0




(c) 2010-2020 LOR-NG Developers Group
Powered by TimeMachine

Valid HTML 4.01 Transitional Правильный CSS!