Foundations of Python Network Programming

(WallPaper) #1

Chapter 16 ■ telnet and SSh


298


•    Many programs read only one line of input at a time when listening to a terminal because
humans like to get an immediate response to every command they type. However, when
reading from a pipe or file, these same programs will wait until thousands of characters have
arrived before they try to interpret their first batch of input. As you just saw, bash stays in
line-at-a-time mode even if its input is a file, but Python decided it wanted to read a whole
Python script from its input before trying to execute even its first line.

•    It is even more common for programs to adjust their output based on whether they are talking
to a terminal. If a user might be watching, they want each line, or even each character, of
output to appear immediately. But if they are talking to a mere file or pipe, they will wait and
batch up large chunks of output and more efficiently send the whole chunk at one time.

Both of the last two issues, which involve buffering, cause all sorts of problems when you take a process that is
usually done manually and try to automate it—because in doing so, you often move from terminal input to input
provided through a file or pipe, and suddenly you find that the programs behave quite differently. They might even
seem to be hanging because “print” statements are not producing immediate output but are instead saving up their
results to push out all at once when their output buffer is full.
The foregoing problem is why many carefully written programs, both in Python and in other languages,
frequently call flush() on their output to make sure that anything waiting in a buffer goes ahead and gets sent out,
regardless of whether the output looks like a terminal.
These therefore are the basic problems with terminals and buffering: programs change their behavior, often in
idiosyncratic ways, when talking to a terminal, and they often start heavily buffering their output if they think they are
writing to a file or pipe instead of letting you see their output immediately.


Terminals Do Buffering

Beyond the program-specific behaviors just described, there is one further class of problems presented by terminal
devices. What happens when you want a program to read its input one character at a time, but the Unix terminal
device itself is buffering your keystrokes to deliver them as a whole line? This common problem happens because the
Unix terminal defaults to “canonical” input processing where it lets the user enter a whole line—and even edit it by
backspacing and retyping—before finally pressing Enter and letting the program see what they have typed.
If you want to turn off canonical processing so that a program can see every individual character as it is typed,
you can use the stty “set the current TTY’s settings” command to disable it.


$ stty -icanon


Another problem is that Unix terminals traditionally supported a pair of keystrokes originally designed so that
users could pause the output and read a screen full of text before it scrolled off and was replaced by more text. Often,
these were the characters Ctrl+S for “Stop” and Ctrl+Q for “Keep going,” and it was a source of great annoyance if
binary data worked its way into an automated Telnet connection because then the first Ctrl+S that happened to pass
across the channel would pause the terminal and probably ruin the session.
Again, this setting can be turned off with stty.


$ stty -ixon -ixoff


Those are the two biggest problems that you will run into with terminals doing buffering, but there are plenty of
less famous settings that can also cause you grief. Because there are so many—and because they vary between Unix
implementations—the stty command actually supports two modes. The modes are cooked and raw, which turn
dozens of settings like icanon and ixon on and off together.


$ stty raw
$ stty cooked

Free download pdf