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 5 ■ NETWORK DATA AND NETWORK ERRORS<br />

which also supplies calls like socket() and bind(). I suggest that you ignore these awkward functions,<br />

and use the struct module instead; it is more flexible, more general, and produces more readable code.<br />

Framing and Quoting<br />

If you are using UDP datagrams for communication, then the protocol itself takes the trouble to deliver<br />

your data in discrete and identifiable chunks—and you have to reorder and re-transmit them yourself if<br />

anything goes wrong on the network, as outlined in Chapter 2.<br />

But if you have made the far more common option <strong>of</strong> using a TCP stream for communication, then<br />

you will face the issue <strong>of</strong> framing—<strong>of</strong> how to delimit your messages so that the receiver can tell where<br />

one message ends and the next begins. Since the data you supply to sendall() might be broken up into<br />

several packets, the program that receives your message might have to make several recv() calls before<br />

your whole message has been read.<br />

The issue <strong>of</strong> framing asks the question: when is it safe for the receiver to finally stop calling recv()<br />

and respond to your message?<br />

As you might imagine, there are several approaches.<br />

First, there is a pattern that can be used by extremely simple network protocols that involve only the<br />

delivery <strong>of</strong> data—no response is expected, so there never has to come a time when the receiver decides<br />

“Enough!” and turns around to send a response. In this case, the sender can loop until all <strong>of</strong> the outgoing<br />

data has been passed to sendall() and then close() the socket. The receiver need only call recv()<br />

repeatedly until the call finally returns an empty string, indicating that the sender has finally closed the<br />

socket. You can see this pattern in Listing 5–1.<br />

Listing 5–1. Sending a Single Stream <strong>of</strong> Data<br />

#!/usr/bin/env python<br />

# <strong>Foundations</strong> <strong>of</strong> <strong>Python</strong> <strong>Network</strong> <strong>Programming</strong> - Chapter 5 - streamer.py<br />

# Client that sends data then closes the socket, not expecting a reply.<br />

import socket, sys<br />

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

HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1'<br />

PORT = 1060<br />

if sys.argv[1:] == ['server']:<br />

» s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)<br />

» s.bind((HOST, PORT))<br />

» s.listen(1)<br />

» print 'Listening at', s.getsockname()<br />

» sc, sockname = s.accept()<br />

» print 'Accepted connection from', sockname<br />

» sc.shutdown(socket.SHUT_WR)<br />

» message = ''<br />

» while True:<br />

» » more = sc.recv(8192) # arbitrary value <strong>of</strong> 8k<br />

» » if not more: # socket has closed when recv() returns ''<br />

» » » break<br />

» » message += more<br />

» print 'Done receiving the message; it says:'<br />

» print message<br />

» sc.close()<br />

75

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

Saved successfully!

Ooh no, something went wrong!