1 Your Task
Download the supplied skeleton code at here.1 (last update 17 July 2025)
In
sendrecv.py
complete an implementation of MySender and MyReceiver.In MySender’s
send_message
function, receive a message in bytes, then format a message to be sent as a sequence of bits, then callself.channel.send_bits()
with those bytes.In MyReceiver’s
handle_bit_from_network
function, receive a bit from the network, then callself.got_message_function()
when those bytes represent a full message passed toMySender
’ssend_message
function.To demonstrate the interface, we supply an example implementation which is partially functional. It transmits messages by converting each byte into bits, and adding a nul byte to separate messages. This satisfies some but not all of the requirements below.
Your implementation must:
Be able to send messages of any length between 0 and 1023 bytes, inclusive
Allow messages to contain any sequence of bytes (of an appropriate length).
(This means that, for example, we should be able to take some of the bits your
send_message
function produces and send a new message containing them without it being corrupted.)If a message’s bytes are corrupted, by changing the values of bits randomly and/or adding and removing bits randomly, then:
You should detect this and avoid calling
got_message_function
with data that does not represent a valid message at least 99.99% of the time. (You should be able to achieve this with a 2 or more-byte checksum.)Other than possibly the next few messages or couple kilobytes of messages, future uncorrupted messages should be received correctly (regardless of where the corruption took place).
Not use too much space to send messages:
- Including any headers/separators, the average size of a random message of N bytes at most 120 bytes or N * 1.2 bytes, whichever is larger. (It’s okay if some pathological messages take up more space.)
Be your own code and use only functionality built-in to python or supplied as part of its standard library. This means that it is permissible to use the
zlib
module’scrc32
function and thestruct
module. But it is not permissible to use, for example, python-pppd
Test your implementation using
test.py
:You can use
python3 test.py send ...
to send sample messages:python3 test.py --input-format binary --output-format binary 00001111 11110000 python3 test.py --input-format hex --output-format hex FF00FF00 809080908090
You can use
python3 test.py recv ...
to receive bits:python3 test.py --input-format binary --output-format binary 111100011110000111111 python3 test.py --input-format hex --output-format hex FF00FFFFFFF
You can use
python3 test.py suite ...
to run a test suite:python3 test.py suite python3 test.py suite --verbose
You can specify to only run parts of test suites by passing a regular expression to –only-test and/or –only-subtest:
python3 test.py suite --only-test=empty-clean python3 test.py suite --only-test=tiny.* python3 test.py suite --only-test=corrupt-first-recovery-tiny1 --only-subtest='delete bit #.*' python3 test.py suite --only-test=corrupt-first-recovery-tiny1 --only-subtest='delete bit #2'
If you want to run additional tests, you might find it useful to modify the list of tests in
TESTS
.When grading, we may run additional tests and/or inspect your code by hand. Although the supplied tests do not intentionally omit functionality you must implement, they may get
unlucky
and fail to detect an implementation which is actually broken and they do not test everything for all possible message sizes. (Also, because some requirements deal with chances of corruption, it may be possible for them to spuriously fail on a correct implementation, though I think that is unlikely.)Briefly document in a comment or docstring near the top of your
sendrecv.py
the frame format you choose.Submit your
sendrecv.py
by using the submission site.
2 Hints
You can reuse the supplied bit to byte and byte to bit conversions..
The
struct
modulespack
orunpack
to convert integers to bytes and vice-versa.Be careful about choosing ambiguous message delimters.
For example, let’s say you choose 0000 as a delimiter for messages and to escape 000 with 0001 and we try to send the message 111111100.
In this case, we’ll send 111111100 0000. There was no reason to escape anything. When we try to remove the delimiter from this, we’ll find the first 0000, and get 1111111, which is not our original message.
The problem here is that the escaping is not sufficient to handle the end-of-message edge case. We could fix this by escaping every 0 instead of every 000, but that’s pretty inefficient. A more space-efficient solution is to choose a delimiter pattern that has a distinctive transition from 0s to 1s that allows us to escape less frequently. The choice of 010 in lecture and 01111110 in the textbook (Systems Approach section 2.3) are examples of this.
If you want to work on portal or similar, you might find it useful to right-click the link, select
copy link
orcopy URL
from the drop-down menu, then run the commandwget THAT_URL
, whereTHAT_URL
is the result of pasting the link/URL.↩︎