Pete Darrow
Pete Darrow

Reputation: 455

setting up select() and write_fds in C

I must be doing something wrong at setting up select() and write_fds. Currently, when I call sendData(), for the first time, it sends 117 bytes (all of it) from the buffer. Then immediately it's called again even there's no more data to send in the buffer and it keeps calling sendData() forever.

Any idea what I am doing wrong here?

int readData(int j){
    return recv(j, buf , nbytes , 0);
}   
int sendData(int j){
    unsigned v = fcntl(j, F_GETFL, 0);
    fcntl(j, F_SETFL, v | O_NONBLOCK);

    return send(j, buf, nbytes, 0);
}   

fd_set master;   
fd_set read_fds; 
fd_set write_fds;   
int fdmax;       
...
FD_ZERO(&master);   
FD_SET(socket, &master);
fdmax = socket;

for(;;){
    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);

    read_fds = master; 
    write_fds = master;
    if(select(fdmax+1, &read_fds, &write_fds, NULL, NULL) == -1){
        exit(4);
    }   
    for(i = 0; i <= fdmax; i++){
        if(FD_ISSET(i, &read_fds)){
            if(i == socket){
                // handle new connections
                addrlen = sizeof remoteaddr;
                newfd = accept(socket, (struct sockaddr *)&addr, &addrlen);
                FD_SET(newfd, &master);
                if(newfd > fdmax) fdmax = newfd;
            }else{  
                // we got some data from a client
                readData(i); 
            }   
        } else if(FD_ISSET(i, &write_fds)){
            if(i != socket){
                // send data when notified
                sendData(i);
            }
        }    
    }   
}

Upvotes: 1

Views: 2340

Answers (2)

user207421
user207421

Reputation: 310907

Sockets are almost always writeable. You should only select on a socket for writeability if you have previously had an EAGAIN/EWOULDBLOCK from a send(), and you should cease doing so when the write has been retried and succeeded.

Upvotes: 0

Chris Dodd
Chris Dodd

Reputation: 126213

You're asking select to notify you when there is space in the network stack to send more data (that's what the write_fds are checking). Since you've only written 117 bytes, there's plenty of space, so it returns immediately, telling you to write more data.

As you don't have more data to send, what you want to do is remove that file descriptor from the write_fds set. You only want to add it to write_fds if the call to send returned a short write (unable to write all the data), or EWOULDBLOCK (assuming you have it set to non-blocking mode).

That brings up the major problem with your code -- you're calling send/recv without checking the return value, so you have no idea how much data was actually sent or received.

Upvotes: 2

Related Questions