Demo 2.3 Hello Internet Server v2

[ 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.


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 ]

MUD Game Programming
MUD Game Programming (Premier Press Game Development)
ISBN: 1592000908
EAN: 2147483647
Year: 2003
Pages: 147
Authors: Ron Penton © 2008-2017.
If you may any questions please contact us: