You must work with one partner on this assignment, and I'd like at least one partner in each group to be someone who has taken CS45.
The server should be able accept multiple, simultaneous client connections so that clients requests do not interfere with each other. However, when you first write the server, write it so that it supports just one client connection at a time, then add support for multiple, simultaneous connections once that works.
The server program should never exit (except when you CNTL-C it, it should exit); if no clients are currently connected, it just waits around for the next client connection. Your server should detect when a client has exited and terminate its end of the connection.
You can decide how your server mangles strings, but your server should be consistent (i.e. is should be either a reverse mangler or a cyclic cipher mangler, or ...). Here are some examples of ways to mangle a string:
% nslookup curry ... Address 130.58.68.36 % client 130.58.68.36 # start the client and try to connect to server # running on curry, # client program should print a prompt for user to enter text Enter the next message: hello there # then send the "hello there" string to the server that will mangle the # received string and send the mangled string back to the client. As a # debugging step, have the server print out the received string and # the returned mangled string. # the client should then print out the result HELLO THERE #the client repeats printing the prompt, reading input, sending ... Do you want to continue (yes/no): yes Enter the next message:
Start by copying over my starting point code into your private directory:
% cp /home/newhall/public/cs85/hw1_startingpt/* . % ls Makefile README client.c mangler.h server.cRead through the README file and the comments in the client and server to help you get going. Also, I'd suggest looking over a TCP/IP programming reference before you get going:
Read through my C Style Guide and make sure that your code conforms to it (good comments, good modular design, robust, etc.).
Start by getting the TCP connection protocol correct: implement a simple client and server program that create sockets and connect and pass a simple message from client to server (send an int value for example), and then try sending a simple response message from server to client.
Once that works, implement the mangling server so that it handles just a single client connection at a time. Once you get that to work, then add support to the server for handling multiple, simultaneous client connetions, and making sure to clean up dead child server processes when they exit (get rid of zombies). Finally, stress test your solution to ensure it is both correct and robust.
Some problems you will need to think about: how the server knows when it has read all of the string sent to it by a client in a single request; how the server knows when a client has terminated its connection; and how to ensure that two clients requests don't interfere with each other.
int pid;
// create a new child process
pid = fork();
if(pid == -1) {
// fork returned an error, handle it
} else if (pid == 0) { // this is the child process:
// child code to handle this specific connection
// until the child exits
} else { // this is the parent process:
// parent process to get ready to accept the next connection
}
In the server set up a sighandler routine that will be invoked when the parent receives a SIGCHILD from an exiting child process:
void my_sigchild_handler(int x)
{
while(waitpid(-1, NULL, WNOHANG) > 0) { }
}
Before accepting connections and forking child threads, register your
signal handler on SIGCHILD by calling sigaction:
struct sigaction myhandler;
...
//set the handler to my_sigchild_handler
myhandler.sa_handler = my_sigchild_handler;
// initialize the set of signals:
sigemptyset(&myhandler.sa_mask);
// set the flags...I'm not sure what the best setting is,
// but this works pretty well (it is a flag that say to
// restart a system call if the signal occurred during a syscall)
myhandler.sa_flags = SA_RESTART;
// call sigaction to register my handler with SIGCHILD signals:
if (sigaction(SIGCHLD, &myhandler, NULL) == -1) {
// something bad happend, lets exit
perror("sigaction");
exit(1);
}
See the man pages for sigaction and wait to get include files and to find out
more about sigaction.
struct linger linger_val; linger_val.l_onoff = 0; linger_val.l_linger = 0; setsockopt(sock_fd, , SO_LINGER, (void *)linger_val, (socklen_t) (sizeof(struct linger));
# info for tcp sockets on machine netstat -tcp -v # proc files with socket info: /proc/net/dev # device information /proc/net/raw # raw socket information /proc/net/tcp # TCP socket information /proc/net/udp # UDP socket information /proc/net/ipx # IPX socket information /proc/net/snmp # statistics # get my IP addr ifconfig # in the eth0 entry it is "inet addr:" entrygetting the state of a process
# one way to find state of server processes: ps -A | grep myserver 27318 pts/2 00:00:00 myserver 27321 pts/2 00:00:00 myserver # if you see a listing like this, then you are not correctly handling SIGCHILDS 27321 pts/2 00:00:00 myserver <defunct> # /proc/pid contains info about process with matching pid: cat /proc/27321/status # this contains the state of the process
see my Unix Help pages for information about creating a tar file using tar.