Timing in SSH

A lot of the work I do “on” my iPad consists of me essentially using the iPad as a terminal to edit files and run commands on one of my iMacs. Editing files is done in Textastic and synced to the Mac through iCloud (used to be through Dropbox). Running commands is done through either Textastic’s internal terminal, which works well enough for simple stuff, or Prompt, which has more robust terminal emulation and is better for more complex sessions. Since a lot of the terminal work I do isn’t complex, and consists of repeated invocations of

pdflatex report

and

python script.py

the responsiveness of the SSH connection to the Mac isn’t important to my productivity. The most common key I use is ↑ to rerun the last command.

But when I do need to construct and run longer commands, I’ve noticed a lag between the keyboard and the screen. I am by no means a fast typist, but I regularly get ahead of the display. This leads to typos that take a while to correct because repetition on the ⌫ key also outruns the display. I often just don’t know where the cursor is on the Mac because it’s not necessarily where I see it on the iPad.

This is not a bug in Prompt or Textastic. When I log into the Linux box that hosts this blog, both terminal programs are smoothly responsive. That the web server is halfway across the country makes it all the more frustrating when I have a choppy terminal session to the Mac that’s no more than 20 feet away from me.

When I decided to try to fix this annoyance, my working assumption was that there was something in the SSH server configuration causing the hiccups. So that was where my Googling started. I found an older post with a suggested change to the DNS settings in /etc/ssh/sshd_config, but that didn’t help because the change had already been made in more recent versions of macOS.

Somehow, though, I ran into this answer from Pistos on StackExchange. Apparently, in its neverending quest to save battery, Apple is powering down the wifi system between packets, which means a delay when new packets arrive or need to be sent. This doesn’t materially affect file transfers or streaming because the packets keep coming, but it plays havoc with intermittent communication like a terminal session.

Pistos’s solution was to set up two connections: one that keeps up a constant, albeit low volume, flow of bytes between the Mac and whatever was connected to it; and another for what he really wanted to do. I took his solution and turned it into this short shell script, which I called nolag:

#!/usr/bin/env bash
while true; do echo -n .; sleep 0.5; done

Pistos used a sleep argument of 0.1 seconds, but I have found 0.5 works just as well.

Now what I do is start a Prompt connection to my Mac and run nolag. Then I duplicate that session in Prompt and do my real work there.

Prompt session menu

This works perfectly and saves me much frustration.

You might be wondering why I don’t just plug my iMac into a wired network. It’s because my home wired network was strung back in the 90s and has bottlenecks that make it slower than my current wifi setup. A better question might be why Apple is trying to save battery life on a Mac that doesn’t run on battery.