Archived

This topic is now archived and is closed to further replies.

Structural

fd_set under unix

Recommended Posts

I''m struggling with a port of my network module to a unix system. I used to store all sockets in an fd_set structure under windows, and this structure under windows has these nice members called "fd_count" and "fd_array". The first one contains the nr of entries, and the array contains all the actual data. I had the habbit of using fd_count and fd_array to loop through the array when sending something to all connected clients or when shutting down. Now, the Unix fd_set, doesn''t have the fd_count and fd_array members, and I''m kind of baffled on how to accomplish my neat loops. Does anyone know if I can get the count of the set and how I can get to the data?

Share this post


Link to post
Share on other sites
You check the elements with the FD_ISSET() macro. The number of elements you''re supposed to keep track of yourself.

Share this post


Link to post
Share on other sites
Alright... thanks... that clarifies some things.

I also just got input from someone here near me. I now see I didn''t quite understand the structure of the file descriptor set.

The fd set is a structure containing handles to data generators (lacking a better word), right?. The fd_set is a binary set, with every bit representing a file descriptor.

Aparently the windows version keeps an internal list of which fd''s (bits) are set as integer, and the actual list of bits is kept somewhere else (as it''s not in the header). So it''s easier to loop through it.

I think I prefer the windows way. Now I have to loop through the entire fd_set, checking every bit. Or is there a way to do it quicker?

Share this post


Link to post
Share on other sites
Then keep track of the file descriptors yourself. Stick them in a vector or something.

Share this post


Link to post
Share on other sites
No offense, but your use of the fd_set structure in Winsock goes against the recommended use to begin with. The documentation for select() in the API documentation says specifically to treat it as an opaque type. Had you done it the right way in the first place, you wouldn''t be having troubles now.

Share this post


Link to post
Share on other sites
You should have a master FD_SET and a read or write FD_SET. First copy the socket you open for listening to master and read (or write but I'll use the read set alone). Use a list or vector of type socket or of a struct with a socket member. Also copy the initial listening socket to the vector. When you drop out of select for the first time and subsequent times check for socket elements in the read/write set using FD_ISSET against the elements in the vector/list, and proceed accordingly. If after the return from select the listening socket is set in the read/write set then you have a connection request queued, so you'll either reject it or add it to the vector after calling accept as well as adding it to the master set by calling FD_SET. At the end of your loop copy the master set back into the read/write set and continue on. The key is that the read or write fd_set will be reduced to what sockets are in a state to read/write respectively. It will remove sockets from the set you are polling that are in a neutral state. That is why you'll maintain a master set to copy back to the read/write set at the end before calling select once again. Hope this helps.

EDIT: If you are using unix you can use the first parameter from select as the amount of file descriptors and use those for comparison. But the first parameter is ignored in windows, so for cross platform compatibility consider using my method unless you find better.

[edited by - nervo on April 6, 2004 9:40:25 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by SiCrane
No offense, but your use of the fd_set structure in Winsock goes against the recommended use to begin with. The documentation for select() in the API documentation says specifically to treat it as an opaque type. Had you done it the right way in the first place, you wouldn't be having troubles now.


I see it written in the docs now, and I can't do anything but agree with you.
So, I'm going to change my programming to only use the defined macro's instead of fiddling in the set directly. That should fix a load of problems.

Do you have any other tips for the port? Like things to make macros of? things that are often different on different OS-es? This is the first time I program things for anything else than Windows, so I could use a few tips

[edited by - Structural on April 6, 2004 9:38:29 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Nervo
You should have a master FD_SET and a read or write FD_SET. First copy the socket you open for listening to master and read (or write but I''ll use the read set alone). Use a list or vector of type socket or of a struct with a socket member. Also copy the initial listening socket to the vector. When you drop out of select for the first time and subsequent times check for socket elements in the read/write set using FD_ISSET against the elements in the vector/list, and proceed accordingly. If after the return from select the listening socket is set in the read/write set then you have a connection request queued, so you''ll either reject it or add it to the vector after calling accept as well as adding it to the master set by calling FD_SET. At the end of your loop copy the master set back into the read/write set and continue on. The key is that the read or write fd_set will be reduced to what sockets are in a state to read/write respectively. It will remove sockets from the set you are polling that are in a neutral state. That is why you''ll maintain a master set to copy back to the read/write set at the end before calling select once again. Hope this helps.

EDIT: If you are using unix you can use the first parameter from select as the amount of file descriptors and use those for comparison. But the first parameter is ignored in windows, so for cross platform compatibility consider using my method unless you find better.

[edited by - nervo on April 6, 2004 9:40:25 AM]


That helps a lot!

Share this post


Link to post
Share on other sites
Just to be clear, as was said the first parameter to select (nfds) is ignored in Winsock. On Unix you have to set it correctly. What you have to set it to is the value of the largest fd plus one, *not* the number of fds as would be logical.

IMHO select wins the award for the worst api design in the entire computing universe.

Share this post


Link to post
Share on other sites
I''ve seen implementations who give FD_SETSIZE as first parameter. Would this be correct? The BSD fd.h header and the VxWorks docs I have here seems to agree, although the windows fd''s I''ve seen go far over the value of 64 (the value FD_SETSIZE under both Windows and BSD).

quote:

If either pReadFds or pWriteFds is NULL, they are ignored. The width parameter defines how many bits will be examined in the file descriptor sets, and should be set to either the maximum file descriptor value in use plus one, or simply to FD_SETSIZE. When select( ) returns, it zeros out the file descriptor sets, and sets only the bits that correspond to file descriptors that are ready. The FD_ISSET macro may be used to determine which bits are set.



Would this have a performance impact?

Share this post


Link to post
Share on other sites
woohoo... it works... even though I've been chasing bugs all day that weren't there.

I'm compiling and running the app on a remote target through a telnet session, and it seems that only printf's in the main thread are shown in the telnet window. Printf's in other threads are only shown in the terminal at the target.
If I had known that, I wouldn't have spent all afternoon figuring out why I didn't see my "data thread started" messages.
I figured it out when the guy at the target said someone "has been spamming the targets terminal with weird printf's".

Oh well... Learned something new again today... Don't spam someone elses target

[edited by - Structural on April 7, 2004 3:34:24 PM]

Share this post


Link to post
Share on other sites