关于程序员:CMPUT-379讲解

56次阅读

共计 9180 个字符,预计需要花费 23 分钟才能阅读完成。

CMPUT 379, Assignment 2, Winter 2021
University of Alberta / Department of Computing Science
(sockets, pthreads, client-server, inotify, synchronization)
Objective
You are asked to implement a client/server application. Multiple clients connect to a single server. In this
assignment, the server acts as an intermediary among two kinds of clients. The first kind of client (observer client)
monitors a file or directory using the inotify facility (man inotify for more information) and reports to the
server all the changes noticed by inotify on the monitored file/directory. Multiple such clients, each monitoring
a different file or directory, and possibly at different hosts, can be connected to the server at any point in time.
The second kind of client (user client) refreshes the screen regularly (similarly to the top command) to display the
most recent inotify data reported by each one of the observer clients currently connected to the server.
All three roles (server, observer client, user client) are implemented by a single executable notapp) and the
specific role is controlled by the flags and arguments passed to it. Specifically:
server:
notapp -s -t <interval> [-p <sport>] [-l <logfile>]
observer client:
notapp -o <saddr> <sport> <fileordir>
user client:
notapp -u <saddr> <sport>
Where <interval> indicates how frequently the server broadcasts to the user clients the most recent events of
its observer clients. The <interval> can take values from 0.1 to 10 seconds. The <sport> is the server port and it
is optional. If not provided, the system chooses a port for the server. This port (the chosen by the system) should
be printed by the server to stdout before it becomes a daemon process. The <logfile> is an optional log file
where the server keeps track of all the messages it received and any of the actions that it took. The log file is
meant mainly for debugging, so it has to be informative to you and the teaching assistants.
When starting as a client of either type (observer or user), the client connects to the server listening on port
<sport> of the host with <saddr> IP address. In the case of an observer client, the <fileordir> indicates the file
or directory to monitor for all possible inotify events.
Observer Client Behavior
The observer is a producer of information and, as such, does not need to consume information coming from the
server. Rather, it provides information to the server. The observer monitors the file or directory indicated for all
2 / 4
possible inotify events, and it reports those events to the server. There is no strong requirement to use multiple
threads for an observer client (or any client for that matter), although one could use them to good advantage. At
a minimum, the first message from a client to the server should allow the server to distinguish whether a client is
an observer or a user client, and, if it is an observer client, what is the file or directory that the particuar observer
is monitoring. There are three requirements for observer clients: a) to send each inotify_event information as
soon as possible to the server, i.e., to not delay it unnecessarily, b) to annotate each such information with the
local timestamp when it happened (in microsecond accuracy, see man gettimeofday), and c) to gracefully
terminate and let the server know it terminated when either (i) the file or directory being monitored is removed,
or (ii) it receives a SIGINT signal. The observer client does not depend on any user terminal input, so it should be
possible to let it run as a background process. It should not produce output to stdout. Finally, for simplicity,
monitoring of directory should not be recursive.
User Client Behavior
The user client, after connecting to the server, periodically refreshes the screen and (assuming N observers are
connected to the server at that point) it displays the most recent inotify event sent by each of the N observers
to the server, sorted in order of timestamps. The output is one line for each of the N observers. The server,
recognizes (see comment for Observer Client Behavior) that it is talking to a user client. The server pushes to the
client, every <interval> seconds, the updated list of most recent event from each of the observer clients.
Therefore, the user client is expected to refresh the screen with the most recent events once every <interval>
seconds. Note that N changes over time and, hence, there might be more, or fewer, lines from one instant to the
next. The user client is supposed to do minimal work, i.e., just the rendering of the information sent from the
server. The user client should terminate when receiving a control-C, but it should do so gracefully, by notifying
the server that it is terminating.
User Client Output Format
The format of the lines displayed by user clients follows the format of this example (with N=3). Upper left is upper
left of the terminal screen. Notice that they are sorted by timestamp with the most recent at the top:
TIME HOST MONITORED EVENT
1612142039.611365 192.168.0.3 myDir f.txt IN_ACCESS
1612142019.855106 192.168.0.10 /tmp src IN_CREATE IN_ISDIR
1612142000.471291 127.0.0.1 a.txt IN_ATTRIB
The time is in the format of seconds followed by a period followed by microseconds (consult man
gettimeofday). HOST is the IP address of the host on which the corresponding observer is running. MONITORED is
the monitored file or directory. In this example, the last observer in the list happens to be monitoring a file
(a.txt) while the two others are directories. The EVENT is the information conveyed in the event mask in human
readable form (see man inotify for the names). If the observer is monitoring a directory, then EVENT is prefixed
by the name of the relevant file or directory within the monitored directory (see name member in struct
inotify_event). In the above examples, someone changed an attribute (e.g., chmod) on a.txt; a subdirectory
named src was created within /tmp; file f.txt (which is inside directory myDir) was read.
3 / 4
Server Behavior
The server binds to the port, it becomes a daemon process, and waits for connections from the clients. In the
initial handshake with the client it has to determine whether a client is an observer or a user client. No
assumptions can be made that all observers (or any observer) connect first. Either kind of client might wish to
connect (or gracefully terminate the connection) to the server at any point in time. The server is responsible for
keeping track of the clients. It is a requirement that each new cleint connection to the server is handled by a
separate pthread. The thread should be terminated when the corresponding connection terminates.
The server works in the following fashion: a) it collects, as quickly as possible, data received from the observer
clients and updates a common data structure which stores the most recent event that came from each observer. If
a logfile was specified, the server also dumps the received events to the log file, in the order they are received. b)
The threads serving the user clients are periodically (with <interval> period) sending the updated information
of this common data structure to their corresponding user clients, so that it can be rendered. It is expected that if
there are M user clients connected at the moment the periodic update is triggered, all M clients receive
consistent, i.e., identical, information. In other words, the threads serving the user clients “broadcast” the current
state of most recent events to all simultaneously connected user clients. It is expected that the server handles the
terminating clients in a graceful manner, i.e., without crashes or undue delays. Finally note that the common data
structure at the server may be accessed by multiple threads at the same time. You will need to use concurrency
control for its access.
There is no specific requirement for the protocol format between clients and server. However, you have to
document what is the protocol you use (what messages you are sending and/or expecting).
Refinement
A requirement is to add one more refinement to your code. There are two possible refinements from which you
can choose.
Server timestamps
The clocks of different hosts are not synchronized, therefore timestamps of observers from different hosts can be
inconsistent (e.g., something might arrive later from another host but have an earlier timestamp than a current
event on our host). Introduce a compilation flag that forces the server to ignore the timestamp associated with
the events sent from the observers and instead uses its own local (at the host where the server is running)
timestamps. These timestamps are of the time instant the server received the corresponding event.
Fresh info visualization
Between two “broadcasts” there might be more than one event from an observer. This is easily handled by having
the server store the most recent event (“overwriting” the previous event) coming from that observer. The
implication is that you might not see some of the events reported by the user clients if a more recent event for
the same observer has occurred within the interval. This is to be expected and it is correct. There could also be
intervals where no new events have been observed by one or more observers. In this case the user server will
broadcast (and the user client will render) the same most recent event information for the observers that had
nothing new. (And the new information for those observers who had more recent events.) Introduce a
4 / 4
compilation flag to add boldface font to the lines representing new recent event from the corresponding
observer.
Deliverables
The language of implementation is C. You are expected to deliver good quality, efficient, modular,
documented, code. That is, the quality of your code will be marked.
Your assignment should be submitted as a single compressed (zip or tar.gz) archive file. The archive should
contain all necessary source files as well as a Makefile. Calling make without any arguments should generate the
notapp executable. Your submission must include the DESIGN.md (plain text or markdown format) document
which: (a) describes your protocol between clients and server, and (b) indicates which refinement you
implemented. Refinement executables should be produced by issuing make notapp.time or make notapp.bold
(depending on which refinement you decided to implement).
In the lab machines, always remember to terminate any processes you have left running before leaving or
logging out your ssh session, and in general before you turn your attention to some other task. Generally,
ensure that you have not left any stray processes running on the physical machine before leaving. Violations of
this rule may be penalized with mark deductions. Furthermore, the system administrators have been given
permission to terminate such processes and to report to the instructor the users who left them running.
Monday, February 1st, 2021

正文完
 0