$29
Introduction
In this assignment, you will write a client program that connects to a given server. The server de nes a communication protocol, which the client has to implement by sending properly formulated messages over a communication pipe. The server hosts several electrocardiogram (ecg) data points of 15 patients suffering from various cardiac diseases. The client's goal, thereby your goal, is to obtain these data points by sending properly formatted messages that the server understands. In addition, the server supports is capable of sending raw les potentially in several segments (i.e., when the le is larger than some internal buffer size). Your client must implement this le transfer functionality as well such that it can collect les of arbitrary size using a series of requests/responese.
We obtained the above dataset from physionet.org.
Starter Code
You are given a source directory with the following les:
A makefile that compiles and builds the source les when you type make command in the terminal.
FIFORequestChannel class (FIFORequestChannel.cpp/.h) that implements a pipe-based communication channel. You can use this to communicate with another process. This class has a read and a write function to receive and send data to/from the server, respectively. The usage of the function is demonstrated in the given client.cpp. No change in this class is necessary for PA2.
A server.cpp that contains the server logic. When compiled with the makefile, an executable called server is made. You need to run this executable to start the server. Although nothing will change in this server for this PA, you will have to refer to its code to understand the server protocol and then implement the client functionality based on that.
The client program in client.cpp that, for the time being, is capable of connecting to the server using the FIFORequestChannel class. The client also sends a sample message to the server and receives a response. Once compiled, an executable le client is generated, which you would run to start the client program. This is the le where you will make most of the changes needed for this assignment.
1
CSCE 313 Spring 2020
A common.h and a common.cpp le that contain different useful classes and functions potentially shared between the server and the client. For instance, if you decide to create classes for different types of messages (e.g., data message, le message), you should put them in these les.
Download the source and unzip it. Open a terminal, navigate to the directory, and then build using make command. After that, run the ./server to start the server. Now, open another terminal, navigate to the same directory, and run client. At this point, the client will connect to the server, exchange a simple message and then the client will exit. Since pipe is a point-to-point connection, when either the client or the server exits, the other side will exit as well after receiving SIGPIPE signal for \broken pipe".
Server Speci cation
The server supports several functionalities. The client requests a certain functionality by sending the appropriate message to the server. Internally, the server will execute the correct functionality, prepare a reply message for the client and send it back.
Connecting to the Server
You will see the following in the server main function:
FIFORequestChannel control_chan ("control", FIFORequestChannel::SERVER_SIDE);
which sets up a communication channel over an OS-provided IPC mechanism called \named pipe". Note that the rst argument in the channel constructor is the name of the channel. To connect to this server, the client has to create an instance with the same name, but with CLIENT SIDE as the second argument:
FIFORequestChannel control_chan ("control", FIFORequestChannel::CLIENT_SIDE);
Requesting Data Points
After creating the channel, the server then goes in a \in nite" loop that processes client requests based on the type. Now, let us nd out how the server works. The server maintains ECG values (at 2 contact points) for each patient in a time series where there are 2 data points (i.e., ecg1 and ecg2) collected every 4ms (see any of the .csv les under the BIMDC/ directory) for the duration of a minute. That means there is 15K data points for each patient in each le and there are 15 such patients. Hence, there are 15 les each with 15K data points.
The client requests a data point by specifying:
Message type is DATA MSG. Data type is MESSAGE TYPE de ned in common.h. There are a number of message types, each serving a different purpose.
Which patient. There are 15 patients total. Required data type is an int with value in range [1; 15]
2
CSCE 313 Spring 2020
At what time in seconds. Data types is double with range [0:00; 59:996]
Which ecg record: 1 or 2, indicating which ecg record the client is interested to obtain. The data type is integer.
You will nd this request format in common.h as datamsg. In response to a properly formatted data message, the server replies with the ecg value as a double. Your rst task is to prepare and send a data message to the server and collect its response.
The following is an example of requesting ecg2 for patient 10 at time 59:004 from the command line when you run the client:
$ ./client -p 10 -t 59.00 -e 2
In the above, the argument \-p" is for which patient, \-t" for time, and \-e" for ecg no.
Requesting Files
To request a le, you need to package the following information in a message:
Message type set to FILE MSG indicating that it is a le request. Data type is MESSAGE TYPE de ned in common.h
Starting offset in the le. Data type is int64 t because of the fact that the le can be large and a usual 32-bit integer will not be sufficient.
How many bytes to transfer beginning from the starting offset. Data type is int. The name of the le as NULL terminated string, relative to the directory BIMDC/
The type filemsg in common.h encodes these information. However, you won't see a eld for the le name, because it is a variable length eld. If you were to use a data type, you would need to know the length exactly, which is impossible beforehand. You can just think of the name as variable length payload data in the packet that follows the header, which is a filemsg object.
The reason for using offset and length is the fact that a le can be very long and may not t in the buffers allocated in this PA. For instance, if the le is 20GB long and if you must send the le in a single message, that message must be 20GB long, requiring the same amount of physical memory and bogging the server down. To avoid this, we set the limit of each transfer by the variable called buffercapacity in both client.cpp and server.cpp. This variable defaults to the constant MAX MESSAGE de ned in common.h. However, you can change that providing the optional argument -m as follows, which changes capacity to 5000 bytes:
$ ./client -m 5000
Note that the change must be done for both client and server to make it effective (e.g., seeing faster/slower performance).
Therefore, instead of requesting the whole le, you just request a portion of the le where the bytes are in range [offset, offset+length]. As a result, you can allocate a buffer that is only length bytes long, but use multiple packets to transfer a single le.
3
CSCE 313 Spring 2020
Furthermore, a client would not know the length of a le unless the server informs. To achieve that, the client should rst send a special le message by setting offset and length both to 0. In response, the server just sends back the length of the le as a int64 t. Note that int64 t is a 64-bit integer which is necessary for les over 4GB size (i.e., the max number represented by an unsigned 32-bit integer is 232 = 4GB). From the le length, the client then knows how many transfers it has to request, because each transfer is limited to max MAX MESSAGE.
Also, note that the requested lename is relative to the BIMDC/ directory. Therefore, to request the le BIMDC/1.csv, the client would put \1.csv" as the le name. The client should store the received les under received/ directory and with the same name (i.e., received/1.csv). Furthermore, take into account that you are receiving portions of the le in response to each request. Therefore, you must prepare the le appropriately so that the received chunk of the le is put in the right place.
The following is an example request for getting le \10.csv" from the client command line:
$ ./client -f 10.csv
where the argument \-f" is for specifying le name.
Requesting New Channel Creation
The client can ask the server to create a new channel of communication. This feature will be implemented in this PA and used extensively in the following ones when you write multi-threaded client. The client sends a special message with message type set to NEWCHANNEL MSG. In response, the server creates a new request channel object, returns the name back, which the client uses to join into the same channel. This is shown in the server's process new channel function.
The following is a request a new channel:
$ ./client -c
.
Your Task
The following are your tasks:
Requesting Data Points: (15 pts) Request all data points for person 1 by (both ecg1 and ecg2), collect the responses, and put them in a le called x1.csv. Compare the le against the original BIMDC/1.csv using a le compare tool (e.g., fc) and demonstrate that they are exactly same. Also, measure the time do the entire thing by using gettimeofday function.
Requesting Files: (35 points)
4
CSCE 313 Spring 2020
{ (20 pts) Request an entire le by rst sending a le message to get its length, and then a series of le messages to get the actual content of the le. Put received le under the received directory with the same name as the original le. Compare the le against the original using linux command diff and demonstrate that they are exactly same. Measure the time for the transfer.
{ (10 pts) Make sure to treat the le as binary, because we will use this same program to transfer any type of le. Putting the data in a STL string will not work, because C++ strings are NULL terminated. To demonstrate that your le transfer is capable of handling binary les as well, make a large empty le under the BIMDC/ directory using the truncate command (see man pages on how to use truncate), transfer that le, and then compare to make sure they are identical using the diff command.
{ (5 pts) Experiment with transferring larger les (e.g., 100MB), and document re-quired time. What is the main bottleneck here? Can you change the transfer time by varying the bottleneck? [Hint: the most likely bottleneck is buffer capacity]
Requesting a New Channel: (15 pts) Ask the server to create a new channel for you by sending a special NEWCHANNEL MSG request and join that channel. After the channel is created, demonstrate that you can use that to speak to the server. Sending a few data point requests and receiving their responses is adequate for that demonstration.
Run the Server as a child process (15 pts) Run the server process as a child of the client process using fork() and exec() such that you do need two terminals: 1 for the client and another for the server. The outcome is that you open a single terminal, run the client which rst runs the server and then connects to it. Also, to make sure that the server does not keep running after the client dies, sent a special QUIT MSG to the server and call wait() function to wait for its nish.
Closing Channelsworth 5 pts You must also ensure that there are NO open connections at the end and NO temporary les remaining in the directory either. The server would clean up this resources as long as you send QUIT MSG at the end. This part is worth 5 points. Note that the given client.cpp already does this for the control channel.
Report (15 points): Write a report describing the design, and the timing data you collected for data points, text le, and binary les. Compare the difference in time between transferring data points vs entire le.
Submission Instruction
Put everything excluding the BIMDC directory in a single directory, zip it and submit on ecampus. Do not forget to make necessary changes to the makefile should you decide to add other .h/.cpp les. Please do not include any data le because that will make your zip le very large. Make sure that your directory has everything needed to compile your program.
5