CS360 Lab #9 -- Jtalk


This is a program that lets n people talk with each other over the network. It is a little constrained, because the server defines n and won't start up until all n people are connected. However, it is a good exercise in using sockets and select().

Jtalk is called in one of two ways:

jtalk host port name n
or
jtalk host port name
The former is the way the server calls jtalk, and the latter is the way the clients call jtalk. When the jtalk server starts, it waits for n-1 clients to attach to it. Then whenever someone (client or server) types into their jtalk process, his/her name is prepended to the string, which is printed out in all n jtalk processes. Thus, the following is an example of me serving a jtalk session on my machine with my two students Goofus and Gallant.

Me, on cetus3.eecs.utk.edu:
UNIX> jtalk cetus3.eecs.utk.edu 6886 The-Professor 3
Client: Gallant has joined
Client: Goofus has joined
Go ahead and talk:

Respected students -- did you enjoy my lecture today?

The-Professor: Respected students -- did you enjoy my lecture today?

Gallant: I enjoyed it so much that I went home, read the lecture notes, and felt emotionally fulfilled!

Goofus: I fell asleep in class.  Sorry, dude.
<CNTL-D>
UNIX> 

Gallant, on some other machine:
UNIX> jtalk cetus3.eecs.utk.edu 6886 Gallant
Server: The-Professor
Client: Gallant has joined
Client: Goofus has joined
Go ahead and talk:

The-Professor: Respected students -- did you enjoy my lecture today?

I enjoyed it so much that I went home, read the lecture notes, and felt emotionally fulfilled!

Gallant: I enjoyed it so much that I went home, read the lecture notes, and felt emotionally fulfilled!

Goofus: I fell asleep in class.  Sorry, dude.
UNIX> 

Goofus, on some other machine:
UNIX> jtalk cetus3.eecs.utk.edu 6886 Goofus
Server: The-Professor
Client: Gallant has joined
Client: Goofus has joined
Go ahead and talk:

The-Professor: Respected students -- did you enjoy my lecture today?

Gallant: I enjoyed it so much that I went home, read the lecture notes, and felt emotionally fulfilled!

I fell asleep in class.  Sorry, dude.

Goofus: I fell asleep in class.  Sorry, dude.
UNIX> 

My code is written so that if you end lines with a backslash, you can send multiple lines at once. That is optional for you, and will not be graded.

Each jtalk server/client should consist of just one process. All lines of text should go to the server, who broadcasts them to all the clients. All processes will need to use select() -- you are not allowed to use pthreads in this lab. sockettome.o and sockettome.h are in the cs360/objs and cs360/include directories respectively.

Exiting semantics

If any of the processes go away, then all processes should exit. That means if the server or any client closes standard input or gets killed by a signal, all processes should exit.

Network Issues and Buffering

You need to be prepared to have read() calls return fewer bytes than you expect. I mentioned in class that using fdopen() can help alleviate problems with read() and write(). Unfortunately, you can't use select() in conjunction with a FILE * that has been opened with fdopen(fd, "r"). So, here are your marching orders:

In my solution, I wrote a procedure called read_n_bytes() which makes successive read() calls until a specified number of bytes have been read. It tries to read all n bytes in one read() call, but if that read() call returns fewer than n bytes, it keeps calling read() to get the remainder.

I send a line of text using the following protocol:

In this way, the reading process calls read_n_bytes() to get 16 bytes, converts that string to a length, and then calls read_n_bytes() on the length. Think about how that is easier and more efficient than simply sending the line of text and having the reader try to buffer lines, or than calling read(fd, b, 1) and reading single characters.

The Gradescript

The gradescript is different from previous gradescripts in that you have to run it from multiple machines. You should put the names of the machines into a file called "hosts.txt". This file should have exactly two lines, for example:
UNIX> cat hosts.txt
cetus2
cetus3
UNIX> 
The lines should be different. You are going to run gradescript (or gradeall) on each machine. For example:

On cetus2:
UNIX> /home/plank/cs360/labs/lab9/gradescript 1
Problem 001 is correct.

Test: sh -c '/home/plank/cs360/labs/lab9/lab9-tester 001 > tmp-grader-cetus2-stdout.txt 2>tmp-grader-cetus2-stderr.txt'
UNIX> 
On cetus3:
UNIX> /home/plank/cs360/labs/lab9/gradescript 1
Problem 001 is correct.

Test: sh -c '/home/plank/cs360/labs/lab9/lab9-tester 001 > tmp-grader-cetus3-stdout.txt 2>tmp-grader-cetus3-stderr.txt'
UNIX> 

