Sockets & Server Sockets

It is easier to demonstrate the functioning of a server socket, because we have a ready made client using a web browser. Unlike the previous tutorials, this one, ServerSocketSample.cpp, is console based. Let us examine the creation of the sockets:

00006:   void main()
00007:   {
00008:     char buf[15] = {0};                   //Data received buffer.
00009:     int msgsize = 0;                      //Message size
00010:   
00011:     //Create a server socket that will listen on port 8080
00012:     ServerSocket ss( 8080 );
00013:     Socket& s = ss.accept();              //Accept a conection

The parameter passed to ServerSocket's constructor is an integer that represents the port that the server will listen in on for a connection. To accept a connection you call the accept() method. This method returns a Socket object. To save on memory and time you should decare the variable that will catch it as a reference, which I have done in line 13. If there was an error, accept() will return an unconnected socket. So simply check to see if the socket is connectd like so:

00015:     //Make sure the connection is valid
00016:     if ( !s.isConnected() )
00017:     {
00018:       cout << Socket::getLastError() << endl;
00019:   
00020:       //If it is a bad connection
00021:       //close the server socket
00022:       //and return.
00023:       ss.close();
00024:       return;
00025:     }

Since we are only going to process one connection, if we encounter an error we output it and close the server socket. The method getLastError() is a static method that returns a string that contains a verbose error message pertaining to the last error that occured. If the client connected okay, then the next thing we do is process the data sent by the client.

00027:     //While we are not at the end of the header
00028:     do
00029:     {
00030:       //Set the buffer to NULL
00031:       memset( buf, NULL, 15 );
00032:       msgsize = s.recv( buf, 14 );        //Recieve a portion of the message
00033:       if ( msgsize < 0 )                  //Make sure there was no error
00034:       {
00035:         cout << "\n\n" << Socket::getLastError() << endl;
00036:         break;
00037:       }
00038:       else
00039:           cout << buf;                    //Output the message
00040:     } while ( strcmp( &buf[msgsize - 4], "\r\n\r\n" ) != 0 );
00041:     cout << endl;                         //Flush the output buffer.

There are several key things to note about the way we handled the receiving of the data. First, notice on line 32 that we cut the buffer size by one. We do this becuase if we passed in 15, the recv() method would have filled up all fifteen bytes with data. That means we would not have had a null terminated string for outputing on line 36. Secondly, recv() returns the number of bytes placed into the buffer or a negative number representing an error code. Notice our check on line 33. All methods of ServerSocket and Socket return a negitive integer when there is an error. So you can check for errors by examining the return value for a number less than zero. Thirdly, you are probably wondering about that strange check done by the while loop. Well HTTP requests terminate in "\r\n\r\n". So we take the size of our message and move back four places and compare. The important thing to note is that if the client is done sending data recv() will still attempt to receive data, in essence it will block indefinitly. So when receiving data you should always check for some kind of terminater character or sequence of characters. Now we can send data to the client like so,

00044:     //Send a message to the client
00045:     s << "Received Header Information.";

This will send to the client the string "Received Header Information." To send non-null terminated data you can use send() method. It looks the same as recv() It just sends the buffer to the client.

Lets run the example to give you a concrete understanding. Compile and execute the example program. Then using Internet Explorer® type in the address bar http://localhost:8080 and press ENTER. The console should output something like this.

And Internet Explorer® should display this.

Finally you should close the sockets like this.

00047:     //Close the sockets.
00048:     s.close();
00049:     ss.close();

It is important that you explicitly close every socket that gets opened. Windows does not automatically close a socket when your program exits. So those sockets stay opened until you restart the computer.