From: AngelP
Subject: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <911ab771-e09f-4fae-aab7-74ad4e1c6ad5@y21g2000hsf.googlegroups.com>
Hi,

I am getting strange connectionrefused, when tring to connect to a
server.
On one console, I start (ping)
on the next (pong)
I expect they to exchange messages and to quit, but I get an error on
writting to the socket. According to (ping), (pong) has accepted
connection, but (pong) waits on accept.

I can not figure out what is wrong.

I have tried this on Ubuntu with CLISP 2.45

Regards, Angel


(defun ping (&optional (server (socket:socket-server 5000)))
  (with-open-stream (s (socket:socket-accept server))
    (socket:socket-server-close server)
    (format t "From pong:~A~%" (read-line s))
    (write-line "ping-result" s))
  (with-open-stream (s (socket:socket-connect 6000
"localhost" :timeout 30))
    (write-line "are you ready?" s)))

(defun pong ()
  (with-open-stream (s (socket:socket-connect 5000))
    (write-line "pong-Req" s)
    (format t "From ping:~A~%" (read-line s)))
  (let ((server (socket:socket-server 6000)))
    (with-open-stream (s (socket:socket-accept server))
      (socket:socket-server-close server)
      (format t "From ping:~A~%" (read-line s)))))



on the first console:

[1]> (loop (ping))
From pong:pong-Req

*** - UNIX error 111 (ECONNREFUSED): Connection refused
The following restarts are available:
ABORT          :R1      ABORT
Break 1 [2]> :w
<1> #<SYSTEM-FUNCTION WRITE-LINE>
EVAL frame for form (WRITE-LINE "are you ready?" S)
Break 1 [2]>

From the second console

[1]> (loop (pong))
From ping:ping-result

*** - Ctrl-C: User break
The following restarts are available:
ABORT          :R1      ABORT
Break 1 [2]> :w
<1> #<SYSTEM-FUNCTION SOCKET-ACCEPT>
EVAL frame for form (SOCKET-ACCEPT SERVER)
Break 1 [2]>

From: K Livingston
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <a97dd398-c1a8-4c2d-a52b-07529335253a@56g2000hsm.googlegroups.com>
On Jun 26, 3:54 pm, AngelP <··········@gmail.com> wrote:
> Hi,
>
> I am getting strange connectionrefused, when tring to connect to a
> server.
> On one console, I start (ping)
> on the next (pong)
> I expect they to exchange messages and to quit, but I get an error on
> writting to the socket. According to (ping), (pong) has accepted
> connection, but (pong) waits on accept.
>
> I can not figure out what is wrong.
>
> I have tried this on Ubuntu with CLISP 2.45
>
> Regards, Angel
>
> (defun ping (&optional (server (socket:socket-server 5000)))
>   (with-open-stream (s (socket:socket-accept server))
>     (socket:socket-server-close server)
>     (format t "From pong:~A~%" (read-line s))
>     (write-line "ping-result" s))
>   (with-open-stream (s (socket:socket-connect 6000
> "localhost" :timeout 30))
>     (write-line "are you ready?" s)))
>
> (defun pong ()
>   (with-open-stream (s (socket:socket-connect 5000))
>     (write-line "pong-Req" s)
>     (format t "From ping:~A~%" (read-line s)))
>   (let ((server (socket:socket-server 6000)))
>     (with-open-stream (s (socket:socket-accept server))
>       (socket:socket-server-close server)
>       (format t "From ping:~A~%" (read-line s)))))
>
> on the first console:
>
> [1]> (loop (ping))
> From pong:pong-Req
>
> *** - UNIX error 111 (ECONNREFUSED): Connection refused
> The following restarts are available:
> ABORT          :R1      ABORT
> Break 1 [2]> :w
> <1> #<SYSTEM-FUNCTION WRITE-LINE>
> EVAL frame for form (WRITE-LINE "are you ready?" S)
> Break 1 [2]>
>
> From the second console
>
> [1]> (loop (pong))
> From ping:ping-result
>
> *** - Ctrl-C: User break
> The following restarts are available:
> ABORT          :R1      ABORT
> Break 1 [2]> :w
> <1> #<SYSTEM-FUNCTION SOCKET-ACCEPT>
> EVAL frame for form (SOCKET-ACCEPT SERVER)
> Break 1 [2]>


It looks like you have a classic example of a race condition.  In all
likelihood the Pong server is not establish at the time that Ping
sends its connection request.  And Ping (if I'm reading the code
correctly, I don't know the clisp network API that well) only requests
once and has no reason to wait, or way to know if Pong is ready to
receive that request.

3 possible solutions come quickly to mind.

#A#
1. change pong's code to open it's server socket right away
2. start ping - have it report when it's server socket is up (you have
to know it's up otherwise for the same reason you could miss pong's
initial request)
3. then start pong - you now know both servers are ready when they
need to be talked to.

