I'm trying to send data over USOCKET. When the data reaches the server, the server should reply back. However, stream-read
(as defined below) only returns the data when it's echoed back with the original data it sent. For example, if I send hello
and the server replies with the same data, hello
, then stream-read
returns, but if the server replies with hi
, stream-read
doesn't return until the server sends the exact buffer it received.
Here's the code: (I've found most of it online.)
;; 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))
As for the server, I'm using a slightly modified version of the boost blocking server example. (c++) The full code can be found here: 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";
}
}
...
Without seeing the code for your server it's hard to answer without a bit of speculation. But:
You use the same socket for each call from the client to the server. If the server isn't expecting that, it won't behave as you want it to.
Your definition of stream-read
calls socket-listen
. Did you mean usocket:socket-listen
? This is a server-side function (and takes different arguments). I'm probably not looking at the exact code you were running.
Advisory notes: (a) my-stream
is actually a socket, not a stream; (b) I encourage you to manage external libraries using Quicklisp.
Here's a full working example. This is on LispWorks; I've used LW internals for the server to make it utterly clear which is server and which is client.
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
If you're still having difficulties, post again with source for your server and your actual stream-read
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With