Foundations of Python Network Programming

(WallPaper) #1

Chapter 3 ■ tCp


54


Since you are not allowed to create unidirectional sockets through a standard socket() call, many programmers
who need to send information in only one direction over a socket will first create it and then—as soon as it is
connected—immediately run shutdown() for the direction they do not need. This means that no operating system
buffers will be needlessly filled if the peer with which they are communicating accidentally tries to send data in
a direction that it should not.
Running shutdown() immediately on sockets that should really be unidirectional also provides a more obvious
error message for a peer that does get confused and tries to send data. Otherwise, the unexpected data either will be
simply ignored or might even fill a buffer and cause a deadlock because it will never be read.


Using TCP Streams Like Files


Since TCP supports streams of data, they might have already reminded you of normal files, which also support reading
and writing sequential data as fundamental operations. Python does a good job of keeping these concepts separate.
File objects can read() and write(), while sockets can only send() and recv(). And no kind of object can do both.
(This is actually a substantially cleaner and more portable conceptual split than is achieved by the underlying POSIX
interface, which lets a C programmer call read() and write() on a socket indiscriminately as though it were a normal
file descriptor.)
But sometimes you will want to treat a socket like a normal Python file object—often because you want to pass it
to code like that, like the many Python modules such as pickle, json, and zlib, can read and write data directly from
a file. For this purpose, Python provides a makefile() method on every socket that returns a Python file object that is
really calling recv() and send() behind the scenes.





import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
hasattr(sock, 'read')
False
f = sock.makefile()
hasattr(f, 'read')
True





Sockets on a Unix-derived system like Ubuntu and Mac OS X, like normal Python files, also have a fileno()
method that lets you discover their file descriptor number in case you need to supply it to lower-level calls. You will
find this helpful when you explore select() and poll() in Chapter 7.


Summary


The TCP-powered “stream” socket does whatever is necessary—including retransmitting lost packets, reordering the
ones that arrive out of sequence, and splitting large data streams into optimally sized packets for your network—to
support the transmission and reception of streams of data over the network between two sockets.
As with UDP, port numbers are used by TCP to distinguish the many stream endpoints that might exist on a
single machine. A program that wants to accept incoming TCP connections needs to bind() to a port, run listen()
on the socket, and then go into a loop that runs accept() over and over to receive a new socket for each incoming
connection with which it can talk to each particular client that connects. Programs that want to connect to existing
server ports need only create a socket and connect() to an address.
Servers will usually want to set the SO_REUSEADDR option on the sockets they bind(), lest old connections still
closing down on the same port from the last time the server was run prevent the operating system from allowing the
binding.

Free download pdf