If you don't want the pong server to start before it has heard from
ping, 2 options come to mind.

#B#
1. change pong's code to start it's server before it sends its message
to ping
2. start ping - have it report when it's server socket is up
3. then start pong

because ping isn't free to call pong until it hears from pong, and
pong doesn't say anything to ping until it's server is up, you have
now avoided the race condition.  (more formal approaches to
multiprocessing sometimes refer to this as a "barrier")

#C#
1. leave pong's code alone, and change ping's code so that it will
make multiple attempts to attach to pong (trying over and over again
until pong is up and the connection is successful)

depending on how you do this, and how many attempts you allow and how
fast, etc. a race condition could still crop up, but given appropriate
enough values you'll be ok.


depending on what you are actually trying to accomplish will inform
your actual choice of correction.  Since the two processes are already
talking to each other though, I prefer some form of #B# over #C#,
since #C# is effectively polling / busy waiting from ping's point of
view, and you can avoid that.

Kevin
From: K Livingston
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <d8142964-8a14-4910-80c3-caec735bd3da@26g2000hsk.googlegroups.com>
On Jun 26, 5:12 pm, K Livingston <······················@gmail.com>
wrote:
> On Jun 26, 3:54 pm, AngelP <··········@gmail.com> wrote:
>
>
>
> > Hi,
>
> > I am getting strange connectionrefused, when tring to connect to a
> > server.
> > On one console, I start (ping)
> > on the next (pong)
> > I expect they to exchange messages and to quit, but I get an error on
> > writting to the socket. According to (ping), (pong) has accepted
> > connection, but (pong) waits on accept.
>
> > I can not figure out what is wrong.
>
> > I have tried this on Ubuntu with CLISP 2.45
>
> > Regards, Angel
>
> > (defun ping (&optional (server (socket:socket-server 5000)))
> >   (with-open-stream (s (socket:socket-accept server))
> >     (socket:socket-server-close server)
> >     (format t "From pong:~A~%" (read-line s))
> >     (write-line "ping-result" s))
> >   (with-open-stream (s (socket:socket-connect 6000
> > "localhost" :timeout 30))
> >     (write-line "are you ready?" s)))
>
> > (defun pong ()
> >   (with-open-stream (s (socket:socket-connect 5000))
> >     (write-line "pong-Req" s)
> >     (format t "From ping:~A~%" (read-line s)))
> >   (let ((server (socket:socket-server 6000)))
> >     (with-open-stream (s (socket:socket-accept server))
> >       (socket:socket-server-close server)
> >       (format t "From ping:~A~%" (read-line s)))))
>
> > on the first console:
>
> > [1]> (loop (ping))
> > From pong:pong-Req
>
> > *** - UNIX error 111 (ECONNREFUSED): Connection refused
> > The following restarts are available:
> > ABORT          :R1      ABORT
> > Break 1 [2]> :w
> > <1> #<SYSTEM-FUNCTION WRITE-LINE>
> > EVAL frame for form (WRITE-LINE "are you ready?" S)
> > Break 1 [2]>
>
> > From the second console
>
> > [1]> (loop (pong))
> > From ping:ping-result
>
> > *** - Ctrl-C: User break
> > The following restarts are available:
> > ABORT          :R1      ABORT
> > Break 1 [2]> :w
> > <1> #<SYSTEM-FUNCTION SOCKET-ACCEPT>
> > EVAL frame for form (SOCKET-ACCEPT SERVER)
> > Break 1 [2]>
>
> It looks like you have a classic example of a race condition.  In all
> likelihood the Pong server is not establish at the time that Ping
> sends its connection request.  And Ping (if I'm reading the code
> correctly, I don't know the clisp network API that well) only requests
> once and has no reason to wait, or way to know if Pong is ready to
> receive that request.
>
> 3 possible solutions come quickly to mind.
>
> #A#
> 1. change pong's code to open it's server socket right away
> 2. start ping - have it report when it's server socket is up (you have
> to know it's up otherwise for the same reason you could miss pong's
> initial request)
> 3. then start pong - you now know both servers are ready when they
> need to be talked to.
>
> If you don't want the pong server to start before it has heard from
> ping, 2 options come to mind.
>
> #B#
> 1. change pong's code to start it's server before it sends its message
> to ping
> 2. start ping - have it report when it's server socket is up
> 3. then start pong
>
> because ping isn't free to call pong until it hears from pong, and
> pong doesn't say anything to ping until it's server is up, you have
> now avoided the race condition.  (more formal approaches to
> multiprocessing sometimes refer to this as a "barrier")
>
> #C#
> 1. leave pong's code alone, and change ping's code so that it will
> make multiple attempts to attach to pong (trying over and over again
> until pong is up and the connection is successful)
>
> depending on how you do this, and how many attempts you allow and how
> fast, etc. a race condition could still crop up, but given appropriate
> enough values you'll be ok.
>
> depending on what you are actually trying to accomplish will inform
> your actual choice of correction.  Since the two processes are already
> talking to each other though, I prefer some form of #B# over #C#,
> since #C# is effectively polling / busy waiting from ping's point of
> view, and you can avoid that.
>
> Kevin

