Receiving data through LISP USOCKET
Asked Answered
F

1

5

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";
  }
}
   ...
Farming answered 23/6, 2013 at 3:49 Comment(0)
C
11

Without seeing the code for your server it's hard to answer without a bit of speculation. But:

  1. 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.

  2. 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.

  3. 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.

Claypool answered 23/6, 2013 at 11:36 Comment(1)
Looks like the server was the issue, replaced it with the practical c++ echo server and everything works! cs.ecs.baylor.edu/~donahoo/practical/CSockets/practical Also, thanks for the socket-read function, it now reads properly.Farming

© 2022 - 2024 — McMap. All rights reserved.