Project 2
In
this project, you are going to implement the real file transfer function
between the clients. The high level description of the requirements is as
follows. Say, client A, is asked by the user for a file. As in the previous
project, it first checks if it has the file and if it does not have the file,
it will send a query to the server asking who has it. The server will choose
one client, say, B, who has the file and tell A, along with a SHA-1 hash of the
file. A will connect to B and B will accept the connection. After that B sends
the file to A. Upon completion of the file transfer, A calls SHA-1 to get the
hash of the file and compares it with the one server gave it. If they match, it
sends a message to the server saying that “I got the file.” Server will update
the record for A and if next time a client asks for this file, server may ask A
to upload the file.
In
this assignment, the clients don’t really store files in the disk. I will
provide a function called “void
generate_file(int file_id,
int length, char *buf)”
which takes the id of the file and a pointer to a char array (plus the length
of the file) as parameter. After you call this function, the array pointed by buf will be filled with the content of the file. All files
are of size 20,000 bytes. You can use “void
find_file_hash(int file_length,
char *file, unsigned char *hash)”
to find the hash of a file. Parameter “hash”
should be a pointer to an array of 20 unsigned char.
You
need only modify the client and server code of the previous project for this
project. For the client (just for simplicity, let’s call it client A):
1.
Initialization.
Same as Project 1.
2.
Connect
to the server. Same as Project 1.
3. Report to the server.
Same as Project 1.
4. Open its own
listening port. Client A opens its listening
port by calling the listen() function; it needs to do
this because other clients may want to connect to it and download file from it.
5.
The
while loop. Client A enters an infinite loop:
· If the user types “f”,
client A will ask which file the user wants and the user will input the file
index. If the user types in, say, 10, client A first checks if it has file 10.
If yes, it prints out a message like “I already have file 10.”
Otherwise, it sends a message to the server saying that “can
you tell me who has file 10?’’ The server will reply with a message with the
information of a client, say, client B, who has file 10, including B’s ID, B’s
IP address, and B’s listening port number. The server also sends client A the
SHA-1 hash of the file. Client A will print out the information it receives.
Client A will then try to connect to client B by calling the connect()
function. After client B accepts the connection, client A will send client B a
message saying that “I need file 10.”
Client B will then send client A the file in 1000-byte blocks, where client B
sleeps for 1 second after sending each block (so the file transfer takes 20
seconds). After receiving the entire file, client A
calls the SHA-1 function to get the hash of the file. Client A prints out the
hash along with the hash server gave it, both as 20 unsigned integers. If they
match, client A sends the server a message saying that “I
have downloaded file 10 from client B.” Client A then closes the connection with
client B. If they do not match, client A asks client B to send again, which
goes on until client A gets the file from client B.
· If the user types “q”, client A quits: a) it
first sends the server a message saying that it wishes to quit, b) waits until
server closes the connection, c) terminate the program.
· Client A also monitors its listening port.
If there is a client, say, client C, trying to connect to it, it will accept
the request. Client A will then receive a message from client C containing the
index of the file client C needs. It will then print out “Client
C wants file (the file index), do you want to send the correct file?”
If the user says yes, then client A goes ahead to send
the file; otherwise, it will ask the user to input a key which is a single
byte, which will be xored with every byte in the file
to be sent to client C. After sending the file, client A
prints out the SHA-1 hash of the file it sends to client C. If client C wants
client A to send the file again, client A will ask the user again and repeat
the process. Later, when client C closes the connection with client A, client A prints out “client C closed the connection with
me!”
6. Auxiliary functions.
Same as Project 1.
7. Note, that client A
must use the select() function to get user inputs, read
message from server, and read messages from the clients.
For the server:
1.
Initialization.
Same
as Project 1.
2.
Accept
requests. Same Project 1.
3.
Answer
client queries. If
a client, say, client A, sends the server a query for a file, the server first
prints out client A’s ID, IP address (the client’s IP address can be found when
calling the accept() function), and the file index
client A is asking for. The server then checks its record of clients and finds
one who has the file. In this project, the server replies with a client whose
ID is (1) larger than A (2) is the smallest among such clients. That is, for
example, if client A’s ID is 5 and clients 0, 1, 3, 7, 9 are the ones who have
the file, the server will give client 7 to client A. In the case that there is
no client with ID greater than A has the file, the server “wraps around,” that
is, for example, if client A’s ID is 5 and clients 0, 1, 3 are the ones who
have the file, the server will give client 0 to client A. The server also
computes a SHA-1 hash of the file and sends it to client A.
4.
Update
client info. After client A has downloaded
a file, it will send a message to the server saying that “I have downloaded
file what from whom.” The sever will update the record
for client A, i.e., add this file to its file vector. If a client leaves, the sever deletes its info.
5.
Respond
to user command. Same as Project 1.
6.
Respond
to client quit message. Same as Project 1.
Thread:
When
a client A is asked to send a file, one possible implementation is that it only
“focuses on” the file transmission, i.e., it sits in a loop and cares about
nothing else. This might be fine if the total number of clients is not large
such that client A will not be contacted again during this time. One much
better implementation is to create a send thread, which will be responsible for
sending files to all those who have requested for files. You probably want to
use an array to remember the clients who have requested files, the file
indices, the keys, and how much has already been sent for each client. If there
are multiple clients, you would want to send file blocks to each client on a
round-robin manner. Extra 10% if you
implement the file transfer using thread.
The set
of files for this project can be downloaded here, including
common.cpp and SHA-1.c for generating the file and SHA-1 function. The
server.cpp and client.cpp also implements relevant functions in Project 1. You
are free to modify the code any way you want.