I also just noticed you were calling them both in a loop...

As another point, you can, if you would like, accept multiple
connections from a single server/accept socket.  So you don't have to
keep tearing your server down and bringing it back up for each
connection.  They can usually hold a configurable number of pending
connections, and calling accept again will just get you the next one
in the queue.
From: Pascal J. Bourguignon
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <87wskbg5ri.fsf@hubble.informatimago.com>
AngelP <··········@gmail.com> writes:

> Hi,
>
> I am getting strange connectionrefused, when tring to connect to a
> server.
> On one console, I start (ping)
> on the next (pong)
> I expect they to exchange messages and to quit, but I get an error on
> writting to the socket. According to (ping), (pong) has accepted
> connection, but (pong) waits on accept.
>
> I can not figure out what is wrong.
>
> I have tried this on Ubuntu with CLISP 2.45

This is not a lisp question, it's a network question.

* The port 6000 (and following) is usually used by X11R6.

* You must ensure when the data is sent with FORCE-OUTPUT or
  FINISH-OUTPUT.

* You must ensure you close sockets even when breaking into the
  debugger and exiting abnormally from the function (use
  UNWIND-PROTECT).

* You should not try to connect to a server before it has time to
  start up (sleep, or better, never close down the server socket)

And finally, I don't see the point of exchanging ports like that, but
if you have fun like this...


(defun pong ()
  (sleep 1)
  (with-open-stream (s (socket:socket-connect 25001))
    (write-line "pong-Req" s)
    (finish-output s)
    (format t "From ping:~A~%" (read-line s))
    (finish-output))
  (let ((server (socket:socket-server 26001)))
    (unwind-protect
         (with-open-stream (s (socket:socket-accept server))
           (format t "From ping:~A~%" (read-line s))
           (finish-output))
      (socket:socket-server-close server))))



(defun ping (&optional (server (socket:socket-server 25001)))
  (unwind-protect
       (with-open-stream (s (socket:socket-accept server))
         (format t "From pong:~A~%" (read-line s))
         (finish-output)
         (write-line "ping-result" s)
         (finish-output s))
    (socket:socket-server-close server))
  (sleep 1)
  (with-open-stream (s (socket:socket-connect 26001 "localhost" :timeout 30))
    (write-line "are you ready?" s)
    (finish-output s)))




Why not keeping the connection open and playing ping pong inside it,
with one server (ping) and one client (pong):

(defun pong (&optional (server-port 25001))
  (with-open-stream (s (socket:socket-connect 25001))
    (loop
       :repeat 4
       :initially  (format t "From ping: ~A~%" (read-line s)) (finish-output)
       :do (write-line "pong" s) (finish-output s)
       :do (format t "From ping: ~A~%" (read-line s)) (finish-output)
       :finally (write-line "done" s) (finish-output s))))


(defun ping (&optional (server (socket:socket-server 25001)))
  (unwind-protect
       (with-open-stream (s (socket:socket-accept server))
         (format s "200 Hello~%")                  (finish-output s)
         (loop
            :for cmd = (read-line s)
            :do (format t "From pong: ~A~%" cmd) (finish-output)
            :while (string-equal cmd "pong")
            :do (write-line "ping" s) (finish-output s)))
    (socket:socket-server-close server)))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"What is this talk of "release"?  Klingons do not make software
"releases".  Our software "escapes" leaving a bloody trail of
designers and quality assurance people in its wake."
From: Oisín Mac Fhearaí
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <c8fa46e1-c451-41a0-8998-b6d7c0de7500@m44g2000hsc.googlegroups.com>
Also, if you send data and immediately close that side of the
connection because ping has done its job, sometimes pong will
experience a connection reset or some other error which screws things
up. In my network code, I just brute forced things until they worked
without really understanding it (perhaps because I was coding a
relatively large application in Java and basically got fed-up and
lazy).
From: AngelP
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <e21bb218-b7bb-4e08-b5ad-6adaaf9f3680@k13g2000hse.googlegroups.com>
Thanks a lot for the recommendations.

And sorry for not being clear.

I have to test a server that implements this kind of protocol - client
sends request, and after awhile, server connects to the client and
sends the answer. The real server is written in c, but is not ready
for testing. To be able to prepare tests, I have written a server of
mine, but described problem arises. Code is from stripped down
communication part to investigate/demonstrate the problem. Workaround
with opened socket works fine, but still there are pending questions.

