09.11.2016 Views

Foundations of Python Network Programming 978-1-4302-3004-5

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

CHAPTER 3 ■ TCP<br />

Using TCP Streams like Files<br />

Since TCP supports streams <strong>of</strong> data, they might have already reminded you <strong>of</strong> normal files, which also<br />

support reading and writing as fundamental operations. <strong>Python</strong> does a very good job <strong>of</strong> keeping these<br />

concepts separate: file objects can read() and write(), sockets can send() and recv(), and no kind <strong>of</strong><br />

object can do both. This is actually a substantially cleaner conceptual split than is achieved by the<br />

underlying POSIX interface, which lets a C programmer call read() and write() on a socket<br />

indiscriminately as though it were a normal file descriptor!<br />

But sometimes you will want to treat a socket like a normal <strong>Python</strong> file object—<strong>of</strong>ten because you<br />

want to pass it into code like that <strong>of</strong> the many <strong>Python</strong> modules such as pickle, json, and zlib that can<br />

read and write data directly from a file. For this purpose, <strong>Python</strong> provides a makefile() method on every<br />

socket that returns a <strong>Python</strong> file object that is really calling recv() and send() behind the scenes:<br />

>>> import socket<br />

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br />

>>> hasattr(s, 'read')<br />

False<br />

>>> f = s.makefile()<br />

>>> hasattr(f, 'read')<br />

True<br />

Sockets, like normal <strong>Python</strong> files, also have a fileno() method that lets you discover their file<br />

descriptor number in case you need to supply it to lower-level calls; we will find this very helpful when<br />

we explore select() and poll() in Chapter 7.<br />

Summary<br />

The TCP-powered “stream” socket does whatever is necessary—including re-transmitting lost packets,<br />

reordering the ones that arrive out <strong>of</strong> sequence, and splitting very large data streams into optimally sized<br />

packets for your network in the first place—to support the transmission and reception <strong>of</strong> streams <strong>of</strong> data<br />

over the network between two sockets.<br />

As with UDP, port numbers are used by TCP to distinguish the many stream endpoints that might<br />

exist on a single machine. A program that wants to accept incoming TCP connections needs to bind() to<br />

a port, run listen() on the socket, and then go into a loop that runs accept() over and over to receive a<br />

new socket for each incoming connection with which it can talk to each particular client that connects.<br />

Programs that want to connect to existing server ports need only create a socket and connect() to an<br />

address.<br />

Servers will usually want to set the SO_REUSEADDR option on the sockets they bind(), lest old<br />

connections still closing down on the same port from the last time the server was run prevent the<br />

operating system from allowing the binding.<br />

Data is actually sent and received with send() and recv(). Some protocols will mark up their data so<br />

that clients and servers know automatically when a communication is complete. Other protocols will<br />

treat the TCP socket as a true stream and send and receive until end-<strong>of</strong>-file is reached. The shutdown()<br />

socket method can be used to produce end-<strong>of</strong>-file in one direction on a socket (all sockets are<br />

bidirectional by nature) while leaving the other direction open.<br />

Deadlock can occur if two peers are written such that the socket fills with more and more data that<br />

never gets read. Eventually, one direction will no longer be able to send() and might hang forever<br />

waiting for the backlog to clear.<br />

If you want to pass a socket to a <strong>Python</strong> routine that knows how to read to or write from a normal<br />

file object, the makefile() socket method will give you a <strong>Python</strong> object that calls recv() and send()<br />

behind the scenes when the caller needs to read and write.<br />

49

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!