Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
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 new in Linux and having problem with FD_ISSET to detect second file descriptor for udp socket. There are 2 clients connecting to my udp socket server, I'm setting FD_SET (fdA), FD_SET (fdB) for each client. But the FD_ISSET is only detect the first fdA for the client B (expected FD_ISSET(fdB) is TRUE)
I cannot fully comment on what is causing the issue you are having, however the code below should work; of course, you will need to add the "extras" around it to meet your needs.
If you are planning to support more than two clients, I would recommend that you consider going with a multi-threaded application, where one thread listens for connections, and another thread handles client requests.
Thank you for your suggestion. I did the same thing like your code for first connection with client A. But when A disconnects, I did not update the rfds_save, so the second connection with client B, I still receive activity on fdA.
To update the rfds_save, do I have to update fdMax?
FD_CLR(fdA, &rfds_save);
To update the rfds_save, do I have to update fdMax?
You're welcome. I don't know for sure if it is absolutely required to update fdMax, however I always did.
Long ago (4+ years ago) I wrote a multi-threaded application in C++ which enabled the server to handle many client connections. I had one thread whose sole purpose was to accept connections, and maintain this list of connected clients, and to make this information (e.g. fd_set, maxFD, and client objects) available.
Another thread, which performed the select(), and subsequent read() operations for a particular client object, was responsible for managing received messages, and notifying the first thread when a client disconnected.
Anyhow, let me know if you have further questions.
On my server-like program, there is one thread for select(), FD_ISSET() and recv() in a loop of two steam sockets, the other thread handles conection call control.
The rfds_save is never changed which always has fdA and fdB.
My problem is when there are two connections, FD_ISSET() in receive thread detects only fdA and does not detect fdB.
Do you know how to assign fdA or fdB to accept different connections?
A server has an open port, which is managed by a socket descriptor. It uses select() to determine if there is activity on that socket (i.e. if a client is connecting). If there is activity on the socket, then the server accepts the client connection. Here's the code for the "listener" thread:
// Determine if anyone is attempting to connect to the listen socket. // If not, then continue; else accept the connection. // if (select(m_listen_socket+1, &listen_set, NULL, NULL, &timeout) == 0) continue;
if (!(FD_ISSET(m_listen_socket, &listen_set))) continue;
// Accept connection (loop back on error) // int sock_len = sizeof(sock); int fd = -1;
The accept_connection() method creates a new client object with the unique file-descriptor 'fd' for that client. The next client that connects would have a different file-descriptor.
The receiver portion of the server, which is another thread, uses select() that monitors each of the file-descriptors assigned to connected clients. When select() reports activity, the returned fd_set is passed to the object serving as the listener-thread; this thread then reports which client sent data. Only then does the receiver thread get a handle to the client object. Here's how I did that:
PHP Code:
// Receiver thread loop while (!stop_requested()) { // Setup file descriptor list for select call // struct timeval timeout = {1, 0}; // one second fd_set read_set; const uint nfds = m_debug_listen.get_client_set(read_set);
// Check if there is any data traffic to be read on any of the // file descriptors. // if (select(nfds+1, &read_set, NULL, NULL, &timeout) == 0) { dbg[*this] << "select timed out" << el; continue; }
dbg[*this] << "Detected Activity" << el;
// Activity detected... find out if its from one of the clients // we are monitoring. Record any clients that send us bad data or // that disconnect. // TDD_debug_client *client = m_debug_listen.get_debug_client(read_set);
if (client == NULL) { dbg[*this] << "Client object could not be found" << el; continue; }
// Now that the client handle is available, attempt to read data // from it. Remove the client if it has disconnected. // ... }
I'm certain that there are other ways to model the server application, so please don't feel your design is deficient if it differs from mine. I was very new (and still am) to socket programming when I wrote this code long ago.
Last edited by dwhitney67; 01-16-2008 at 02:38 PM.
Reason: Grammar and spelling corrections.
No I do not. However, that is not to say you can't.
My accept_connection() method merely creates a new client object, using the socket descriptor for that client.
I implemented a separate method in my 'listener' thread to perform the FD_SET (looping through my list of clients). When done, this method returns both the fd_set value and the max-FD (or 'nfds') to the caller (i.e. the thread waiting for activity from clients). These values are then used within the select().
// Check if there is any data traffic to be read on any of the // file descriptors. // if (select(nfds+1, &read_set, NULL, NULL, &timeout) == 0) ...
I suppose you could do the FD_SET in your "accept connection" method, but eventually you will still require to know the highest-numbered socket descriptor for use in the select() call.
Btw, your little exercise piqued my interest in revamping my skills with socket programming. Below are the listings of my Listener and Receiver threads, followed by the Client Manager -- all written in C++ and relying on the Boost libraries. This was hastily thrown together yesterday, so it may not be the best design. In fact, it probably would be nice to have a separate Receiver thread for each client, rather than one to service them all.
#include <netinet/in.h> #include <cstring> // for memset() #include <cerrno> // for errno #include <iostream> // for cerr, endl
// Constructor // (I) port - port number to listen for client connections. // (I) maxClients - max number of clients that may connect. // (I) clientMgr - object for managing list of connected clients // Listener::Listener( const int port, const int maxClients, ClientMgr &clientMgr ) : m_port( port ), m_maxClients( maxClients ), m_clientMgr( clientMgr ) { // do nothing here }
// Destructor // Listener::~Listener() { // do nothing here }
// Constructor // (I) port - port number to listen for client connections. // (I) maxClients - max number of clients that may connect. // ClientMgr::ClientMgr() { // do nothing here }
// Destructor // ClientMgr::~ClientMgr() { // do nothing here }
// Returns socket descriptor client set for clients that are connected // (O) clientSet - socket descriptor set that is returned // // Returns the highest numbered socket descriptor of the connected clients. // int ClientMgr::getClientSet( fd_set &clientSet ) { boost::mutex::scoped_lock lock( m_mutex );
FD_ZERO( &clientSet );
int nfds = 0;
for ( Iterator it = m_clientList.begin(); it != m_clientList.end(); ++it ) { FD_SET( it->first, &clientSet );
nfds = std::max( nfds, it->first ); }
return nfds; }
// Returns handle to client object // (I) activeClient - socket descriptor set returned by select() // Client * ClientMgr::getClient( const fd_set &activeClient ) { boost::mutex::scoped_lock lock( m_mutex );
Client *client = 0;
for ( Iterator it = m_clientList.begin(); it != m_clientList.end(); ++it ) { if ( FD_ISSET( it->first, &activeClient ) ) { client = it->second; break; } }
return client; }
// Remove a disconnected client from the list of clients // (I) client - the client object // void ClientMgr::removeClient( Client *client ) { boost::mutex::scoped_lock lock( m_mutex );
Iterator it = m_clientList.begin();
for ( ; it != m_clientList.end(); ++it ) { if ( it->second == client ) { close( it->first ); delete it->second; m_clientList.erase( it ); client = 0; break; } } }
// Creates a new client object. // (I) sd - socket descriptor assigned to connected client. // void ClientMgr::acceptConnection( const int sd ) { boost::mutex::scoped_lock lock( m_mutex );
if ( m_clientList.find( sd ) == m_clientList.end() ) { m_clientList[ sd ] = new Client( sd ); } }
Last edited by dwhitney67; 01-18-2008 at 02:17 AM.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.