Repository navigation
Socket close detection #212
Description
Activity
Copying from #211:
-- | If you're operating `Socket` in multithread environment, -- for example, use a timeout thread to close `Socket`. you have to -- make sure `Socket` is opened before read/write, 'withConnectedSocket' -- will run your action if `Socket` is still 'Connected', otherwise -- return the 'Socket' status instead. -- -- Note, this will block other thread which try to close `Socket` by locking -- the status `MVar`. withConnectedSocket :: Socket -> (Socket -> IO a) -> IO (Either SocketStatus a) withConnectedSocket sock@(MkSocket _ _ _ _ statusVar) act = withMVar statusVar $ \status -> case status of Connected -> act sock _ -> return (Left status)
@eborden I would like to do two things:
- Merging
withConnectedSocketto thenetworkpackage - Updating documentation to describe that safer packages should be implemented separately based on
withConnectedSocket
Reacted by Evan Rutledge Borden- Merging
- added a commit that references this issue
on Dec 28, 2017 withConnectedSocketis now inmaster.I don't fully understand why, but
withConnectedSocketwas removed in ceba911 Perhaps this reasoning a few weeks prior is relevant? #286 (comment)What's the status of this functionality (detecting when a client disconnects/closes so that the server can kill an expensive computation)? A few other issues seem related but don't appear to have a definitive answer (e.g. #302).
Another use case where cancellation is especially important is when using websockets. AFAICT the only workaround is to use a heartbeat (i.e. require the client to ping every 30s).
I don't fully understand why, but
withConnectedSocketwas removed in ceba911 Perhaps this reasoning a few weeks prior is relevant? #286 (comment)The current
Socketdoes not have status. We decided to not maintain socket status in Haskell side.What's the status of this functionality (detecting when a client disconnects/closes so that the server can kill an expensive computation)? A few other issues seem related but don't appear to have a definitive answer (e.g. #302).
This is a famous issue of system call. Not Haskell problem. There is no way to detect socket status in the OS kernel without trying to send or receive data.
Another use case where cancellation is especially important is when using websockets. AFAICT the only workaround is to use a heartbeat (i.e. require the client to ping every 30s).
I don't know what you want to implement exactly. If you want to close idle connections, the
timeoutandrecvcan be used. Iftimeoutis too expensive, you can try thetime-managerpackage.Recently, I implemented very cheap
timeout: https://github.com/kazu-yamamoto/quic/blob/master/Network/QUIC/Timeout.hsThanks for the definitive answer 🙇♂️
There is no way to detect socket status in the OS kernel without trying to send or receive data.
Is there a way that I could convince myself of this, too? It seems to work in Node.js:
var WebSocketServer = require('websocket').server; var http = require('http'); var server = http.createServer(); server.listen(1337); wsServer = new WebSocketServer({ httpServer: server }); wsServer.on('request', function(request) { var connection = request.accept(null, request.origin); connection.on('close', function() { console.log('CLOSE') }); });
$ websocat ws://localhost:1337 Ctrl+CAfter Ctrl+C, the Node.js process prints "CLOSE".
I'm not very familiar with sockets, so I'm probably not understanding something here. Does http://stefan.buettcher.org/cs/conn_closed.html provide any answers?
I guess that the
closecallback is called whenrecv(2)returns 0.I think that node is using
epoll(2). Whenepoll()tells that RX is available for a socket,recv(2)is called. RX gets available when either any data is received or EOF (TCP Fin) is received.
This is actually a continuation of #169 and pr #211 , I'm starting a new thread because i realized there's one more problem we should get done: how should we detect a
Socketclose event.The obvious way is to catch
IOErrorwhen usingread/write. in #211 we take this step further so thatread/writeon a closedSocketis guaranteed to throw anIOError, no matter who close the socket, which fix a bug of unix itself in some sense.But what if we want to actively detect if a
Socketis closed? let's say we're performing a expensive calculation to respond a waiting client, it's reasonable to periodically check if theSocketis still opened, otherwise we can cancel the calculation, but currently withnetworkwe can't do that. it's a interesting problem in other language too, please read this to get a understand of how complex of unix socket.here's some thought:
Exceptionsituation in network. but i don't know how we can get backward compatibility if we change the exception type.read/writewith new one, which guarantee to throw whenSocketwas closed, and we should document about throwing behavior clearly. AMVaris cheap comparing actual IO operation.recvMaybe :: Socket -> Int -> Maybe ByteString. sadly i don't think we can do much for sending functions: returning aMaybe ()looks silly.isConnectedis not ideal for reasons i listed above, we can provide a proper implementation with a new name, but i'm not sure if we can do it under windows.In #211 , i proposed
withConnectedSocket, but this function has a subtle problem: you can't use any operations which read the socket status inside it. the problem is insidewithMVar, theMVaris empty, if we use anything which try totakeMVar, we produced a deed lock.I'm not sure if we sure we should do these in another
network-safepackage, feel free to discuss about above points : ).