2

I have a fd_set "write_set" which contains sockets that I want to use in a send(...) call. When I call select(maxsockfd+1, NULL, &write_set, NULL, &tv) there it always returns 0 (timeout) although I haven't sent anything over the sockets in the write_set yet and it should be possible to send data.

Why is this? Shouldn't select return instantly when it's possible to send data over the sockets in write_set?

Thanks!

Edit: My code..

// _read_set and _write_set are the master sets
fd_set read_set = _read_set;
fd_set write_set = _write_set;

// added this for testing, the socket is a member of RemoteChannelConnector.
std::list<RemoteChannelConnector*>::iterator iter;
for (iter = _acceptingConnectorList->begin(); iter != _acceptingConnectorList->end(); iter++) {

    if(FD_ISSET((*iter)->getSocket(), &write_set)) {

        char* buf = "a";
        int ret;
        if ((ret = send((*iter)->getSocket(), buf, 1, NULL)) == -1) {
            std::cout << "error." << std::endl;
        } else {
            std::cout << "success." << std::endl;
        }

    }

}

struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;

int status;

if ((status = select(_maxsockfd, &read_set, &write_set, NULL, &tv)) == -1) {

    // Terminate process on error.
    exit(1);

} else if (status == 0) {

    // Terminate process on timeout.
    exit(1);

} else {
// call send/receive
}

When I run it with the code for testing if my socket is actually in the write_set and if it is possible to send data over the socket, I get a "success"...

simon
  • 41
  • 3
  • Are you sure _maxsockfd is correct ? It has to be 1 greater than the file descriptor in any of your read_set or write_set. In the actual code above you don't have _maxsockfd + 1, whist you do in the question. – nos May 21 '11 at 12:19
  • -1 for C++ code tagged C. Also, prefixing symbol names with `_` is almost always wrong. – R.. GitHub STOP HELPING ICE May 21 '11 at 12:24
  • @nos Aw yeah that was it, thanks you. – simon May 21 '11 at 12:31
  • 1
    +1 just because I think R.. is being mean. Prefixing with `_` is an accepted convention for prefixing C++ instance variables. – Dietrich Epp May 21 '11 at 12:33
  • What kind of sockets are these? Are they connected? Bound? Datagram? Stream? – Dietrich Epp May 21 '11 at 12:38
  • I'm using TCP stream sockets. They are bound and connected. – simon May 21 '11 at 12:41
  • 1
    @Dietrich Epp Let me tell you about the time I had to debug a rather large program that sometimes crashed horribly when run on a new platform. It turns out someone had defined a `_write_err()` function. Well. It turned out a system library also had a _write_err() function called on an error path of another system function, defined as a weak symbol. So on that case the _write_err() function of the program got called instead of the system _write_err function. It was not fun. Same goes for variables, at least globals. Don't prefix them with _ – nos May 21 '11 at 15:13
  • @nos: Instance variables never have linkage. – Dietrich Epp May 21 '11 at 23:54

2 Answers2

0

I don't believe that you're allowed to copy-construct fd_set objects. The only guaranteed way is to completely rebuild the set using FD_SET before each call to select. Also, you're writing to the list of sockets to be selected on, before ever calling select. That doesn't make sense.

Can you use poll instead? It's a much friendlier API.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    Regarding copying fd_sets: http://stackoverflow.com/questions/2421672/are-there-any-platforms-where-using-structure-copy-on-an-fd-set-for-select-or – John Zwinck May 21 '11 at 13:18
  • With "writing to the list of sockets to be selected on" are you referring to the send() call? If yes, this purely for testing and isn't there in the actual code. I just wanted to test if the sockets are actually in the sets and if I could send something over them. @John Thanks, I will use FD_COPY then. – simon May 21 '11 at 13:57
0

Your code is very confused. First, you don't seem to be setting any of the bits in the fd_set. Secondly, you test the bits before you even call select.

Here is how the flow generally works...

  • Use FD_ZERO to zero out your set.
  • Go through, and for each file descriptor you're interested in the writeable state of, use FD_SET to set it.
  • Call select, passing it the address of the fd_set you've been calling the FD_SET function on for the write set and observe the return value.
  • If the return value is > 0, then go through the write set and use FD_ISSET to figure out which ones are still set. Those are the ones that are writeable.

Your code does not at all appear to be following this pattern. Also, the important task of setting up the master set isn't being shown.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194