New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to detect a closed socket in a non-blocking way #12

Open
phoe opened this Issue Nov 29, 2015 · 3 comments

Comments

Projects
None yet
3 participants
@phoe
Contributor

phoe commented Nov 29, 2015

The API tells me what to do in two cases:

  • ...check whether reading from a socket stream will block, and
  • ...check whether the other end has closed my socket stream.

I find it impossible to:

  • ...check whether the other end has closed my socket stream without blocking.

Let's assume a following situation:

> (defparameter *socket* (socket-listen "localhost" 65035)) ;; => *SOCKET*
> (defparameter *stream* (socket-stream (socket-accept (wait-for-input *socket* :timeout 3000)))) ;; => *STREAM* ;after ncat localhost 65035
;; Ctrl-C on the ncat, socket gets closed, OR NOT, socket still open
> (listen *stream*) ;; => NIL

In a situation portrayed above, I should NOT do a (read-line *stream*) because (listen *stream*) gives me a NIL.

The issue I see is, (listen *stream*) gives a NIL in two cases:

  • when there is no data on the stream (usual case),
  • when there is an EOF on the stream (problematic case).
    And I am unable to separate these two cases.

In other words: is there any way to separate these two cases mentioned above?
In yet other words: in the situation portrayed within the code block, what command will reliably tell me whether the NIL given to me by the (listen *socket*) is because of lack of data or an EOF?

@phoe

This comment has been minimized.

Contributor

phoe commented Nov 29, 2015

Let me show what I do:

CL-USER> (use-package :usocket)
T
CL-USER> (defparameter *socket-no-data* (socket-listen "localhost" 65001)) 
*SOCKET-NO-DATA*
CL-USER> (defparameter *socket-closed* (socket-listen "localhost" 65002)) 
*SOCKET-CLOSED*
CL-USER> (defparameter *socket-no-data-accepted* (socket-accept (wait-for-input *socket-no-data* :timeout 3000)))
;; I connect using ncat localhost 65001
*SOCKET-NO-DATA-ACCEPTED*
CL-USER> (defparameter *socket-closed-accepted* (socket-accept (wait-for-input *socket-closed* :timeout 3000)))
;; I connect using ncat localhost 65002
*SOCKET-CLOSED-ACCEPTED*
;; Ctrl-C is sent to ncat localhost 65002, socket gets closed
CL-USER> (defparameter *socket-no-data-stream* (socket-stream *socket-no-data-accepted*))
*SOCKET-NO-DATA-STREAM*
CL-USER> (defparameter *socket-closed-stream* (socket-stream *socket-no-data-accepted*))
*SOCKET-CLOSED-STREAM*
CL-USER> (listen *socket-no-data-stream*)
NIL
CL-USER> (listen *socket-closed-stream*)
NIL
CL-USER> (wait-for-input *socket-no-data* :timeout 0)
#<STREAM-SERVER-USOCKET {10050D9163}>
NIL
CL-USER> (wait-for-input *socket-closed* :timeout 0)
#<STREAM-SERVER-USOCKET {10051DFD23}>
NIL
CL-USER> (wait-for-input *socket-no-data* :timeout 0 :ready-only t)
NIL
NIL
CL-USER> (wait-for-input *socket-closed* :timeout 0 :ready-only t)
NIL
NIL
CL-USER> (wait-for-input *socket-no-data-accepted* :timeout 0 :ready-only t)
NIL
NIL
CL-USER> (wait-for-input *socket-closed-accepted* :timeout 0 :ready-only t)
NIL
NIL
CL-USER> 

I see no way to tell the two sockets' state apart.

@glv2

This comment has been minimized.

Contributor

glv2 commented Mar 22, 2016

For a character stream, you could use something like:

(read-char-no-hang *socket-stream* nil :eof)

For a binary stream, it might be more difficult as there is no read-byte-no-hang function in the standard. Only a few implementations have it (I think clisp and allegrocl have it).

@cyclohexanamine

This comment has been minimized.

cyclohexanamine commented Sep 24, 2016

For SBCL on Windows,

(read-char-no-hang *socket-closed-stream* nil :eof)

returns NIL regardless of whether the socket is closed or just blocking. It gives :eof for closed streams on SBCL/Linux and CCL/Linux when I tested those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment