This assignment makes use of files contained in this zip file. This assignment is due Tuesday, October 4.
This assignment simulates a server process communicating with a client process using a "binary message protocol". In the zip file there is a file server.c
that implements the server. Your assignment is to implement the client program, client.c
. This assignment uses the material from Section 2.1 (pages 31-59) from the textbook.
The server program "sends" messages to the client program by writing the messages to standard output. The client program should "receive" messages by reading them from standard input. So the command line
> ./server 10 | ./client
uses a pipe to simulate the communication channel from the server to the client (the server's command-line argument 10 tells the server to send 10 messages to the client).
Here is a description of the message protocol used by the server. Each message begins with a single byte that is a "message header". There are three kinds of messages, a "numeric message", a "text message", and an "end-of-transmision" message. After a message header will be the "body" of the message (except for the end-of-transmission message which has no message body; it consists of just the message header byte).
The message header for the end-of-transmission message is 0x80
(in hexadecimal). The meaning of this message header is that there are no more messages and the server will close its output stream, and the client should close its input stream.
The message header for a "text message" has its most significant bit set to 1
and its seven least significant bits set to an integer value between 1 and 127. The meaning of this message header is that it will be followed by the given number of printable ASCII characters (hex 20 through 7E), which the client should read.
The message header for the "numeric message" has its most significant bit set to 0
. The remaining seven bits are a "bit field" with the following meaning. A 0
bit tells the client to expect an int
to be sent to it by the server. A 1
bit tells the client to expect a double
to be sent to it by the server. The client should read the bits from least significant bit to most significant bit. So, for example, if the message header in hexadecimal is 0x39
(or binary 00111001
), then the client should expect to receive, in order, one double, then two ints, then three doubles, followed by one int.
The eight bytes of a double are sent by the server in big-endian byte order. That means that the server sends the most significant byte of a double first, followed by the second-most significant byte, etc. for all eight bytes of the double.
The four bytes of an int are sent by the server in "weird-endian" byte order. For the purpose of this assignment, the weird-endian byte order means that the server will first send the second-most significant byte of the int, followed by the third-most significant byte, followed by the most significant byte, followed by the int's least significant byte.
In order to access the bytes of a double in big-endian order, or the bytes of an int in weird-endian order, you need to use either a pointer with a cast, or a C union. Look at pages 44-45 of the textbook (Figure 2.4) for an example of using a pointer with a cast. Look at the file server.c
for an example using a union.
Write a program client.c
that implements the receiving end of the above protocol. Besides implementing the above protocol, your client.c
program should do a few other things. The client should keep track of how many bytes it is receiving from the server. After receiving an end-of-transmision message, the client should print out its count of the total number of bytes it received from the server. If the client should detect an end-of-file condition before receiving an end-of-transmission message, the client should print an error message that includes the number of bytes it has received so far from the server. The client should also print to standard output the contents of each text message and each numeric message.
In the zip file there is an executable demo version of the client program (for both Linux and Windows). Your version of client.c
should behave exactly like the demo version.
You should test your client.c
program on a Linux machine. The Windows command line does not handle binary data very well (the Windows versions of stdin and stdout are not in "binary mode" but the Linux ones are). If you run the client-server pair on Windows, it will occasionally fail with an unexpected end-of-file.
To help you debug your client.c
program, each time the server program is run it logs all the messages it sends to the client to a text file called log_file.txt
. The log file contains very verbose versions of the messages sent to the client. The log file shows the message headers in binary notation, it shows the double and integer numbers in both decimal and hexadecimal formats (in the transmitted byte order), and it tells you the length of the text messages in decimal format.
Each time you run the server program, it creates a random set of messages. If you want to test your client program with a repeatable set of messages, run the server one time and capture its (binary) output in a file.
>./server 5 > test_messages.data
Then run your client as many times as you want with the test_messages.data
file as its input.
>./client < test_messages.data
When you do this, be sure to keep a copy of the server's log_file.txt
. It can help you determine if your client's output is correct.
Turn in a zip file called CS223Hw2Surname.zip
(where Surname
is your last name) containing your version of client.c
.
This assignment is due Tuesday, October 4.