I'm having a bit of trouble figuring out how to detect if a socket is closed or not. Outside of using read()/write(). I also don't want to set the socket to non-blocking if at all possible.
I wrote a function that reads a single char(or byte, whatever) and wanted to use it in a simulated blocking and nonblocking way.
It works fine for waiting for the correct timeouts, but since I use ioctl() to detect if there is data to be read, I won't actually call the read() method that would show me the socket is closed.
I was thinking there was some way to detect "can write" or "can read" on a file descriptor without going into a blocking state, but I can't find it if there is one. -
read_ret_t ReadChar(int sock, int milisecondTimeout, char &refchar)
-
{//-1=errors, 0=closed, 1=timeout, ?=ok?
-
enum read_ret_t retval=ERRORED ;
-
char buf[10]={0x00};
-
char nbyte[10]={0x00};
-
int numofwaits=0;
-
if(milisecondTimeout!=0)
-
{// "non-blocking"
-
refchar=0x00;
-
while(numofwaits<milisecondTimeout)
-
{
-
int bytestoread=0;
-
int d=ioctl(sock, FIONREAD, &bytestoread);//should do error checking on return value of this
-
if(d!=0)printf("ioctl()=%d\r\n",d);
-
//int fd=write(sock,nbyte,1);//writing a single 0x00 byte can trigger fd=-1 when closed
-
if(bytestoread>0)
-
{
-
int res=read(sock,buf,1);
-
if (res<0)
-
{retval=ERRORED;}
-
else if(res==0)
-
{retval=CLOSED;}
-
else
-
{retval=OK;}
-
-
refchar=buf[0];
-
break;
-
}
-
else
-
{
-
usleep(1000);//1000uSecs = one milisec
-
numofwaits=numofwaits+1;
-
}
-
}
-
if (numofwaits>=milisecondTimeout)
-
{
-
retval=TIMEDOUT;
-
}
-
-
}
-
else
-
{//blocking
-
int res=read(sock,buf,1);
-
if (res<0)
-
{retval=ERRORED;}
-
else if(res==0)
-
{retval=CLOSED;}
-
else
-
{retval=OK;}
-
-
refchar=buf[0];
-
}
-
-
return retval;
-
}
-
Any thoughts on a non-blocking way to detect if a blocking call has timed out?
I toyed with changing the socket option of receive timeouts to a very small time and using like recv with the PEEK option, but that seemed like the wrong way to go.
11 17183
My memory is really fuzzy on this topic, but I think I've accomplished something like this in the past by setting a timer, then calling read(). Then if the timer expires you get an interrupt, which makes the read fail, setting errno appropriately. That way you can just start the read and if the socket is closed you'll get that error too and you wont have to worry about blocking for too long.
I can't for the life of me remember how to accomplish timers in C and my usual references aren't handy at the moment.
@Plater
If you don't want to use a read() call on the socket (the read() might succeed if the socket is still open and connected and where should the byte be put?) you can call a select on that single file/socket descriptor; if the socket is not connected and not ready for a read the errno variable is set to EBADF and the select() function will return -1 (if I'm not mistaken).
kind regards,
Jos
I was looking at the select function, but it seemed to have a lot of structs and overhead and I wasn't even sure it would tell me what i wanted.
It also said it was a blocking call
EDIT:
FD_ISSET doesn't change between open and closed fd
EDIT AGAIN:
Ok, so select can be given a timeout, and it behaves a lot like Poll() does in C# (I imagine Poll just calls select)
Seems that checking for writable/exceptional never changes, but checking for readable will trigger if their is data to be read of if the socket is closed.
And since I have another check already to see if there is data, I can combine them to find out.
Thanks for all the help!
@Plater
Yep, if doesn't change those flags when an error occurs; check for the return status of select() and the errno variable. Those sets are simply bit sets with a bit set for every file descriptor number, e.g. bit 0 is set for stdin. FD_ISSET simply checks for a particular bit value; the FD_SET and FD_CLR macros (re)set that particular bit.
kind regards,
Jos
For those who are interested, here is what I have: -
bool isClosed(int sock)
-
{
-
bool retval =false;
-
int bytestoread=0;
-
fd_set myfd;
-
-
FD_ZERO(&myfd);
-
FD_SET(sock,&myfd);
-
int sio=select(FD_SETSIZE,&myfd, (fd_set *) 0,(fd_set *) 0, &timeout);
-
//have to do select first for some reason
-
int dio=ioctl(sock, FIONREAD, &bytestoread);//should do error checking on return value of this
-
retval=((bytestoread==0)&&(sio==1));
-
-
return retval;
-
}
-
@Plater
Isn't select() supposed to return -1 when the descriptor is closed?
kind regards,
Jos
@JosAH
Maybe if it is closed on the local side, but since i am using a socket, it could be closed remotely
@Plater
But in that case a read would simply fail; isn't your software prepared for that event? i.e. no more data can be read ...
kind regards,
Jos
@JosAH
Yes, if I actually DO a read, I would get the failure message, but since I only do a read if there is data there to be read, that is where the problem arises. And thus, the select() call
@Plater
Ah, ok, you only read given some sort of an event caused by incoming data. That select() call is ideal for that in a separate thread ... but it's of no use when the line is dead on the other side.
kind regards,
Jos
@JosAH
Well its working just perfect for it so far
Post your reply Sign in to post your reply or Sign up for a free account.
Similar topics
22 posts
views
Thread by Bryan |
last post: by
|
5 posts
views
Thread by John Marshall |
last post: by
|
reply
views
Thread by Marco Nicosia |
last post: by
|
3 posts
views
Thread by Sagaert Johan |
last post: by
|
2 posts
views
Thread by John Regan |
last post: by
|
reply
views
Thread by Didier Trosset |
last post: by
|
reply
views
Thread by nik |
last post: by
|
5 posts
views
Thread by yinglcs |
last post: by
|
15 posts
views
Thread by =?ISO-8859-15?Q?L=E9na=EFc?= Huard |
last post: by
| | | | | | | | | | |