1. Why race conditions occurred - according to
http://clisp.cons.org/impnotes/socket.html#so-connect
connect will block for no more than :timeout seconds, so there is 3
sec time for the connection to be established.
2. Why error appeared on sending data. If the problem is that there is
no server, then error should be in (socket:connect) (as it is
when :timeout is not specified) but it stops on (write-line). - By my
understanding, that means, the connection has been accepted by the
server. But pong stays on "(socket:accept)", so according to the
server, connection is not accepted.

Do I miss something, or there is a problem in clisp's socket-connect
implementation?

Regadrs, Angel
From: Barry Fishman
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <m3skuzx7um.fsf@barry_fishman.acm.org>
AngelP <··········@gmail.com> writes:
> And sorry for not being clear.
>
> I have to test a server that implements this kind of protocol - client
> sends request, and after awhile, server connects to the client and
> sends the answer.

This is not the way TCP servers and sockets work.  If you try to connect
to a port that does not have a server listening the connection will be
refused.  Timeouts only help if you have trouble reaching the server
machine.

You might have your clients sleep and try again when connections fail.
This would require your servers to stay listening for a reasonable
amount of time and use the SO_REUSEADDR socket option.

You might have a continuously running broker server that accepts
connections from your "clients" and your "servers", and matches up
requests with applications that can resolve them.

You might try implementing your own style "client/server" on top of UDP.

-- 
Barry Fishman
From: Pascal J. Bourguignon
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <7cej6j59xk.fsf@pbourguignon.anevia.com>
AngelP <··········@gmail.com> writes:

> Thanks a lot for the recommendations.
>
> And sorry for not being clear.
>
> I have to test a server that implements this kind of protocol - client
> sends request, and after awhile, server connects to the client and
> sends the answer. The real server is written in c, but is not ready
> for testing. To be able to prepare tests, I have written a server of
> mine, but described problem arises. Code is from stripped down
> communication part to investigate/demonstrate the problem. Workaround
> with opened socket works fine, but still there are pending questions.
>
> 1. Why race conditions occurred - according to
> http://clisp.cons.org/impnotes/socket.html#so-connect
> connect will block for no more than :timeout seconds, so there is 3
> sec time for the connection to be established.

You used :timeout 30.  The problem was that the client process tried
to connect before the server could call listen(2).


> 2. Why error appeared on sending data. If the problem is that there is
> no server, then error should be in (socket:connect) (as it is
> when :timeout is not specified) but it stops on (write-line). - By my
> understanding, that means, the connection has been accepted by the
> server. But pong stays on "(socket:accept)", so according to the
> server, connection is not accepted.

Connection may be done asynchronously.  There may be options at the
raw sockets level to ask for synchronous connection.  Notice that
usually servers speak first, sending a "200 Hello" message, therefore
clients of these protocols won't send before the connection is really
established.


> Do I miss something, or there is a problem in clisp's socket-connect
> implementation?

I don't think  there's any problem with SOCKET-CONNECT.  If you need
more precise control, you may use the #+clisp RAWSOCK package.

-- 
__Pascal Bourguignon__
From: Barry Margolin
Subject: Re: CLISP - Unexpected connectionrefused
Date: 
Message-ID: <barmar-C33B52.08463527062008@newsgroups.comcast.net>
In article <··············@pbourguignon.anevia.com>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> AngelP <··········@gmail.com> writes:
> 
> > Thanks a lot for the recommendations.
> >
> > And sorry for not being clear.
> >
> > I have to test a server that implements this kind of protocol - client
> > sends request, and after awhile, server connects to the client and
> > sends the answer. The real server is written in c, but is not ready
> > for testing. To be able to prepare tests, I have written a server of
> > mine, but described problem arises. Code is from stripped down
> > communication part to investigate/demonstrate the problem. Workaround
> > with opened socket works fine, but still there are pending questions.
> >
> > 1. Why race conditions occurred - according to
> > http://clisp.cons.org/impnotes/socket.html#so-connect
> > connect will block for no more than :timeout seconds, so there is 3
> > sec time for the connection to be established.
> 
> You used :timeout 30.  The problem was that the client process tried
> to connect before the server could call listen(2).
> 
> 
> > 2. Why error appeared on sending data. If the problem is that there is
> > no server, then error should be in (socket:connect) (as it is
> > when :timeout is not specified) but it stops on (write-line). - By my
> > understanding, that means, the connection has been accepted by the
> > server. But pong stays on "(socket:accept)", so according to the
> > server, connection is not accepted.
> 
> Connection may be done asynchronously.

I don't know CLISP, but most network APIs implement connect() 
synchronously, unless the application specifically asks for non-blocking.

And if it is asynchronous, there should be a way to wait for it to 
complete.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***