Detecting if a file descriptor is closed

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Plater
    Recognized Expert Expert
    • Apr 2007
    • 7872

    Detecting if a file descriptor is closed

    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.

    [code=c]
    read_ret_t ReadChar(int sock, int milisecondTimeo ut, 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(milisecondTi meout!=0)
    {// "non-blocking"
    refchar=0x00;
    while(numofwait s<milisecondTim eout)
    {
    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,n byte,1);//writing a single 0x00 byte can trigger fd=-1 when closed
    if(bytestoread> 0)
    {
    int res=read(sock,b uf,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=numo fwaits+1;
    }
    }
    if (numofwaits>=mi lisecondTimeout )
    {
    retval=TIMEDOUT ;
    }

    }
    else
    {//blocking
    int res=read(sock,b uf,1);
    if (res<0)
    {retval=ERRORED ;}
    else if(res==0)
    {retval=CLOSED; }
    else
    {retval=OK;}

    refchar=buf[0];
    }

    return retval;
    }
    [/code]

    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.
  • mac11
    Contributor
    • Apr 2007
    • 256

    #2
    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.

    Comment

    • JosAH
      Recognized Expert MVP
      • Mar 2007
      • 11453

      #3
      Originally posted by Plater
      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.
      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

      Comment

      • Plater
        Recognized Expert Expert
        • Apr 2007
        • 7872

        #4
        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!

        Comment

        • JosAH
          Recognized Expert MVP
          • Mar 2007
          • 11453

          #5
          Originally posted by Plater
          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
          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

          Comment

          • Plater
            Recognized Expert Expert
            • Apr 2007
            • 7872

            #6
            For those who are interested, here is what I have:

            [code=c#]
            bool isClosed(int sock)
            {
            bool retval =false;
            int bytestoread=0;
            fd_set myfd;

            FD_ZERO(&myfd);
            FD_SET(sock,&my fd);
            int sio=select(FD_S ETSIZE,&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=((bytest oread==0)&&(sio ==1));

            return retval;
            }
            [/code]

            Comment

            • JosAH
              Recognized Expert MVP
              • Mar 2007
              • 11453

              #7
              Originally posted by Plater
              For those who are interested, here is what I have:
              [snip]
              Isn't select() supposed to return -1 when the descriptor is closed?

              kind regards,

              Jos

              Comment

              • Plater
                Recognized Expert Expert
                • Apr 2007
                • 7872

                #8
                Originally posted by JosAH
                Isn't select() supposed to return -1 when the descriptor is closed?

                kind regards,

                Jos
                Maybe if it is closed on the local side, but since i am using a socket, it could be closed remotely

                Comment

                • JosAH
                  Recognized Expert MVP
                  • Mar 2007
                  • 11453

                  #9
                  Originally posted by Plater
                  Maybe if it is closed on the local side, but since i am using a socket, it could be closed remotely
                  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

                  Comment

                  • Plater
                    Recognized Expert Expert
                    • Apr 2007
                    • 7872

                    #10
                    Originally posted by JosAH
                    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
                    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

                    Comment

                    • JosAH
                      Recognized Expert MVP
                      • Mar 2007
                      • 11453

                      #11
                      Originally posted by Plater
                      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
                      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

                      Comment

                      • Plater
                        Recognized Expert Expert
                        • Apr 2007
                        • 7872

                        #12
                        Originally posted by JosAH
                        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
                        Well its working just perfect for it so far

                        Comment

                        Working...