Получение данных через LISP USOCKET
Я пытаюсь отправить данные через USOCKET. Когда данные достигают сервера, сервер должен ответить обратно. Тем не мение, stream-read
(как определено ниже) возвращает данные, только когда они возвращаются с исходными данными, которые они отправили. Например, если я отправлю hello
и сервер отвечает с теми же данными, hello
, затем stream-read
возвращается, но если сервер отвечает hi
, stream-read
не возвращается, пока сервер не отправит точный буфер, который он получил.
Вот код: (Я нашел большую часть в Интернете.)
;; Load USocket
(load #P"/usr/share/common-lisp/source/cl-asdf/asdf.lisp")
(asdf:operate 'asdf:load-op :usocket)
(defun stream-read (stream)
(socket-listen (usocket:socket-stream stream)))
(defun stream-print (string stream)
(write-line string (usocket:socket-stream stream))
(force-output (usocket:socket-stream stream)))
;; Define a stream
(defparameter my-stream
(usocket:socket-connect "127.0.0.1" 6003))
;; Use the stream
(stream-print "random" my-stream)
(print (stream-read my-stream))
Что касается сервера, я использую слегка модифицированную версию примера сервера повышения буста. (C++) Полный код можно найти здесь: http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/echo/blocking_tcp_echo_server.cpp
...
void session(socket_ptr sock)
{
try
{
for (;;)
{
char data[max_length];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(data), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
std::vector<char> v(data,data+length);
std::string theStr;
for(unsigned int i=0;i<v.size();i++)
{
if(v[i]<32 || v[i]>=0x7f);//Remove non-ascii char
else theStr.insert(theStr.end(),v[i]);
}
std::cout<<"|"<<theStr<<"|"<<std::endl;
boost::asio::write(*sock, boost::asio::buffer(data, length)); //works
boost::asio::write(*sock, boost::asio::buffer("some", 4)); //doesn't work
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
...
1 ответ
Не видя код для вашего сервера, трудно ответить без спекуляций. Но:
Вы используете один и тот же сокет для каждого вызова от клиента к серверу. Если сервер этого не ожидает, он не будет вести себя так, как вы этого хотите.
Ваше определение
stream-read
звонкиsocket-listen
, Ты имел ввидуusocket:socket-listen
? Это функция на стороне сервера (и принимает разные аргументы). Я, вероятно, не смотрю на точный код, который вы использовали.Консультативные заметки: (а)
my-stream
на самом деле это сокет, а не поток; (б) Я рекомендую вам управлять внешними библиотеками с помощью Quicklisp.
Вот полный рабочий пример. Это на LispWorks; Я использовал внутренние компоненты LW для сервера, чтобы было совершенно ясно, кто является сервером, а кто клиентом.
CL-USER 1 > (ql:quickload :usocket)
To load "usocket":
Load 1 ASDF system:
usocket
; Loading "usocket"
(:USOCKET)
CL-USER 2 > (comm:start-up-server
:service 6003
:function (lambda (handle)
(let* ((stream (make-instance 'comm:socket-stream
:socket handle
:direction :io
:element-type 'base-char))
(line (read-line stream)))
(format stream "Hello: ~a~%" line)
(force-output stream))))
#<MP:PROCESS Name "6003 server" Priority 85000000 State "Running">
CL-USER 3 > (defun socket-read (socket)
(read-line (usocket:socket-stream socket)))
SOCKET-READ
CL-USER 4 > (defun socket-print (string socket)
(write-line string (usocket:socket-stream socket))
(force-output (usocket:socket-stream socket)))
SOCKET-PRINT
CL-USER 5 > (defun test (thing)
(let ((socket (usocket:socket-connect "127.0.0.1" 6003)))
(socket-print thing socket)
(socket-read socket)))
TEST
CL-USER 6 > (test "Buttered toast")
"Hello: Buttered toast"
NIL
CL-USER 7 > (test "A nice cup of tea")
"Hello: A nice cup of tea"
NIL
Если вы все еще испытываете трудности, отправьте сообщение снова с указанием источника для вашего сервера и вашего фактического stream-read
,