472,125 Members | 1,569 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,125 software developers and data experts.

Detecting if a file descriptor is closed

Plater
7,872 Expert 4TB
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.

Expand|Select|Wrap|Line Numbers
  1. read_ret_t ReadChar(int sock, int milisecondTimeout, char &refchar)
  2. {//-1=errors, 0=closed, 1=timeout, ?=ok?
  3.   enum read_ret_t retval=ERRORED ;
  4.   char buf[10]={0x00};
  5.   char nbyte[10]={0x00};
  6.   int numofwaits=0;
  7.   if(milisecondTimeout!=0)
  8.   {// "non-blocking"
  9.     refchar=0x00;
  10.     while(numofwaits<milisecondTimeout)
  11.     {
  12.       int bytestoread=0;
  13.       int d=ioctl(sock, FIONREAD, &bytestoread);//should do error checking on return value of this
  14.       if(d!=0)printf("ioctl()=%d\r\n",d);
  15.       //int fd=write(sock,nbyte,1);//writing a single 0x00 byte can trigger fd=-1 when closed
  16.       if(bytestoread>0)
  17.       {
  18.         int res=read(sock,buf,1);
  19.         if (res<0)
  20.         {retval=ERRORED;}
  21.         else if(res==0)
  22.         {retval=CLOSED;}
  23.         else
  24.         {retval=OK;}
  25.  
  26.         refchar=buf[0];
  27.         break;
  28.       }
  29.       else
  30.       {
  31.         usleep(1000);//1000uSecs = one milisec
  32.         numofwaits=numofwaits+1;
  33.       }
  34.     }
  35.     if (numofwaits>=milisecondTimeout)
  36.     {
  37.       retval=TIMEDOUT;
  38.     }
  39.  
  40.   }
  41.   else
  42.   {//blocking
  43.     int res=read(sock,buf,1);
  44.     if (res<0)
  45.     {retval=ERRORED;}
  46.     else if(res==0)
  47.     {retval=CLOSED;}
  48.     else
  49.     {retval=OK;}
  50.  
  51.     refchar=buf[0];
  52.   }
  53.  
  54.   return retval;
  55. }
  56.  
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.
Mar 11 '09 #1
11 17183
mac11
256 100+
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.
Mar 12 '09 #2
JosAH
11,448 Expert 8TB
@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
Mar 12 '09 #3
Plater
7,872 Expert 4TB
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!
Mar 12 '09 #4
JosAH
11,448 Expert 8TB
@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
Mar 12 '09 #5
Plater
7,872 Expert 4TB
For those who are interested, here is what I have:

Expand|Select|Wrap|Line Numbers
  1. bool isClosed(int sock)
  2. {
  3.   bool retval =false;
  4.   int bytestoread=0;
  5.   fd_set myfd;
  6.  
  7.   FD_ZERO(&myfd);
  8.   FD_SET(sock,&myfd);
  9.   int sio=select(FD_SETSIZE,&myfd, (fd_set *) 0,(fd_set *) 0, &timeout);
  10.   //have to do select first for some reason
  11.   int dio=ioctl(sock, FIONREAD, &bytestoread);//should do error checking on return value of this
  12.   retval=((bytestoread==0)&&(sio==1));
  13.  
  14.   return retval;
  15. }
  16.  
Mar 12 '09 #6
JosAH
11,448 Expert 8TB
@Plater
Isn't select() supposed to return -1 when the descriptor is closed?

kind regards,

Jos
Mar 12 '09 #7
Plater
7,872 Expert 4TB
@JosAH
Maybe if it is closed on the local side, but since i am using a socket, it could be closed remotely
Mar 12 '09 #8
JosAH
11,448 Expert 8TB
@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
Mar 12 '09 #9
Plater
7,872 Expert 4TB
@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
Mar 12 '09 #10
JosAH
11,448 Expert 8TB
@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
Mar 12 '09 #11
Plater
7,872 Expert 4TB
@JosAH
Well its working just perfect for it so far
Mar 12 '09 #12

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
reply views Thread by Didier Trosset | 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
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.