So for this assignment, you're going to modify your card dealer server and client from the last assignment to use TCP. This should mean only minimal changes - call the open_tcp_srvr_sock() function instead of the open_udp_srvr_sock() function, right? Unfortunately, nothing is that easy. Once you've opened a TCP server socket, every time you accept a connection from another client, you've got another socket to handle. At any point in time after the first client has connected, the server can't afford to just call accept() on the main server socket, or recv() on a client connection, because the call would block and the server would be ignoring all the other sockets.
There are several different ways to handle this, and you'll get a chance to try some of them on for size in this and the next three assignments. For this one, we'll try a simple, but not terribly efficient, technique known as polling. This is sort of like the polling that we talked about for link level protocols; the server will just loop through all of its sockets on a regular basis, checking each one to see if it has anything happening.
In order to do this, it is important that the server doesn't block on any socket call. You make this happen by changing putting each socket in non-blocking mode. You can do this using the fcntl() call with the O_NDELAY or O_NONBLOCK flag (O_NDELAY is the old constant, and it is now #defined to be O_NONBLOCK). You can see an example of this in the section on Asynchronous Broadcast in Gary's Unix Network Programming Manual. This example is also working with asynchronous I/O, which we won't worry about now. Just look through the code for O_NDELAY - you should do something similar, without also setting the O_ASYNC flag.
Once you have a socket set to non-blocking mode, you can call accept() or recv() on it without getting stuck. So you can set up a loop in your program where you do an accept() on the main server socket then a recv() on each client connection socket, handling any of them that has anything to do, and then do it all over again. This is known as a poll loop. If you do just that, in a really tight loop, it's likely that you will suck up most of your machine's CPU doing just that. So after you've made a pass through all the sockets, you should put in a call to sleep(), so the program will take a break before polling again. A value of one second should work pretty well.
Modify your server as specified - you can give it a new name, but everything else should work just as it did for the previous program. Also create a modified client that uses TCP to connect to the server.
Note that now you are using TCP, so you will be able to call recv() and know when a client breaks the connection. When that occurs, you should close the client socket. You will still need to use <CTRL>-C to break out of the program when you are done running it, because it should always be polling the main server socket (using accept) while it is running.
Suppose your source is in the files my_net_clnt.c and my_net_srvr.c. (I'm not advocating this as the best way to divide things, just using it as an example.) You can use the following commands to create an archive file:
gcc -c -o my_net_clnt.o my_net_clnt.c
gcc -c -o my_net_srvr.o my_net_srvr.c
ar -r libmy_net.a my_net_clnt.o my_net_srvr.o
gcc -o tcp_card_server tcp_card_server.c -lmy_net
You should include the following: