I think the server loop does not do what is indended (although this doesn't explain the Wireshark results).

server.d

   (...)
   if (!conn.waitForData(dur!"msecs"(250))) continue;

   while (!conn.empty)
   {
     size_t chunk = cast(size_t)min(conn.leastSize, BUFFER_SIZE);
     conn.read(_buffer[0..chunk]);
     part.put(_buffer[0..chunk]);
   }
   (...)
});

In that code, conn.empty will block until data becomes available and in consequence will keep the loop running until all data is read/the connection is closed. It has to do so, because is is supposed to provide a logical end-of-stream marker. If you want to read packet-by-packet, you can use the non-blocking conn.dataAvailableForRead property instead:

while(conn.connected)
{
	if (!conn.waitForData(dur!"msecs"(250))) continue;
	while (conn.dataAvailableForRead)
	{
		size_t chunk = cast(size_t)min(conn.leastSize, BUFFER_SIZE);
		conn.read(_buffer[0..chunk]);
		part.put(_buffer[0..chunk]);
	}
	// ...
}

If the timeout is not explicitly needed, then this should be enough:

while (true)
{
	size_t chunk = cast(size_t)min(conn.leastSize, BUFFER_SIZE);
	if (chunk == 0) break; // leastSize == 0 <=> empty <=> !connected
	conn.read(_buffer[0..chunk]);
	// ...
}

leastSize will block as empty would do until data comes available, or until the connection is closed, in which case 0 is returned. I'll add some proper descriptions with the exact behavior of these properties to the documentation, as this is definitely not clear in the current state.