ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm working on a server-like program which calls select in a loop using multiple stream sockets. All descriptors in the program are non-blocking, so select and a pthread_cond_wait somewhere else are the only blocking points I have.
I'm having a "problem" when a connected client exits and the cooresponding socket descriptor on the server isn't the first in the select list. The select call doesn't break until another descriptor has data ready or until the first descriptor's other end closes. In other words, the only break for an unreadable socket happens when that socket is the first in the list. This keeps the descriptor hanging, but more importantly, keeps the program from accurately updating the status of what's connected.
As an example:
client X connects to the server (placed 1st with FD_SET)
client Y connects to the server (placed 2nd with FD_SET)
client Z connects to the server (placed 3rd with FD_SET)
...
client Y exits and implicitly closes it's connections
the socket for Y is still a part of the select list until either X or Z send data or X exits
I experimented with a timeout for select, but I'd be better off using while (read(...) < 0); or something similarly attrocious because of its processor intensity.
I get the feeling I'm partially lucky to get what I am getting due to undefined behavior. The main goal is to have a blocked server except for when something is happening. Thanks.
ta0kira
PS The exit happens during the blocked select call. I haven't been able to create a situation where the exit happens between the select calls since.
... I experimented with a timeout for select, but I'd be better off using while (read(...) < 0); or something similarly attrocious because of its processor intensity.
I don't quite understand what is atrocious about using a timeout with select(). Doesn't your server thread have to check if there are other clients connecting? How will it do so if it is suspended while waiting for activity from an existing client?
When a client disconnects, select() reports activity with the client's socket. At this point, the server will not know what type of activity has occurred until a read() is performed. If the read() operation returns a value less than zero, then you know that the client has disconnected.
Here's a code snippet of a multi-threaded server I worked on many years ago that handles data incoming from multiple clients. Note that client connections where handled in a separate thread.
PHP Code:
while (!stop_requested()) { // Setup file descriptor list for select call // struct timeval timeout = {1, 0}; // one second fd_set readSet; const uint32_t nfds = m_clientList.getClientSet(read_set);
// Check if there is any data traffic to be read on any of the // file descriptors. // if (select(nfds+1, &readSet, NULL, NULL, &timeout) == 0) { dbg[*this] << "select timed out" << el; continue; }
// The code below to determine the client was actually done in a // a mutex-protected method within the m_clientList object. I've // shown it here just to show the gist of what needed to get the // handle to the client object (if any). // Client *client = NULL;
for (Iterator it = m_clientList.begin(); it != m_clientList.end(); ++it) { if (FD_ISSET(it->first, &readSet)) { client = it->second; } }
if (client == NULL) { dbg[*this] << "Client object could not be found" << el; continue; }
// Client is known. // bool newMsgAvailable = true;
while (newMsgAvailable == true) { char msg[MsgAPI::MAX_MSGLEN] = {NULL}; size_t msgSize = client->getNextMsg(msg, sizeof msg); // read() done in here
switch (msgSize) { case Client::NO_NEW_MSG: dbg[*this] << "No new message received" << el; newMsgAvailable = false; break;
case Client::MSG_TOO_LARGE: case Client::CLIENT_DISCONNECTED: dbg[*this] << "Msg Too Large or Client Disconnected" << el; m_clientList.removeClient(client); newMsgAvailable = false; break;
Your processor shouldn't have jumped to 90% because of the select(). It was probably something else on your system (or your application, if it is multithreaded) that is causing the issue.
Compile and run the following program, and verify if indeed the process is taking up a substantial amount of CPU time.
Actually, the place where I used select with a timeout was for a bound local socket. The socket was open the entire time, and literally the only change was the addition of a 100ms timeout. Non-blocking accept with a 100ms retry in its place kept processor useage low, so, it wasn't the loop code. The matter of having a closed socket is a different one, though. It did take place within a pthread, so that might be the problem. I'll try to duplicate both conditions: the timeout and the non-first descriptor.
The way I do test for a closed socket is to take the result of select (as long as errno isn't EINTR) and try to read each descriptor (non-blocking.) If I get a 0 read then I close it and remove it from the list. shutdown does seem to force select to break, though.
ta0kira
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.