Multiplexed I/O thus becomes the pivot point for the application, designed similarly to the following activity:
—Robert Love, Linux System Programming, 2nd Edition, Chapter 2, pp. 52.
Interprocess communication allows data to bypass memory protection boundaries and other restrictions imposed by processes, in a selective way that preserves the integrity of the processes themselves. This allows processes to adopt and implement application-specific protocols for how they connect with each other and how those data are exchanged, which in turn allows multiple processes to cooperate in solving problems more effectively and/or efficiently.
Managing multiple connections at once requires careful attention to both performance and correctness, and different alternatives for doing so concurrently are particularly important. In this lab you will use event multiplexing to allow a server to accept and use connections concurrently, with only a single thread of execution. Clients also will be single-threaded and each will perform its operations sequentially. Together the clients and server will complete a form of distributed merge sort, of shuffled numbered fragments of a file back into the original file.
In this lab, you will:
Create a
Make sure that the name of each person who worked on this lab
assignment is listed at the beginning of it, and make sure that in
addition to completing the code for this project, you also carefully
document your work in that readme.txt
file for your project, in which you
should record your observations as you go, and then refine
your readme.txt
file
into a cohesive lab report before submitting your lab solution.readme.txt
file, as indicated
in the Assignment section below.
man
pages: man 2 read
,
man 2 write
, man 2 bind
,
man 7 unix
, and man 7 ip
.
Please note that as long as you attribute the source of the
code (in your readme.txt
write up and in comments in the
code you submit), in your lab assignments you are free to use (or
derive code from) the examples in the LPI and LKD text books, and/or
from the Linux source code they reference, without asking permission
first - however, for any other data structure implementations that you
find on the internet or in other books, etc. you must first ask permission
from your instructors (if we approve of any such source we will post on Piazza
to confirm our approval and to let everyone else in the course know about
that potential source of code they may use as well).
Please read through the grading rubric for the lab assignments in this course, and please keep the points it makes in mind as you design, implement, and test your lab solution.
readme.txt
file, list the names of the people who
worked together on this lab, and a working e-mail address for each of those people.
You are encouraged to work in groups of 2 or 3 people on this lab assignment,
though you may work individually instead if you prefer: groups larger than 3 are not
allowed for this assignment.
jabberwocky_spec
) that
resides in the server's working directory - i.e., the directory from which the server
was launched; and (2) a port number at which it should listen for and accept connection
requests from clients.
The server should open that file and read lines of text from it: the first line
should give the name of an output file that the server should produce in its
working directory (for example, "jabberwocky"
could be given to hold
the text of
Lewis Carroll's poem,
"Jabberwocky"), and the subsequent lines of the file should give the names of files
that contain numbered lines for fragments of the main file
(for example, jabberwocky_1
,
jabberwocky_2
,
jabberwocky_3
,
jabberwocky_4
, and
jabberwocky_5
).
I've written a simple C++ program,
file_shuffle_cut.cpp
that may be
helpful in testing your code (it generates fragments from a file, which your lab
solution should then be able to reconstitute to reproduce the original file).
Use g++ (which is provided in the module for the C compiler version you should
be using) to build this program, as in:
g++ -o file_shuffle_cut file_shuffle_cut.cpp
and then you can test the compiled binary on the source file itself, as in:
./file_shuffle_cut file_shuffle_cut.cpp 3
The program should be able to work correctly for arbitrary numbers of fragment files. This means that the server will need to use variable length arrays, or use dynamically allocated heap memory to hold onto the file descriptors for the open fragment files.
The server code also should be sure to check all function return values, especially from the system calls that open the files, since that is how it can determine whether or not each file was opened successfully.
Last, as you work on this assignment you are strongly encouraged to use
debugging tools like gdb
to step through the behavior of your program
- in fact you can use separate copies of gdb
to run your server and
your clients and in doing so step through the entire distributed behavior of
your code. Working incrementally, and compiling and testing (including stepping
through your code in gdb
) each time you complete a new part of the
assignment can help avoid problems and lead you more quickly to a working
lab solution.
Whenever a client connects to the server, the server should accept the connection, and prepare to send data from the current fragment file to that client (Note: in doing so it is essential that the line delimiters are preserved and not lost). The server should then return to waiting on relevant (1) connection request events from the socket on which it is listening, and (2) read and write events from that new socket as well as from any other sockets it has already opened with other clients; as noted below, as the server completes different phases of its execution some of the events will no longer be relevant and the server will cease waiting on them.
readme.txt
file.
Watch out for "short reads" and "short writes" in which only part of a
sequence of characters is read or written in a single call to read()
or write()
(and make sure to check the return values from
those calls so you can handle that) - a single such call per event
is all you can do without blocking on a given socket before the server
returns to waiting for further events. Please also note that a server
may have multiple distinct actions available at once - it could have data ready
from a client to which it had connected earlier, even as it is sending data to
a new client - it should interleave such enabled reads and writes as much as it can,
to allow as much concurrency as possible within a single thread.
Add a section titled "Server Design" to your readme.txt
file,
and in it describe briefly (in a few paragraphs) how you implemented these
requirements, and identify any design choices that you made along with
the rationale behind those decisions.
main
function. If any subsequent
step of the program fails in a manner that cannot be worked around,
the client program should also output an appropriate error message and
return a unique non-zero error value that corresponds to the
kind of problem that occurred.
The client should first create a socket, and then connect to the server using the address and port it received from the command line. Once the connection is established, the client program should repeatedly read data from the newly connected socket. The client should preserve the formatting of the data from the server (a line number followed by a line of text including the delimiter, repeatedly) as it does that.
readme.txt
file.
Again watch out for "short reads" and "short writes" in which only part of a
sequence of characters is read or written in a single call to read()
or write()
. One option on the client side (since it does not need to
multiplex different I/O events concurrently) is to use higher level library functions
for reading and writing data, though even when calling those it is essential to check
their return values and other indicators of how much data was read or written.
readme.txt
file.
The client program should then go through the data structure in that order, using repeated writes (or higher level library functions to write data to the socket) to send the lowest line number and its line back to the server over the connected socket, then sending the next higher line number and its line, etc. (note that with high probability the line numbers will not all be sequential).
0
is conventional for that in C).
Add a section titled "Client Design" to your readme.txt
file,
and in it describe briefly (in a few paragraphs) how you implemented these
requirements, and identify any design choices that you made along with
the rationale behind those decisions.
gdb
as
noted above) is to write a bash
(or other Linux shell environment)
script that launches a given number of clients at once - this creates a situation
with high concurrency which is one of the conditions under which your lab solution
will be graded. Think about other situations and how they can help to establish
other important conditions for testing your programs, and run those tests as well.
Add a section titled "Build Instructions" to your readme.txt
file,
which explains briefly how to compile and run your server and client programs. This can
involve command lines that invoke the compiler directly, or if you wrote and submitted
a Makefile
it could be a command line that invokes make
,
etc.
Add a section titled "Testing and Evaluation" to your readme.txt
file,
and in it describe all the test cases you ran, and your observations about how your
client and server programs performed in each of those cases. Be sure to test the
edge cases noted in the assignment when the server (or possibly client) may return
an error code, and make sure it handles those as specified, as well as the cases
where it runs successfully to completion. If you run into any issues during
testing where your server or client program isn't working correctly, in this section
of your report please decribe briefly what the issue was, how testing helped to
identify it, and how you fixed that issue.
readme.txt
file please add a section
titled "Development Effort" and in it please provide an estimate of the
amount of time (in total person-hours) that your team (or you if you didn't
work with anyone else) spent completing this assignment. This will allow
us to calibrate and possibly refine the content of this course in future
semesters.
readme.txt
file containing all the sections requested above
.c
file containing your server code
.c
file containing your client code
Please make sure your readme.txt
file lists the names of everyone who worked on the project. If you are working in a team, if possible have just one person submit the files - however, if you must submit your solution from multiple Canvas accounts, please make sure that exactly the same files (and versions of those files) are submitted in each case.