[ LiB ] |
Now that you know how to use the select() function, I want to show you how to actually use it to create an enhanced version of the "Hello Internet Server" program, Demo 2.1.
Instead of accepting just one packet, this program goes through a perpetual loop, using the select() function to poll the open sockets to see which have activity on them. Sounds easy, doesn't it?
This demo can be found in the directory /Demos/Chapter02/Demo03-HelloInternetServerV2/, in the file Demo03.cpp. As with the other demos in this chapter, this one also begins with Code Blocks 2.1 and 2.2, so I do not show them.
This time, a socket management system is needed to keep track of all of the open data sockets. To store them, I am using a vector , which is essentially an array. (See Appendix C on the CD if you are unfamiliar with vectors.) This is how the main routine of the demo starts:
int main() { int err; // for getting errors int lsock; // listening socket vector<int> socketlist; // list of sockets // start the socket library StartSocketLib;
There is an error variable, a listening socket, and a vector of data sockets that is currently empty.
After this, Code Block 2.3 is inserted (see Demo 2.1), and that basically takes care of creating lsock as a listening socket.
NOTE
I call the vector a "list of sockets," but don't confuse that with the STL container called list .
The following code comes after the listening socket has been created. It basically creates all of the variables you need for the demo:
fd_set rset; // the read-set int i; // a generic iterating variable struct timeval zerotime; // the zero-time timeval structure zerotime.tv_usec = 0; zerotime.tv_sec = 0; char buffer[128]; // used for getting messages bool done = false; // used for quitting vector<int>::iterator itr; // a vector iterator
This should be self-explanatory. In the next part, the loop is begun, and the socket set is cleared out and filled with the listening and data sockets:
while( !done ) { // clear the set FD_ZERO( &rset ); // add the listening socket FD_SET( lsock, &rset ); // add all of the data sockets for( itr = socketlist.begin(); itr != socketlist.end(); itr++ ) FD_SET( *itr, &rset );
After the set is filled with all the sockets you want to check, you can call the select function to find out which sockets have activity:
i = select( 0x7FFFFFFF, &rset, NULL, NULL, &zerotime );
After that, I check to see if i is more than 0, which indicates that there were sockets with activity. If there was activity, I check to see if there are any incoming connections on the listening socket:
if( i > 0 ) { if( FD_ISSET( lsock, &rset ) ) { // incoming connection int dsock = accept( lsock, (struct sockaddr*)&socketaddress, &sa_size ); // add the socket to the list socketlist.push_back( dsock ); }
After that, I loop through every data socket in the vector and check to see if there is activity on any of them. If there is activity on any of them, the function attempts to receive the data:
// loop through each socket and see if it has any activity for( itr = socketlist.begin(); itr != socketlist.end(); itr++ ) { if( FD_ISSET( *itr, &rset ) ) { // incoming data err = recv( *itr, buffer, 128, 0 );
At this point, err should contain the number of bytes received: 0 if the socket was closed, or -1 if there was an error. Here is the code that handles that:
// quit if there's an error: if( err == -1 ) { cout << "Socket receiving error!" << endl; return 0; } // just shut down and close sockets that have been disconnected if( err == 0 ) { shutdown( *itr, 2 ); CloseSocket( *itr ); socketlist.erase( itr ); // erase socket from list // move iterator back because we removed an item: itr--; } // write out the data to the server window: else { cout << "Data: " << buffer << endl; if( strcmp( buffer, "servquit" ) == 0 ) done = true; } } } } }
Most notable is the code that checks to see if the socket was disconnected. If it was disconnected, the function calls the shutdown and CloseSocket functions, and then the socket is removed from the vector. The iterator is decremented at the end of that block, because you've deleted an item, and the iterator skips over the next item in the vector if it isn't decremented.
The last block prints out the data it has received and checks to see if the text was servquit , which means a message was sent by the client telling the server to shut down.
Finally, here is the code that closes all sockets that are still open and shuts down:
shutdown( lsock, 2 ); CloseSocket( lsock ); for( i = 0; i < socketlist.size(); i++ ) { shutdown( socketlist[i], 2 ); CloseSocket( socketlist[i] ); } CloseSocketLib; }
Well, that's all there is to it. So now you can try compiling and running it. You can use Demo 2.2 to connect to this server, but it only prints the same message over and over; the server never quits. That's okay though; you can press Ctrl+C on your keyboard to halt the program.
[ LiB ] |