Detecting a closed socket?

BlitzMax Forums/BlitzMax Programming/Detecting a closed socket?

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Well, the problem is using the built in functions with MAX, you really can't detect a client socket closing. Autoclose only works to close a socket that is garbage collected. The problem for me is, I've got an open socket for every client that connects to my server, but these won't autoclose if the client disconnects. Further, with the way things were my server couldn't receive the closing message and so never knew if a connection was actually alive or not (I could use a ping of sorts, and will end up doing so for potentially faulty connections (i.e. they haven't been able to receive in 15 seconds), but this shouldn't be necessary for connections that close normally and infact send a packet notifying you that they've closed!)

There are two ways, by default, that max provides you with to detect activity on a socket. Sock.ReadAvail() returns the # of bytes available to receive. Under the hood it's calling ioctl (or ioctlsocket() in Windows). A method strongly discouraged by many (from what I've read.)

The only other way in BMax to really tell if there is data available on a socket is to call Sock.Recv(). This normally returns -1 if nothing is available (and sets the error code to WSAEWOULDBLOCK), it returns 0 if the socket is closing, or otherwise returns the number of the bytes it actually read into the buffer provided.

For some reason the standard BMax socket module won't return -1 if nothing is available, but instead returns 0.
Method Recv( buf:Byte Ptr,count,flags=0 )
		Local n=recv_( _socket,buf,count,flags )
		If n<0 Return 0
		Return n
	End Method


Not sure why that is - but that prevents you from simply calling Recv() all the time and actually differentiating between 0 bytes to receive and a closed connection. Calling Recv() on all of your connections, even when there's nothing to receive, is also a bad practice.

The ideal approach (well, given that Bmax is using sockets 1.1) would either be Asynchronous sockets or the Select() method. I've ended up hacking together a Select() method - but due to the fact that a certain macro (FD_ISSET) isn't wrapped in any way available the code I ended up with is ugly.

Very ugly. It's so ugly I want to punch someone. I'm going to try and clean it up and then post it.