Starting from:
$35

$29

Program 5 • Client/Server and Sockets Solution 1 of 4




1. Overview




This project will implement a client/server application using sockets. A daemon (cixd) listens on a socket for client connection requests. Each connection will cause the server to fork a child process to serve the client. The daemon runs in an infinite loop listening. The server exits when the client disconnects. A client (cix) connects to a server and can send files, receive files, and get a summary listing of all files present.




A socket is a two-way means of communication between processes, not necessarily running on the same host. An IPv4 host is know by a 4-octet sequence such as 128.114.108.152, and a port is an unsigned 16-bit number (0 to 65535). Communi-cation will be done via TCP/IP over IPv4 sockets.




2. Programs




In this project, two main programs are to be written for the three parts of the project : the daemon and server, and the client. There will also be several library files written to be used by the programs. The general function is similar to sftp(1).




cixd

Usage : cixd port




Creates a server socket and goes into an infinite loop : When it accepts a client socket, it uses fork(2) to create a child process, which functions as the server to communicate with the client. The daemon listens for connections on the given port.




The server is forked with an open socket communicating with the client. Its loop repeatedly reads commands and information from the client and acts on those commands, returning information back to the client. Its loop will be a receive followed by a send, responding to client requests. It exits when the client closes the socket. It does no terminal I/O except for debugging purposes.




cix

Usage : cix host port




The client interacts with the user. Commands are read from the terminal (or redirect), each of which is executed one at a time by communicating with the server. Results are then displayed at the terminal. The client connects to the given host and port.







3. Interactive Commands




The cix client responds to commands read from the standard output and writes out-put to the standard output and error and accesses files. In the syntax below, Courier Bold are literal characters actually typed in, while Roman Italic stands for appropriate substitutions.




2 of 4







exit




Quit the program. An end of file marker or Control/D is equivalent. get filename




Copy the file named filename on the remote server and create or overwrite a file of the same name in the current directory.




help




A summary of available commands is printed.




ls




Causes the remote server to execute the command ls -l and prints the output to the user’s terminal.




put filename




Copies a local file into the socket and causes the remote server to create that file in its directory.




rm filename




Causes the remote server to remove the file.




4. Protocol used by the cix* programs




For the client and server to communicate, a protocol needs to be established. Each message must be framed in terms of a header and a payload. The header always consists of a struct of size 64 bytes. All messages between client and server consist of these 64 bytes, possibly followed by a payload. For alignment purposes, the nbytes field is first. Before filling in the fields, use memset(3) to clear the struct.




enum class cix_command : uint8_t {




ERROR = 0, EXIT, GET, HELP, LS, PUT, RM, FILE, LSOUT, ACK, NAK




};




size_t constexpr FILENAME_SIZE = 59;




struct cix_header {




uint32_t nbytes {0};




cix_command command {cix_command::ERROR}; char filename[FILENAME_SIZE] {};

};




The purposes of the fields are as follows :




uint32_t nbytes;




The number of bytes in the payload if there is any payload. Otherwise it must be zero (MBZ). This field is sent in network byte order and so must use the functions ntohl(3) and htonl(3) when loading and storing data.




cix_command command;




A single byte containing one of the cix_command constants. Note that the enum is specifically a uint8_t single byte type.




char filename[59];




The name of the file being transferred or removed. The filename may not have any slash (’/’) characters in it and must be null-terminated (with ’\0’). All bytes following the null must also be null. Pathnames with slashes and file-names longer than 58 characters are prohibited.

3 of 4







Following are the meanings of each of the cix_command values. Each is either client to server (C→S) or server to client (S→C), but never both.




cix_command::ERROR




An error flag to indicate an invalid header. Used internally.




cix_command::EXIT

Internal to cix, not used in communication.




cix_command::GET (C→S)




Request a file from the server. The filename is used both remotely and locally.




The payload length is 0.




cix_command::HELP

Internal to cix, not used in communication.




cix_command::LS (C→S)

Request file (ls) information. The payload length and filename are zeroed.




cix_command::PUT (C→S)




The length of the payload is the number of bytes in the file. The contents of the file immediately follow the header. The bytes of the payload are unstruc-tured and may contain null bytes. Binary files are acceptable.




cix_command::RM (C→S)




Request to remove a file. The payload length is 0.




cix_command::FILE (S→C)




Response to a cix_command::GET. The filename is the same as in the request and the payload length reflects the number of bytes in the file. The payload consists of the bytes of the file.




cix_command::LSOUT (S→C)




Response to a cix_command::LS. The filename is zeroed and the payload length is the number of bytes sent in the payload. The payload is the output of the command ls -l.




cix_command::ACK (S→C)




Response to either a cix_command::PUT or a cix_command::RM indicating that the request was successfully completed.




cix_command::NAK (S→C)




Response to any request that fails. There is no payload. The filename field is the same as was in the original request. The payload field is set to the value of errno in the server’s attempt to preform a task.




5. Procedures




Each of the above commands requires procedures for accessing files, including read-ing files from disk and writing files to disk, as well as accessing directories. When any of the system calls fails in the server, the server immediately terminates the operation and sends the value of errno back to the client in a cix_command::NAK mes-sage.

4 of 4







For the client or server to send a file it must first be read into a buffer. Binary files must be properly handled, so protocols which assume text files won’t work. To load a file from disk, use istream::read(), collecting characters into a buffer. Read the entire file into a buffer then close it. After that, it may be sent down the socket. Alternatively, stat(2) the file to see how large it is, and send the file down the socket piecemeal.



When receiving a file from the socket, Receive the header and determine the size of the file. Create an ostream and use ostream::write() to write the parts of the file as they are received from the socket. A C++ stream is closed when the variable goes out of scope, or you can call close.



To delete a file for the cix_command::RM command, use unlink(2) :



rc = unlink (filename);




To execute the cix_command::LS command use popen(2) and pclose(2) to create a pipe stream from the ls(1) command



FILE* pipe = popen ("ls -l", "r");




Then read the characters from the pipe in the easiest way, probably by using fgets(3). Finally, pclose(pipe). Then send the output back the client in a cix_ command::LSOUT message.




Modules



There will need to be several modules in this suite of programs. Each of the pro-grams, of course, will have its own source file with a main function in it.




The sockets module will be a useful inclusion into the program as its own module.




There should also be a cix_protocol module to implement the protocols and contain code for accessing files and sockets, since these will be used by both the client and the server.







7. Use of ports




If your daemon listens on a port that has been bound by another process, you will get the message ‘‘Address already in use’’ because only one process at any given time is allowed to listen on a particular process. To avoid this, choose a port number not being used by anyone else on the same server. You should pick a dynamic or private port number from the range 49152 through 65535 (0xC000 through 0xFFFF).




8. Runaway Processes




Be careful in using fork(2) so that you don’t accidentally create a fork-bomb. The command pkill(1) can be used to kill all processes matching a particular pattern. So the command




pkill cix




will kill all of your processes whose executables contain the string ‘‘cix’’. A really quick way to log out is to use kill(1) :




kill -9 -1




kill -s KILL -1

will send SIGKILL to all of your processes, thus logging you out.

5 of 4







9. What to Submit




Submit Makefile which builds both programs, all necessary C++ header and imple-mentation files. And if doing pair programming, the PARTNER file. When the grader uses the command make in the submit directory, the three binaries should be built.

More products