How can I implement recv that will timeout after a predetermined amount of time?

The Stevens book talks about setting the SO_RECVTIMEO socket option to force recv to timeout after a period of time. Another popular way is to use the select or poll statement. You can register the socket file description with select as you would with any other regular file description and select supports setting a timeout on it. Select will then return either after something is available to be read on the socket, or the timeout has expired. You can easily figure out which case occurs by checking the bitmap returned by select. Here is some sample code:
   int sockfd;
   fd_set readfds, masterfds;
   struct timeval timeout;
 
   ...

   sockfd = socket(...);

   timeout.tv_sec = 10;                    /*set the timeout to 10 seconds*/

   timeout.tv_usec = 0;

 
   FD_ZERO(&masterfds);
   FD_SET(sockfd, &masterfds);

   memcpy(&readfds, &masterfds, sizeof(fd_set));

   if (select(sockfd+1, &readfds, NULL, NULL, &timeout) < 0)
   {
     perror("on select");
     exit(1);
   }

   if (FD_ISSET(sockfd, &readfds))
   {
     // read from the socket
   }
   else
   {
     // the socket timedout
   }

Lab Assignment: Based on Lab 2's Echo Server and Echo Client, add timeout feature to Echo Server. That means echo server will wait to read() for a period of time. If the server hasn't received message within the period, the server will print "client time out" at server's screen.