I am reading and writing to TCP socket via a duplex handle h.
In the client:
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
connect sock $ addrAddress addr
h <- getSocketHandle conn
In the server:
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
setSocketOption sock ReuseAddr 1
withFdSocket sock setCloseOnExecIfNeeded
bind sock $ addrAddress addr
listen sock 1024
forever $ do
(conn, _) <- accept sock
h <- getSocketHandle conn
forkFinally (server h) (const $ hClose h)
where:
getSocketHandle :: Socket -> IO Handle
getSocketHandle conn = do
h <- socketToHandle conn ReadWriteMode
hSetBinaryMode h True
hSetNewlineMode h NewlineMode {inputNL = CRLF, outputNL = CRLF}
hSetBuffering h LineBuffering
return h
When both the client and the server are available, it all works fine, but when the TCP connection terminates, e.g. because the client or the server exit, nothing happens - hGetLine
/hPutStrLn
just block the thread.
How can I make them throw exception?
Similarly, if the client fails to connect (e.g. because of the server not responding), connect
also just blocks.
I suspect I should somehow set the timeouts on the socket, but experimenting with socket options didn't change much - I tried SO_LINGER, SO_KEEPALIVE, SO_USER_TIMEOUT doesn't seem to be supported by the system (it blocks when I try to get it), SO_RCVTIMEO / SO_SNDTIMEO don't seem to be supported by Network.Socket - at least that's what the docs say...
For connect
/hPutStrLn
I could use timeout
from System.Timeout
(it seems a hack, but it will work), but for hGetLine
/hGet
it won't work - it can just wait for user input, so it should only throw exception when the connection terminates.
I should probably just read the network programming - I was hoping to figure it out quickly... Any help is really appreciated.
EDIT: It seems like I should be using lower level send
/sendAll
and recv
, do buffering and cutting to lines in my code (or read byte by byte - probably it would be buffered anyway as set in listen
) and treat 0 length returns by recv
as disconnection. Isn't there a way to make it work via handle with higher level functions?
question from:
https://stackoverflow.com/questions/65858284/detecting-when-tcp-connection-fails-to-open-or-is-terminated 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…