[Python编程(第4版)].(Programming.Python.4th.Edition).Mark.Lutz.文字版

(yzsuai) #1
such as the print built-in that writes text strings (as we’ve learned, binary mode
files require byte strings instead). When dealing with the raw socket directly,
though, text must still be manually encoded to byte strings, as shown in most of
Example 12-11’s tests.

Buffered streams, program output, and deadlock
As we learned in Chapters 5 and 10, standard streams are normally buffered, and
printed text may need to be flushed so that it appears on a socket connected to a
process’s output stream. Indeed, some of this example’s tests require explicit or
implicit flush calls to work properly at all; otherwise their output is either incom-
plete or absent altogether until program exit. In pathological cases, this can lead
to deadlock, with a process waiting for output from another that never appears. In
other configurations, we may also get socket errors in a reader if a writer exits too
soon, especially in two-way dialogs.
For example, if client1 and client4 did not flush periodically as they do, the only
reason that they would work is because output streams are automatically flushed
when their process exits. Without manual flushes, client1 transfers no data until
process exit (at which point all its output is sent at once in a single message), and
client4’s data is incomplete till exit (its last printed message is delayed).
Even more subtly, both client3 and client4 rely on the fact that the input built-
in first automatically flushes sys.stdout internally for its prompt option, thereby
sending data from preceding print calls. Without this implicit flush (or the addition
of manual flushes), client3 would experience deadlock immediately, as would
client4 if its manual flush call was removed (even with input’s flush, removing
client4’s manual flush causes its final print message to not be transferred until
process exit). client5 has this same behavior as client4, because it simply swaps
which process binds and accepts and which connects.
In the general case, if we wish to read a program’s output as it is produced, instead
of all at once when it exits or as its buffers fill, the program must either call
sys.stdout.flush periodically, or be run with unbuffered streams by using
Python’s -u command-line argument of Chapter 5 if applicable.
Although we can open socket wrapper files in unbuffered mode with a second
makefile argument of zero (like normal open), this does not allow the wrapper to
run in the text mode required for print and desired for input. In fact, attempting
to make a socket wrapper file both text mode and unbuffered this way fails with
an exception, because Python 3.X no longer supports unbuffered mode for text
files (it is allowed for binary mode only today). In other words, because print
requires text mode, buffered mode is also implied for output stream files. More-
over, attempting to open a socket file wrapper in line-buffered mode appears to not
be supported in Python 3.X (more on this ahead).
While some buffering behavior may be library and platform dependent, manual
flush calls or direct socket access might sometimes still be required. Note that
sockets can also be made nonblocking with the setblocking(0) method, but this


Making Sockets Look Like Files and Streams | 833
Free download pdf