You can try out talk on our systems. For example, if user jo on machine foo wants to talk with user mo on machine blah, jo will enter the command:
% talk mo@blahtalk on blah sends a message to the talk daemon (talkd) on foo to initiate setting up a talk connection between jo and mo. The talk daemon of foo will send a message to the console window notifying mo how to respond to start a talk session with jo. For example, mo would see something like this:
Message from Talk_Daemon@foo at 13:36 ... talk: connection requested by jo@foo talk: respond with: talk jo@fooThen mo would type the following to finish the talk connection and begin remotely talking with jo:
% talk jo@foo
For this assignment, we are going to implement a system that is similar to Unix talk (we will simplify some of the connection issues associated with talk). The goal of this assignment is to give you some practice writing an interface specification, and writing a client and server application using TCP sockets. You should write your solution as a C or C++ program that makes Unix system calls to create, set up a connect, read, write, and close a socket.
Because one goal of this assignment is to develop an interface for talk clients and servers, I'd like to have at least 3 different groups implementing a solution so that we can test if different group's clients and servers can speak to each other). You should work with one or two partners on this assignment, and I'd like at least one partner in each group to be someone who has taken CS45 (Jeff, Adam, Trilok, or Drew).
During the talk session, the client and server alternate turns waiting for a message from the other (which will be sent a line of input at a time) and sending a message to the other. The client should be the first one to send a message (a line of input). Note that this is different than talk where both parties can "simultaneously" send and receive messages from the other.
For this assignment, we will only worry about the server being able to handle one client connection and talk session at a time (for the next assignment we will add multiple, simultaneous connections).
% nslookup curry ... Address 130.58.68.36 % ./talk_client 130.58.68.36 # start the client and try to connect to server # running on curry (IP 130.58.68.36) # when the connection succeeds, the client program should print a prompt # for user to enter a line of text to send to the server: enter next message: hello there # then send the "hello there" string to the server and wait for the server # to send a response. When the client receives the server's response, # it should print it out, and then ask the user if he/she wants to continue, # and if so, print out the prompt for the user to enter the next line of # test to send to the server: talk server response: hi, what's up? enter next message: # the client repeats printing the prompt, reading input, sending ... # when the user enters "hangup" to the "enter next message" prompt # a special message should be sent to the server indicating that this # talk session should be terminated, and the client should exitThe server will behave like the following after the initial TCP connection is set up:
# the server first waits to receive the first line of text from the client, # and when it receives it, prints it out, and enters a prompt for the # user on the server side to enter the next message to be sent to the client # (the server cannot terminate the conversation, only the client side can): talk client says: hello there enter next message: hi, what's up?
# client 1 on first machine connects to the talk server % ./cs85talk_client 130.58.68.62 enter next message: hello talk server response is: hi there enter next message: what is happening? talk server response is: nothing, what is up with you? enter next message: nothing, I guess good bye talk server response is: bye bye enter next message: hangup # client 2 on a different machine connects to the talk server % ./cs85talk_client 130.58.68.62 enter next message: hello? talk server response is: hi, who are you? enter next message: I'm jo schmoe, who are you? talk server response is: I am the all powerful talk server!!!! enter next message: oh, well in that case, so long. talk server response is: so long. enter next message: hangup # server (note when the conversation with the first client ends and the second begins) ./cs85talk_server client (130.58.68.158,35804) sent message: hello enter next message: hi there client (130.58.68.158,35804) sent message: what is happening? enter next message: nothing, what is up with you? client (130.58.68.158,35804) sent message: nothing, I guess good bye enter next message: bye bye client (130.58.68.166,34479) sent message: hello? enter next message: hi, who are you? client (130.58.68.166,34479) sent message: I'm jo schmoe, who are you? enter next message: I am the all powerful talk server!!!! client (130.58.68.166,34479) sent message: oh, well in that case, so long. enter next message: so long.
Start by copying over my starting point code into your private directory:
% cp /home/newhall/public/cs85/hw1_startingpt/* . % ls Makefile README client.c cs85talk.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.).
Once you have done some background reading about socket programs, then next step is to define the interface for your talk client and server. Since I want all student's clients to be able to communicate with all student's servers, as a class you will develop the interface for the client and server. I'll give you time at the end of class on Thursday to designing the API between client and server programs. The API will define how clients and server communicate different types of messages to each other, it will also define how each side knows when the contents of the next message have been received (for example, for some systems, fixed-length messages are sent between client and server, so each party knows when it has read enough bytes of the next message it is receiving, in other systems variable length messages are supported, and then the sender typically send the length of the message it is about to send first, so that the server knows how much to receive).
After the TCP connection is set up between a client and server, the client can sent two types of messages to the server, each one resulting in a different action by the server (one is an "I'm exiting message", the other is a "here is my next message to display" message followed by the line of text to display). Typically, when the server needs to interpret the type of a message in oder to know how to respond, the client sends a special short message (called a message tag) indicating which type of message it is sending, and then if need be, sends the rest of the message of that type to the server. The server, will first receive the message tag, and then invoke a routine for handling that type of message.
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 connections, 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.
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));
struct sockaddr_in name; namelen = sizeof(struct sockaddr_in); if(getpeername(sock_fd, (struct sockaddr *)(&name), &namelen)) { perror("getpeername"); close(sock_fd); return -1; } printf("client port %d ip %s\n", name.sin_port, inet_ntoa(name.sin_addr));
# to get my machine's IP addr: % /sbin/ifconfig # in the eth0 entry it is "inet addr:" entry # info for tcp sockets on this 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
printf("hello there"); fflush(stdout); // force all buffered printf output to stdout
# one way to find state of cs85talk_server processes: ps -A | grep cs85talk_server 27318 pts/2 00:00:00 cs85talk_server 27321 pts/2 00:00:00 cs85talk_server # if you see a listing like this, then you are not correctly handling process exits 27321 pts/2 00:00:00 cs85talk_server <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.