Allow Client#loop to take an optional timeout

This allows us to non-blockingly poll for available changes, and to avoid
blocking (eg) a reactor if we've been mistakenly woken up.