Всем привет!
Я хотел сделать простой http клиент на sbcl, но не получается: при использовании socket-make-stream даже файл не создаётся, то же самое при использовании send/receive. Вот код:
[code](in-package :common-lisp-user)
(require :sb-bsd-sockets)
(defpackage :http-client
(:use :common-lisp :sb-bsd-sockets)
(:export :wget-text))
(in-package :http-client)
(defun wget-text (host page file &optional (port 80))
(let ((socket (make-inet-socket :stream :tcp)))
(socket-connect socket
(host-ent-address (get-host-by-name host))
port)
(let ((stream (socket-make-stream socket
:input t
:output t
:buffering :full
:element-type :default
:external-format :iso-8859-1)))
(format stream "GET ~A HTTP/1.0~2%" page)
; (socket-send socket (format nil "GET ~A HTTP/1.0~2%" page) nil)
(with-open-file (out file :direction :output)
; (write-sequence (socket-receive socket nil 1024) out)
(loop :for line = (read-line stream nil nil) :while line
:do (write-line line out))))
(socket-close socket)))[/code]
Было бы неплохо еще finish-output вызвать после format. Это должно сбросить буфер.
Тут парой тем ниже есть набросок решения с использованием iolib. Есть готовое решение:
trivial-http. Использование специфичных для конкретной иплементации api крайне не рекомендуется.
Чё-то он (iolib) у меня требует пакет :net.sockets, странно...
>Чё-то он (iolib) у меня требует пакет :net.sockets, странно...
Было бы ещё неплохо привести листинг... а так, применив cl-astral, могу лишь предпологать, что версия iolib'а не совподает с версией еще чего нибудь (cffi, sbcl...). У меня такое было когда пытася поставить iolib через asdf-install. Если использовать
clbulid, то он будет тянуть всё с git/darcs/etc и проблемы синхронизации версий быть не должно.
Советую использовать drakma для работы через http.
Собственно, в этом коде проблема в буферизации. Вывод текста в поток сокета не приводит к отправке данных по сети до тех пор, пока не будет забит буфер. Так как удаленный сервер так и не получает текста запроса, то он ничего и не отправляет, поэтому и чтение из потока сокета все время блокируется. Если же буфер сбросить с помощью finish-output, то удаленный сервер получает запрос и начинает отправку данных.
http://lisper.ru/apps/format/61 — вот исправленный код.
А я брал всё с cliki и с оф сайта iolib. Вот листинг:
component :NET.SOCKETS not found, required by
#<SYSTEM "iolib" {AC8FEE1}>
[Condition of type ASDF:MISSING-DEPENDENCY]
Restarts:
0: [ABORT] Return to SLIME's top level.
1: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" RUNNING {A8800C1}>)
Backtrace:
0: ((LABELS ASDF::DO-ONE-DEP) ASDF:COMPILE-OP :NET.SOCKETS NIL)
1: ((LABELS ASDF::DO-DEP) ASDF:COMPILE-OP (:NET.SOCKETS :IO.STREAMS :IO.MULTIPLEX :IOLIB.BASE))
2: ((SB-PCL::FAST-METHOD ASDF::TRAVERSE (ASDF:OPERATION ASDF:COMPONENT)) #(3 NIL) #<unavailable argument> #<ASDF:COMPILE-OP NIL {BA59D19}> #<ASDF:SYSTEM "iolib" {AC8FEE1}>)
3: ((LABELS ASDF::DO-DEP) ASDF:COMPILE-OP ("iolib"))
4: ((SB-PCL::FAST-METHOD ASDF::TRAVERSE (ASDF:OPERATION ASDF:COMPONENT)) #(3 NIL) #<unavailable argument> #<ASDF:LOAD-OP NIL {B94A479}> #<ASDF:SYSTEM "iolib" {AC8FEE1}>)
5: (ASDF:OPERATE ASDF:LOAD-OP :IOLIB)[:EXTERNAL]
6: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ASDF:OOS (QUOTE ASDF:LOAD-OP) :IOLIB) #<NULL-LEXENV>)
7: (SB-FASL::LOAD-AS-SOURCE #<SB-SYS:FD-STREAM for "file /home/antoon/lisp/install-script.lisp" {AE59D21}> NIL NIL)
8: ((FLET SB-FASL::LOAD-STREAM) #<SB-SYS:FD-STREAM for "file /home/antoon/lisp/install-script.lisp" {AE59D21}>)
9: (LOAD "/home/antoon/lisp/install-script.lisp")[:EXTERNAL]
10: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LOAD "/home/antoon/lisp/install-script.lisp") #<NULL-LEXENV>)
11: (SWANK::EVAL-REGION "(load \"/home/antoon/lisp/install-script.lisp\")
")
12: ((LAMBDA NIL))
13: (SWANK::TRACK-PACKAGE #<CLOSURE (LAMBDA NIL) {AE52A6D}>)
14: ((LAMBDA (SWANK-BACKEND::FN)) #<CLOSURE (LAMBDA NIL) {AE52A55}>)
15: (SWANK::CALL-WITH-BUFFER-SYNTAX #<CLOSURE (LAMBDA NIL) {AE52A55}>)
16: (SWANK::REPL-EVAL "(load \"/home/antoon/lisp/install-script.lisp\")
")
17: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK:LISTENER-EVAL "(load \"/home/antoon/lisp/install-script.lisp\")
") #<NULL-LEXENV>)
18: ((LAMBDA NIL))
19: ((FLET #:FORM-FUN1570))
20: ((FLET #:FORM-FUN1570))
21: ((LAMBDA (SWANK-BACKEND::HOOK SWANK-BACKEND::FUN)) #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<CLOSURE (LAMBDA NIL) {AE52205}>)
22: ((LAMBDA NIL))
23: ((FLET #:FORM-FUN1570))
24: ((FLET #:FORM-FUN1570))
25: ((LAMBDA (SWANK-BACKEND::HOOK SWANK-BACKEND::FUN)) #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL) {B98E96D}>)
26: (SWANK::CALL-WITH-REDIRECTED-IO #<SWANK::CONNECTION {B38DF41}> #<CLOSURE (LAMBDA NIL) {AE52175}>)
27: (SWANK::CALL-WITH-CONNECTION #<SWANK::CONNECTION {B38DF41}> #<FUNCTION (LAMBDA NIL) {B98E96D}>)
28: (SWANK::HANDLE-REQUEST #<SWANK::CONNECTION {B38DF41}>)
29: (SWANK::REPL-LOOP #<SWANK::CONNECTION {B38DF41}>)
30: (SWANK::REPL-LOOP #<SWANK::CONNECTION {B38DF41}>)[:EXTERNAL]
31: (SWANK::CALL-WITH-BINDINGS NIL #<CLOSURE (LAMBDA NIL) {A88507D}>)
32: ((FLET SB-THREAD::WITH-MUTEX-THUNK))
33: ((FLET #:WITHOUT-INTERRUPTS-BODY-[CALL-WITH-MUTEX]477))
34: (SB-THREAD::CALL-WITH-MUTEX #<CLOSURE (FLET SB-THREAD::WITH-MUTEX-THUNK) {B6443215}> #S(SB-THREAD:MUTEX :NAME "thread result lock" :%OWNER #<SB-THREAD:THREAD "repl-thread" RUNNING {A8800C1}> :STATE 1) #<SB-THREAD:THREAD "repl-thread" RUNNING {A8800C1}> T)
35: ((LAMBDA NIL))
36: ("foreign function: #x80645AC")
37: ("foreign function: #x8052AE1")
38: ("foreign function: #x805BAED")
39: ("foreign function: #xB7FC34C0")
Вот установочный скрипт:
(in-package :asdf)
(load "/home/antoon/lisp/alexandria/alexandria.asd")
(load "/home/antoon/lisp/babel_0.3.0/babel.asd")
(load "/home/antoon/lisp/trivial-features_0.6/trivial-features.asd")
(load "/home/antoon/lisp/cffi_0.10.5/cffi.asd")
(load "/home/antoon/lisp/cl-ppcre-2.0.3/cl-ppcre.asd")
(load "/home/antoon/lisp/trivial-garbage_0.18/trivial-garbage.asd")
(load "/home/antoon/lisp/bordeaux-threads-0.7.0/bordeaux-threads.asd")
(load "/home/antoon/lisp/iolib-0.6.0/iolib.asd")
(oos 'load-op :alexandria)
(oos 'load-op :babel)
(oos 'load-op :trivial-features)
(oos 'load-op :cffi)
(oos 'load-op :cl-ppcre)
(oos 'load-op :trivial-garbage)
(oos 'load-op :bordeaux-threads)
(oos 'load-op :iolib)
А версия sbcl какая? В любом случае я повторюсь -- для того что бы не жанглировать версиями библиотек есть clbuild.
З.Ы. Обчно создают одну дирекорию systems, куда кидают симлинки на все asd файлы (find <где то> -name '*.asd' -exec ln -s {} . \;), которую пихают в asdf:*central-registry*. После того, как asdf знает где искать asd файлы достаточно только (asdf:oos 'asdf:load-op :iolib), а все зависимости будут загружены автоматически.
А clbuild сам вытягивает зависимости или их надо вручную устанавливать?
>А clbuild сам вытягивает зависимости или их надо вручную устанавливать?
Сам. ИМХО clbuild -- самы простой способ без лишнего гемороя собрать все нужные cl библиотеки (конечно gentoo users со мной не согласятся).
>(конечно gentoo users со мной не согласятся).
Gentoo lisp-overlay — самый простой способ собрать нужные либы. ;)