The gradescript calls the program lab9-tester with a number. Let's take a look at what that does:

On cetus2:
UNIX> /home/plank/cs360/labs/lab9/lab9-tester 001
Have forked off talk client with name Chad-Ochocinco
Waiting for all talk processes to connect



All processes have printed the proper server line.
All processes have printed the proper client line(s).
Testing writes
Events correctly processed: 0.
UNIX> 
On cetus3:



UNIX> /home/plank/cs360/labs/lab9/lab9-tester 001
Have forked off talk server with name Keroppi
Waiting for all talk processes to connect
All processes have printed the proper server line.
All processes have printed the proper client line(s).
Testing writes
Events correctly processed: 0.
UNIX> 

Each lab-tester call forks off some clients and a server. The server may be on the first machine or the second one. Each has a different name. In the above test, there is one client on cetus2 with the name "Chad-Ochocinco", and there is a server on cetus3 with the name "Keroppi."

Each lab-tester reads standard-output of all of its clients and servers. In that way, it knows when all the clients and servers have connected. When they are all connected, it tests having them talk to each other. The order in which the various processes talk are in the files tmp-input-host.txt. They will be be identical. In the above test:

UNIX> cat tmp-input-cetus2.txt
UNIX> 
There is no talking -- the test merely checks that your program prints the correct lines for having the clients and servers hook up.

Let's try a more advanced test:

On cetus2:












UNIX> /home/plank/cs360/labs/lab9/lab9-tester 50
Have forked off talk client with name Thor
Have forked off talk client with name Tiger
Waiting for all talk processes to connect
All processes have printed the proper server line.
All processes have printed the proper client line(s).
Testing writes
Events correctly processed: 11.
UNIX> 
On cetus3:
UNIX> /home/plank/cs360/labs/lab9/lab9-tester 50
Have forked off talk server with name The-Donald
Have forked off talk client with name Sasha
Have forked off talk client with name Gus
Have forked off talk client with name Abby
Have forked off talk client with name Mittens
Have forked off talk client with name Luther
Have forked off talk client with name Keroppi
Have forked off talk client with name Fiona
Have forked off talk client with name Waluigi
Waiting for all talk processes to connect
All processes have printed the proper server line.



All processes have printed the proper client line(s).
Testing writes
Events correctly processed: 11.

In this case there are 9 processes on cetus3 and only two on cetus2. After the clients all connect to the server, there are eleven events:

UNIX> cat tmp-input-cetus2.txt
The-Donald: Spinning 'round and 'round
Thor: Now testify
Sasha: You don't have to call me lieutenant Rosie and I don't want to be your son
Gus: Now it's like top gun in the Old West, everybody wants me to draw
Abby: Look at me, I'm in tatters!
Mittens: I'm only here for fun
Tiger: There's a little cafe where they play guitars all night and day
Luther: Baddest bitches in the bed
Keroppi: How I swing
Fiona: Does it matter? (Shattered) Does it matter?
Waluigi: You got rats on the west side
UNIX> 
The lab9-tester program feeds each line into the given process, and then tests all 11 processes for the correct output. In the example above, it writes the string "Spinning 'round and 'round" to standard input of the "The-Donald" process on cetus3. It then waits and makes sure that all 11 processes have printed the proper output. It then writes "Now testify" to standard input of the "Thor" process. It repeats this for each of the 11 events, and if they're all correct, it says so.

Frankly, this is a kind way for me to test your programs -- you'll note that I never have two processes talking to the server simultaneously. Please remember my kindness.

Now, you may have problems because you can't see your output when you're running gradescript. If you want to see output while debugging, you should have your jtalk print to stderr.

You can call lab9-tester with any positive numerical argument -- if the number is greater than 100, it will generate a random test case. The gradescript only calls it with 1-100. The test cases are:

lab9-tester generates its port number based on its argument, which means that if you call it twice in succession, you may get the bind() error message:

UNIX> /home/plank/cs360/labs/lab9/gradescript 90
Problem 090 is correct.

Test: sh -c '/home/plank/cs360/labs/lab9/lab9-tester 090 > tmp-grader-cetus2-stdout.txt 2>tmp-grader-cetus2-stderr.txt'
UNIX> /home/plank/cs360/labs/lab9/gradescript 90
bind(): Address already in use

You need to wait up to two minutes before calling this again.
UNIX> 
Such is life -- you'll have to wait two minutes.