I wrote this when I assigned the lab in Fall, 2016; words like these should probably be in the write-up instead of off there.
The solution to this is very short (not much different than the size of the DateServer example, so the trick isn't to write a lot of code, but it's to get the code right. There are a few things that tend to hang people up here:
Using read() and write() to do byte-oriented I/O. Since you need this to handle binary content (things like JPGs), you can't use text oriented I/O (things like Scanners, BufferedReaders, and PrintWriters) because they tend to mangle binary data.
You may find it useful to call flush() on your output somewhere. When you write to an OutputStream the system may buffer those bytes to send a bunch as a group for efficiency reasons. If you know there are no more bytes coming, you can use flush() to force the system to send what it has.
I wrote this when I assigned the lab in Fall, 2016; words like these should probably be in the write-up instead of off there.