Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

select on UDP socket doesn't end when socket is closed - what am I doing wrong?

I'm working on Linux system (Ubuntu 7.04 server with a 2.6.20 kernel).

I've got a program that has a thread (thread1) waiting on a select for a UDP socket to become readable. I'm using the select (with my socket as the single readfd and the single exceptfd) instead of just calling recvfrom because I want a timeout.

From another thread, I shutdown and close the socket. If I do this while thread1 is blocked in a recvfrom, then the recvfrom will terminate immediately. If I do this while thread1 is blocked in a select with a timeout, then the select will NOT terminate immediately, but will eventually timeout properly.

Can anyone tell me why it is that the select doesn't exit as soon as the socket is closed? Isn't that an exception? I can see where it isn't readable (obviously), but it's closed, which seems to be to be exeptional.

Here's the opening of the socket (all error handling removed to keep things simple):

m_sockfd = socket(PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in si_me;
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(port);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(m_sockfd, (struct sockaddr *)(&si_me), sizeof(si_me)) < 0)
{
// deal with error
}

Here's the select statement that thread1 executes:

struct timeval to;
to.tv_sec = timeout_ms/1000;// just the seconds portion
to.tv_usec = (timeout_ms%1000)*1000;// just the milliseconds 
                                    // converted to microseconds

// watch our one fd for readability or
// exceptions.
fd_set  readfds, exceptfds;
FD_ZERO(&readfds);
FD_SET(m_sockfd, &readfds);
FD_ZERO(&exceptfds);
FD_SET(m_sockfd, &exceptfds);

int nsel = select(m_sockfd+1, &readfds, NULL, &exceptfds, &to);

UPDATE: Obviously (as stated below), closing the socket isn't an exceptional condition (from select's point of view). I think what I need to know is: Why? And, Is that intentional?.

I REALLY want to understand the thinking behind this select behavior because it seems counter to my expectations. Thus, I obviously need to adjust my thinking on how the TCP stack works. Please explain it to me.

like image 433
Michael Kohne Avatar asked Jan 19 '09 18:01

Michael Kohne


People also ask

Do UDP sockets need to be closed?

Close the socket Since there is no concept of a connection in UDP, there is no need to call shutdown.

Do UDP sockets need to bind?

The datagram can be sent from any address/port so the socket needn't be bound. The datagram must be sent to a particular address/port (so that information will have to be passed to the function that does the sending)

Why does UDP only need one socket?

For UDP, the socket API allows one socket to receive from many endpoints, and to send to many endpoints - so many servers use just one socket since there isn't any need for more. In some cases, the protocol is a simple request and reply.

Does UDP open a socket?

UDP is a very simple protocol. Messages, so called datagrams, are sent to other hosts on an IP network without the need to set up special transmission channels or data paths beforehand. The UDP socket only needs to be opened for communication. It listens for incoming messages and sends outgoing messages on request.


3 Answers

Maybe you should use something else to wake up the select. Maybe a pipe or something like that.

like image 101
iny Avatar answered Oct 03 '22 19:10

iny


UDP is a connectionless protocol. Since there is no connection, none can be broken, so the consumer doesn't know that the producer will never send again.

You could make the producer send an "end of stream" message, and have the consumer terminate upon receiving it.

like image 27
John Zwinck Avatar answered Oct 03 '22 19:10

John Zwinck


Could you not send a signal (e.g. USR2) to the thread which would cause select() to return with EINTR? Then in the signal handler set a flag telling it not to restart the select()?

That would remove the need for waiting on multiple file descriptors, and seems a lot cleaner than using a pipe to kill it.

like image 28
Richard Whitty Avatar answered Oct 03 '22 18:10

Richard Whitty