3013 Project 3

Electronic Handball

Due date: Saturday, October 2nd, by 11:59pm

Index


Overview

This assignment is intended to introduce you to using sockets in a client-server system. The server processes communicate with shared memory and synchronize by using semaphores. Each client process communicates to a server via a socket. You are to implement the program described below on any CCC Alpha machines (reno, bert, ernie, scooter, wpi ...)


Handball

You are to make a multi-player game of computer handball (handball is a made-up variation of pong that will allow 2+ people play the same ball-bouncing type of game with paddles). Your handball game must have:

Here is a screen-shot of a possible game in action:

                  Freddy: 3    Billy: 8   Marky: 6

                             Freddy's Turn

		/-------------------------------------- \
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|    *                                  |
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|                                       |
		|                 =====                 |
		|                                       |
		|                                       |

                        j- left, k- right, space- stop

(Coming soon! You can try out the above game at: /cs/cs3013/server and /cs/cs3013/handball.)

You are free (and encouraged) to be creative with any of the game aspects, including speed, direction, paddle size, characters, keyboard controls, scoring ...


Behind the Scenes

The game is made up of clients and servers. The servers share the game state between them. The clients access the servers to get the game state and then display it on the screen. The clients also send paddle and ball movement (when appropriate) to the servers.

The server "listens" on a pre-chosen port on it's host workstation. As an analogy, if the host workstation is a street name (say, Institute Road), then the port is the house number on that street (say, 100). The port is specified as an integer. You should choose a port number between 5001 - 9999. Together, a <host,port> pair gives the address for the server. You can assume the server is started first. Using the host and the port, the client will connect to the server.

When the server receives a connection, it does a fork() to create a child process to service the request. The client and the child will then communicate along the connected socket. The child will retrieve any needed information for the client, and send that information back along the connected socket (the communication is 2-way). When the child is finished, it sends an "exit" message to the client and terminates. The parent, meanwhile, has returned to listening on the original socket and port, waiting for connections from other clients.

Technically, there is no output to a terminal required by the server, but you will probably find it helpful to have the server display status messages for logging and debugging.

In all cases, the server should handle errors such as validating the data sent by the clients, socket connections, fork requests, etc.


Old Hat

As in project 2, you will use curses to help with the text-based aspects of the program. You can also use shared memory and semaphores to synchronize among the server processes, and signals for alarm handlers and graceful cleanup of resources.

Note that the shared memory wrappers from project 2 limit you to 2K. You can modify this by changing a value in the shm.h header file. If you do so, please use care. Also, the shared memory wrappers will only let you create 1 shared memory segment at a time. This is a limitation of the wrappers, not of Unix shared memory. If you want more than one shared memory segment, you will have to modify the wrapper source code.


New Hat

You will use sockets for your client-server communication. To simplify the use of sockets, you may use some code wrappers written especially for this project. The source file containing these wrappers are sock.c and a header file containing prototype definitions is sock.h. The routines provided in sock.h are:

/* sockcreate -- Create socket from which to read.
   Takes port as argument.
   Return socket descriptor if ok, -1 if not ok.  */
int sockcreate(int port);

/* sockaccept -- accept connection on a socket.
   Takes socket descriptor (from sockcreate) as argument.
   Return new socket descriptor if ok, -1 if not ok. */
int sockaccept(int sock);

/* sockconnect -- create socket to host at port.
   Takes host name (ex- "reno") and port as argument.
   Return socket if ok, -1 if no ok. */
int sockconnect(char *host, int port);

You will also use the non-wrapped system calls of send and recv. In particular, the socket descriptors returned by sockcreate() and sockconnect() are parameters to send() and recv(). Do a man 2 send and a man 2 recv for more information. See the Samples section for an example of how these wrappers might be used.

As with the shared memory and semaphore wrappers, you must compile the file sock.c yourself. Do this by downloading both the sock.c and sock.h files to your directory and using the command gcc -c sock.c. Better still, use a Makefile (see Makefiles in project 2 for more information) to compile.

Note, unlike message queues, shared memory and semaphores, sockets are removed for you by the OS when your process terminates.

Pseudo-code for your handball server might look like:

  create shared memory

  create semaphore

  set signal handler to catch C-c

  while (1) {

    accept connections

    fork child

    if (parent) then continue

    make sure not too many players

    receive message with players name

    add player to game 

    while (!done) {

          /* play game */

          receive message (command)

          move paddle (if appropriate)

          send message (board)

    }

    remove player

    exit child process

  }

  remove shared mem and sem

Pseudo-code for your handball client might look like:

  connect to server

  set up signal handler for sending messages on Control-C

  send login information /* name */

  while(!done) {

    send read request /* to get game state */

    draw on screen /* chat */

    if (my turn)

        get paddle move

        move ball

        send update        

    sleep until alarm

  }

  send logout information

end

Questions

Answer the following questions when you turn in your project:

...
  1. There are some network protocols that do not guarantee that all the bytes you send() will arrive at the other process' recv() call. In other words, if you send a paddle move or a board update, it may not arrive. Briefly describe how you would modify your client and server to handle such a network protocol.

  2. There were two architectural solutions to this project that were discussed in class: forked server where the server process forks a child to handle each client, and select server where a single server process handles all clients with the help of the select() call. Which did you use? Describe one advantage of your approach. Describe one advantage of the alternate approach.


Return to 3013 Home Page

Send all questions to the TA mailing list.