0
votes

I wrote a server/client program. And use select check socket. But when client close socket(tcp status in server will get in close_wait), select always return 1 and errno is 0.

Why select return 1? Tcp socket have nothing to read now!

server:

int sock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(6999);
socklen_t socklen = sizeof(struct sockaddr_in);
bind(sock, (struct sockaddr *)&addr, socklen);
listen(sock, 0);

int clisock;
clisock = accept(sock, NULL, NULL);

fd_set backset, rcvset;
struct timeval timeout;
timeout.tv_sec = 3;

int maxfd = clisock+1;
FD_SET(clisock, &rcvset);
backset = rcvset;

int ret;
while(1) {
    rcvset = backset;
    timeout.tv_sec = 3;
    ret = select(maxfd, &rcvset, NULL, NULL, &timeout);
    if(ret <= 0)
        continue;

    sleep(1);
    printf("ret:%d, %s\n", 
        ret, strerror(errno));
}

client:

int sock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(6999);

socklen_t socklen = sizeof(struct sockaddr_in);
connect(sock, (struct sockaddr *)&addr, socklen);

sleep(3);
close(sock);
sleep(100);

output:

./server 
ret:1, Success
ret:1, Success
ret:1, Success
2
When the remote end-point closes its connection, the local end-point will become readable, but with read returning 0. That is the indication that the remote end-point has been closed, read returning 0.Some programmer dude
Regarding your use of errno, don't check it unless there actually is an error, and always check it directly after the erroneous function call (i.e. if select fail you have to check errno directly after select). Think about what would happen if sleep failed? Then errno would contain the error from the sleep function.Some programmer dude
You have told select() that you want a notification when you can read from the socket. You should read from the socket, then you can check if reading from the socket give you an error on that socket. (select() can watch many sockets, select() is not going to indicate an error on one particular socket when you watch the socket for read events). If you chose to not read from the socket when select() tells you that you can, select() will tell you that you still can read from it on the next iteration too.nos
And lastly, remember that select modifies the sets, so if you have multiple descriptors in the sets you pass to select, you have to clear the set and add all descriptors again.Some programmer dude
The value of errno if there is no error is undefined, don't check it unless there is an error.Some programmer dude

2 Answers

2
votes

The socket is readable because the peer has closed it and when you read from it you will get an end of stream. Rather than nothing.

CLOSE_WAIT means that TCP is waiting for you to close the socket. So close it.

1
votes

Select returns because there is an event on one of the sockets it monitors. The documentation uses the term "readable". In this cas it is somewhat misleading since the socket on the other end is closed from and there are no bytes to read from it. The reason why the documentation is phrased like that is because select works on any kind of file descriptor. The "file" could be a socket, a pipe or a normal file. They didn't want to get entangled by the specifics of the different types of file descriptor.

That the socket on the other end is closed is normal, so select should not return an error in this case. When you try to actually read from your socket you will get an error once you have read all available data, if the connection has been closed on the other end.

Since select can monitor several file descriptors at once, and uses a single bit for each file descriptor it would be impossible to differentiate between "data has arrived" and "the socket on the other end has been closed". Both events will flag the socket as "readable".

The same goes when monitoring for writing. If the other side closes its endpoint the socket will be flagged as "writable" as far as select is concerned. You won't get the error until you actually try writing to the socket.