├── README.txt ├── errata.txt ├── python2 ├── 10 │ ├── excerpt.html │ ├── fetch_mechanize.py │ ├── fetch_urllib2.py │ ├── phoenix-tidied.html │ ├── phoenix.html │ └── weather.py ├── 11 │ ├── bottle_app.py │ ├── bottle_template.html │ └── wsgi_app.py ├── 12 │ ├── message.txt │ ├── mime_decode.py │ ├── mime_gen_alt.py │ ├── mime_gen_basic.py │ ├── mime_gen_both.py │ ├── mime_headers.py │ ├── mime_parse_headers.py │ ├── mime_structure.py │ ├── test.txt │ ├── test.txt.gz │ ├── trad_gen_newhdrs.py │ ├── trad_gen_simple.py │ └── trad_parse.py ├── 13 │ ├── debug.py │ ├── ehlo.py │ ├── login.py │ ├── simple.py │ └── tls.py ├── 14 │ ├── download-and-delete.py │ ├── mailbox.py │ └── popconn.py ├── 15 │ ├── folder_info.py │ ├── mailbox_summary.py │ ├── open_imap.py │ ├── open_imap.txt │ ├── open_imaplib.py │ ├── open_imaplib.txt │ └── simple_client.py ├── 16 │ ├── fabfile.py │ ├── sftp.py │ ├── shell.py │ ├── ssh_commands.py │ ├── ssh_simple.py │ ├── ssh_simple.txt │ ├── ssh_threads.py │ ├── telnet_codes.py │ └── telnet_login.py ├── 17 │ ├── advbinarydl.py │ ├── advbinaryul.py │ ├── asciidl.py │ ├── binarydl.py │ ├── binaryul.py │ ├── connect.py │ ├── dir.py │ ├── nlst.py │ └── recursedl.py ├── 18 │ ├── jsonrpc_client.py │ ├── jsonrpc_server.py │ ├── rpyc_client.py │ ├── rpyc_server.py │ ├── testfile.txt │ ├── xmlrpc_client.py │ ├── xmlrpc_introspect.py │ ├── xmlrpc_multicall.py │ └── xmlrpc_server.py ├── 01 │ ├── getname.py │ ├── search1.py │ ├── search2.py │ ├── search3.py │ ├── search4.py │ └── search4.txt ├── 02 │ ├── big_sender.py │ ├── udp_broadcast.py │ ├── udp_local.py │ └── udp_remote.py ├── 03 │ ├── tcp_deadlock.py │ └── tcp_sixteen.py ├── 04 │ ├── dns_basic.py │ ├── dns_mx.py │ ├── forward_reverse.py │ └── www_ping.py ├── 05 │ ├── blocks.py │ └── streamer.py ├── 06 │ ├── certfiles.crt │ └── sslclient.py ├── 07 │ ├── Bench.sh │ ├── Test.sh │ ├── TestLancelot.conf │ ├── client.py │ ├── lancelot.py │ ├── lancelot_tests.py │ ├── my_trace.py │ ├── server_SocketServer.py │ ├── server_async.py │ ├── server_multi.py │ ├── server_poll.py │ ├── server_simple.py │ └── server_twisted.py ├── 08 │ ├── hashing.py │ ├── queuecrazy.py │ └── squares.py └── 09 │ ├── get_rfc2616.py │ └── verbose_http.py └── python3 ├── 10 ├── excerpt.html ├── fetch_mechanize.py ├── fetch_urllib2.py ├── phoenix-tidied.html ├── phoenix.html └── weather.py ├── 11 ├── bottle_app.py ├── bottle_template.html └── wsgi_app.py ├── 12 ├── message.txt ├── mime_decode.py ├── mime_gen_alt.py ├── mime_gen_basic.py ├── mime_gen_both.py ├── mime_headers.py ├── mime_parse_headers.py ├── mime_structure.py ├── test.txt ├── test.txt.gz ├── trad_gen_newhdrs.py ├── trad_gen_simple.py └── trad_parse.py ├── 13 ├── debug.py ├── ehlo.py ├── login.py ├── simple.py └── tls.py ├── 14 ├── download-and-delete.py ├── mailbox.py └── popconn.py ├── 15 ├── folder_info.py ├── mailbox_summary.py ├── open_imap.py ├── open_imap.txt ├── open_imaplib.py ├── open_imaplib.txt └── simple_client.py ├── 16 ├── fabfile.py ├── sftp.py ├── shell.py ├── ssh_commands.py ├── ssh_simple.py ├── ssh_simple.txt ├── ssh_threads.py ├── telnet_codes.py └── telnet_login.py ├── 17 ├── advbinarydl.py ├── advbinaryul.py ├── asciidl.py ├── binarydl.py ├── binaryul.py ├── connect.py ├── dir.py ├── nlst.py └── recursedl.py ├── 18 ├── jsonrpc_client.py ├── jsonrpc_server.py ├── rpyc_client.py ├── rpyc_server.py ├── testfile.txt ├── xmlrpc_client.py ├── xmlrpc_introspect.py ├── xmlrpc_multicall.py └── xmlrpc_server.py ├── 01 ├── getname.py ├── search1.py ├── search2.py ├── search3.py ├── search4.py └── search4.txt ├── 02 ├── big_sender.py ├── udp_broadcast.py ├── udp_local.py └── udp_remote.py ├── 03 ├── tcp_deadlock.py └── tcp_sixteen.py ├── 04 ├── dns_basic.py ├── dns_mx.py ├── forward_reverse.py └── www_ping.py ├── 05 ├── blocks.py └── streamer.py ├── 06 ├── certfiles.crt └── sslclient.py ├── 07 ├── Bench.sh ├── Test.sh ├── TestLancelot.conf ├── client.py ├── lancelot.py ├── lancelot_tests.py ├── my_trace.py ├── server_SocketServer.py ├── server_async.py ├── server_multi.py ├── server_poll.py ├── server_simple.py └── server_twisted.py ├── 08 ├── hashing.py ├── queuecrazy.py └── squares.py └── 09 ├── get_rfc2616.py └── verbose_http.py /README.txt: -------------------------------------------------------------------------------- 1 | This archive contains the example programs for the Apress book: 2 | 3 | Foundations of Python Network Programming 4 | The Comprehensive Guide to Building Network Applications with Python 5 | Second Edition 6 | 7 | The examples for each chapter are in individual directories for that 8 | chapter. Please refer to the comments in the book's introduction for 9 | information on running these examples, and platform-specific notes. 10 | 11 | If errors are found in the examples after the book goes to print, 12 | updated examples will be posted here. 13 | 14 | -- Brandon Rhodes 15 | January, 2011 16 | 17 | 18 | STATUS OF PYTHON 3 EXAMPLES 19 | As of January 2011 20 | 21 | 01/getname.py - OK 22 | 01/search1.py - waiting on port of "googlemaps" to Python 3 23 | 01/search2.py - OK 24 | 01/search3.py - OK 25 | 01/search4.py - OK 26 | 27 | 02/big_sender.py - OK 28 | 02/udp_broadcast.py - OK 29 | 02/udp_local.py - OK 30 | 02/udp_remote.py - OK 31 | 32 | 03/tcp_deadlock.py - OK 33 | 03/tcp_sixteen.py - OK 34 | 35 | 04/dns_basic.py - waiting on port of "pydns" to Python 3 36 | 04/dns_mx.py - waiting on port of "pydns" to Python 3 37 | 04/forward_reverse.py - OK 38 | 04/www_ping.py - OK 39 | 40 | 05/blocks.py - OK 41 | 05/streamer.py - OK 42 | 43 | 06/sslclient.py - OK 44 | 45 | 07/client.py - OK 46 | 07/lancelot.py - OK 47 | 07/lancelot_tests.py - waiting on port of "funkload" to Python 3 48 | 07/my_trace.py - OK 49 | 07/server_SocketServer.py - OK 50 | 07/server_async.py - OK 51 | 07/server_multi.py - OK 52 | 07/server_poll.py - OK 53 | 07/server_simple.py - OK 54 | 07/server_twisted.py - waiting on port of "Twisted" to Python 3 55 | 56 | 08/hashing.py - OK 57 | 08/queuecrazy.py - waiting on port of "pyzmq" to Python 3 58 | 08/squares.py - waiting on port of "python-memcached" to Python 3 59 | 60 | 09/get_rfc2616.py - OK 61 | 09/verbose_handler.py - OK 62 | 63 | 10/fetch_mechanize.py - waiting on port of "mechanize" to Python 3 64 | 10/fetch_urllib2.py - OK 65 | 10/weather.py - "lxml" part works great; "BeautifulSoup" is commented out 66 | 67 | 11/bottle_app.py - OK 68 | 11/wsgi_app.py - OK 69 | 70 | 12/mime_decode.py - OK 71 | 12/mime_gen_alt.py - OK 72 | 12/mime_gen_basic.py - OK 73 | 12/mime_gen_both.py - OK 74 | 12/mime_headers.py - OK 75 | 12/mime_parse_headers.py - OK (but why does the space character disappear?) 76 | 12/mime_structure.py - OK 77 | 12/trad_gen_newhdrs.py - OK 78 | 12/trad_gen_simple.py - OK 79 | 12/trad_parse.py - OK 80 | 81 | 13/debug.py - OK 82 | 13/ehlo.py - OK 83 | 13/login.py - OK 84 | 13/simple.py - OK 85 | 13/tls.py - OK 86 | 87 | 14/download-and-delete.py - OK 88 | 14/mailbox.py - OK 89 | 14/popconn.py - OK 90 | 91 | 15/folder_info.py - waiting on port of "imapclient" to Python 3 92 | 15/mailbox_summary.py - waiting on port of "imapclient" to Python 3 93 | 15/open_imap.py - waiting on port of "imapclient" to Python 3 94 | 15/open_imaplib.py - OK 95 | 15/simple_client.py - waiting on port of "imapclient" to Python 3 96 | 97 | 16/fabfile.py - waiting on port of "fabric" to Python 3 98 | 16/sftp.py - waiting on port of "paramiko" to Python 3 99 | 16/shell.py - OK 100 | 16/ssh_commands.py - waiting on port of "paramiko" to Python 3 101 | 16/ssh_simple.py - waiting on port of "paramiko" to Python 3 102 | 16/ssh_threads.py - waiting on port of "paramiko" to Python 3 103 | 16/telnet_codes.py - OK 104 | 16/telnet_login.py - OK 105 | 106 | 17/advbinarydl.py - OK 107 | 17/advbinaryul.py - OK 108 | 17/asciidl.py - OK 109 | 17/binarydl.py - OK 110 | 17/binaryul.py - OK 111 | 17/connect.py - OK 112 | 17/dir.py - OK 113 | 17/nlst.py - OK 114 | 17/recursedl.py - OK 115 | 116 | 18/jsonrpc_client.py - waiting on port of "lovely.jsonrpc" to Python 3 117 | 18/jsonrpc_server.py - waiting on port of "lovely.jsonrpc" to Python 3 118 | 18/rpyc_client.py - waiting on port of "rpyc" to Python 3 119 | 18/rpyc_server.py - waiting on port of "rpyc" to Python 3 120 | 18/xmlrpc_client.py - OK 121 | 18/xmlrpc_introspect.py - OK 122 | 18/xmlrpc_multicall.py - OK 123 | 18/xmlrpc_server.py - OK 124 | -------------------------------------------------------------------------------- /errata.txt: -------------------------------------------------------------------------------- 1 | On page 21: 2 | ephemeral range in linux as described is inaccurate, check /proc/sys/net/ipv4/ip_local_port_range 3 | 4 | On page 21: 5 | says that client uses recv instead of recvfrom, but code listing in book says otherwise. 6 | On page 21: 7 | Note that the Python program can always use a socket's getsockname() method to retrieve the current IP and port to which the socket is bound. 8 | 9 | Warning: As documented here: http://bugs.python.org/issue1049 10 | 11 | The behavior and return value for calling socket.socket.getsockname() on 12 | an unconnected unbound socket is unspecified. On UNIX, it returns an 13 | address ('0.0.0.0', 0), while on Windows it raises an obscure exception 14 | "error: (10022, 'Invalid argument')". 15 | On page 26: 16 | 17 | The first code listing: 18 | 19 | >>> import socket 20 | >>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 21 | >>> s.sendto('Fake reply', ('127.0.0.1', 47873)) 22 | 23 | The indentation for the second line appears wrong. It looks like there is whitespace before the "s =", when there shouldn't be. 24 | 25 | On page 68: 26 | 27 | script dns_mx.py resolves the hostname of all the mx records to the same IP address. 28 | In resolve_hostname "name = sys.argv[1]"should be changed to "name = hostname" 29 | 30 | On page 73: 31 | 32 | Instead of being stored as four decimal digits 4, 4, 2, and 3 with ... 33 | 34 | should be: 35 | 36 | Instead of being stored as four decimal digits 4, 2, 5, and 3 with ... 37 | 38 | On page 122: 39 | 40 | (from the queue module) 41 | 42 | should be: 43 | 44 | (from the Queue module) 45 | 46 | note the capital Q 47 | 48 | On page 243: 49 | "remove" should be "remote" in: 50 | 51 | "A locally stored message can be uploaded directly to one of the remove folders" 52 | 53 | -------------------------------------------------------------------------------- /python2/01/getname.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - getname.py 3 | 4 | import socket 5 | hostname = 'maps.google.com' 6 | addr = socket.gethostbyname(hostname) 7 | print 'The address of', hostname, 'is', addr 8 | -------------------------------------------------------------------------------- /python2/01/search1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search1.py 3 | 4 | from googlemaps import GoogleMaps 5 | address = '207 N. Defiance St, Archbold, OH' 6 | print GoogleMaps().address_to_latlng(address) 7 | -------------------------------------------------------------------------------- /python2/01/search2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search2.py 3 | 4 | import urllib, urllib2 5 | try: 6 | import json 7 | except ImportError: # for Python 2.5 8 | import simplejson as json 9 | 10 | params = {'q': '207 N. Defiance St, Archbold, OH', 11 | 'output': 'json', 'oe': 'utf8'} 12 | url = 'http://maps.google.com/maps/geo?' + urllib.urlencode(params) 13 | 14 | rawreply = urllib2.urlopen(url).read() 15 | 16 | reply = json.loads(rawreply) 17 | print reply['Placemark'][0]['Point']['coordinates'][:-1] 18 | -------------------------------------------------------------------------------- /python2/01/search3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search3.py 3 | 4 | import httplib 5 | try: 6 | import json 7 | except ImportError: # for Python 2.5 8 | import simplejson as json 9 | 10 | path = ('/maps/geo?q=207+N.+Defiance+St%2C+Archbold%2C+OH' 11 | '&output=json&oe=utf8') 12 | 13 | connection = httplib.HTTPConnection('maps.google.com') 14 | connection.request('GET', path) 15 | rawreply = connection.getresponse().read() 16 | 17 | reply = json.loads(rawreply) 18 | print reply['Placemark'][0]['Point']['coordinates'][:-1] 19 | -------------------------------------------------------------------------------- /python2/01/search4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search4.py 3 | 4 | import socket 5 | sock = socket.socket() 6 | sock.connect(('maps.google.com', 80)) 7 | sock.sendall( 8 | 'GET /maps/geo?q=207+N.+Defiance+St%2C+Archbold%2C+OH' 9 | '&output=json&oe=utf8&sensor=false HTTP/1.1\r\n' 10 | 'Host: maps.google.com:80\r\n' 11 | 'User-Agent: search4.py\r\n' 12 | 'Connection: close\r\n' 13 | '\r\n') 14 | rawreply = sock.recv(4096) 15 | print rawreply 16 | -------------------------------------------------------------------------------- /python2/01/search4.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Content-Type: text/javascript; charset=UTF-8 3 | Vary: Accept-Language 4 | Date: Wed, 21 Jul 2010 16:10:38 GMT 5 | Server: mafe 6 | Cache-Control: private, x-gzip-ok="" 7 | X-XSS-Protection: 1; mode=block 8 | Connection: close 9 | 10 | { 11 | "name": "207 N. Defiance St, Archbold, OH", 12 | "Status": { 13 | "code": 200, 14 | "request": "geocode" 15 | }, 16 | "Placemark": [ { 17 | ... 18 | "Point": { 19 | "coordinates": [ -84.3063479, 41.5228242, 0 ] 20 | } 21 | } ] 22 | } 23 | 24 | -------------------------------------------------------------------------------- /python2/02/big_sender.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - big_sender.py 3 | # Send a big UDP packet to our server. 4 | 5 | import IN, socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | MAX = 65535 9 | PORT = 1060 10 | 11 | if len(sys.argv) != 2: 12 | print >>sys.stderr, 'usage: big_sender.py host' 13 | sys.exit(2) 14 | 15 | hostname = sys.argv[1] 16 | s.connect((hostname, PORT)) 17 | s.setsockopt(socket.IPPROTO_IP, IN.IP_MTU_DISCOVER, IN.IP_PMTUDISC_DO) 18 | try: 19 | s.send('#' * 65000) 20 | except socket.error: 21 | print 'The message did not make it' 22 | option = getattr(IN, 'IP_MTU', 14) # constant taken from 23 | print 'MTU:', s.getsockopt(socket.IPPROTO_IP, option) 24 | else: 25 | print 'The big message was sent! Your network supports really big packets!' 26 | -------------------------------------------------------------------------------- /python2/02/udp_broadcast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - udp_broadcast.py 3 | # UDP client and server for broadcast messages on a local LAN 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 8 | 9 | MAX = 65535 10 | PORT = 1060 11 | 12 | if 2 <= len(sys.argv) <= 3 and sys.argv[1] == 'server': 13 | s.bind(('', PORT)) 14 | print 'Listening for broadcasts at', s.getsockname() 15 | while True: 16 | data, address = s.recvfrom(MAX) 17 | print 'The client at %r says: %r' % (address, data) 18 | 19 | elif len(sys.argv) == 3 and sys.argv[1] == 'client': 20 | network = sys.argv[2] 21 | s.sendto('Broadcast message!', (network, PORT)) 22 | 23 | else: 24 | print >>sys.stderr, 'usage: udp_broadcast.py server' 25 | print >>sys.stderr, ' or: udp_broadcast.py client ' 26 | sys.exit(2) 27 | -------------------------------------------------------------------------------- /python2/02/udp_local.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - udp_local.py 3 | # UDP client and server on localhost 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | MAX = 65535 9 | PORT = 1060 10 | 11 | if sys.argv[1:] == ['server']: 12 | s.bind(('127.0.0.1', PORT)) 13 | print 'Listening at', s.getsockname() 14 | while True: 15 | data, address = s.recvfrom(MAX) 16 | print 'The client at', address, 'says', repr(data) 17 | s.sendto('Your data was %d bytes' % len(data), address) 18 | 19 | elif sys.argv[1:] == ['client']: 20 | print 'Address before sending:', s.getsockname() 21 | s.sendto('This is my message', ('127.0.0.1', PORT)) 22 | print 'Address after sending', s.getsockname() 23 | data, address = s.recvfrom(MAX) # overly promiscuous - see Chapter 2 24 | print 'The server', address, 'says', repr(data) 25 | 26 | else: 27 | print >>sys.stderr, 'usage: udp_local.py server|client' 28 | -------------------------------------------------------------------------------- /python2/02/udp_remote.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - udp_remote.py 3 | # UDP client and server for talking over the network 4 | 5 | import random, socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | MAX = 65535 9 | PORT = 1060 10 | 11 | if 2 <= len(sys.argv) <= 3 and sys.argv[1] == 'server': 12 | interface = sys.argv[2] if len(sys.argv) > 2 else '' 13 | s.bind((interface, PORT)) 14 | print 'Listening at', s.getsockname() 15 | while True: 16 | data, address = s.recvfrom(MAX) 17 | if random.randint(0, 1): 18 | print 'The client at', address, 'says:', repr(data) 19 | s.sendto('Your data was %d bytes' % len(data), address) 20 | else: 21 | print 'Pretending to drop packet from', address 22 | 23 | elif len(sys.argv) == 3 and sys.argv[1] == 'client': 24 | hostname = sys.argv[2] 25 | s.connect((hostname, PORT)) 26 | print 'Client socket name is', s.getsockname() 27 | delay = 0.1 28 | while True: 29 | s.send('This is another message') 30 | print 'Waiting up to', delay, 'seconds for a reply' 31 | s.settimeout(delay) 32 | try: 33 | data = s.recv(MAX) 34 | except socket.timeout: 35 | delay *= 2 # wait even longer for the next request 36 | if delay > 2.0: 37 | raise RuntimeError('I think the server is down') 38 | else: 39 | break # we are done, and can stop looping 40 | 41 | print 'The server says', repr(data) 42 | 43 | else: 44 | print >>sys.stderr, 'usage: udp_remote.py server [ ]' 45 | print >>sys.stderr, ' or: udp_remote.py client ' 46 | sys.exit(2) 47 | -------------------------------------------------------------------------------- /python2/03/tcp_deadlock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 3 - tcp_deadlock.py 3 | # TCP client and server that leave too much data waiting 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = '127.0.0.1' 9 | PORT = 1060 10 | 11 | if sys.argv[1:] == ['server']: 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | s.bind((HOST, PORT)) 14 | s.listen(1) 15 | while True: 16 | print 'Listening at', s.getsockname() 17 | sc, sockname = s.accept() 18 | print 'Processing up to 1024 bytes at a time from', sockname 19 | n = 0 20 | while True: 21 | message = sc.recv(1024) 22 | if not message: 23 | break 24 | sc.sendall(message.upper()) # send it back uppercase 25 | n += len(message) 26 | print '\r%d bytes processed so far' % (n,), 27 | sys.stdout.flush() 28 | print 29 | sc.close() 30 | print 'Completed processing' 31 | 32 | elif len(sys.argv) == 3 and sys.argv[1] == 'client' and sys.argv[2].isdigit(): 33 | 34 | bytes = (int(sys.argv[2]) + 15) // 16 * 16 # round up to // 16 35 | message = 'capitalize this!' # 16-byte message to repeat over and over 36 | 37 | print 'Sending', bytes, 'bytes of data, in chunks of 16 bytes' 38 | s.connect((HOST, PORT)) 39 | 40 | sent = 0 41 | while sent < bytes: 42 | s.sendall(message) 43 | sent += len(message) 44 | print '\r%d bytes sent' % (sent,), 45 | sys.stdout.flush() 46 | 47 | print 48 | s.shutdown(socket.SHUT_WR) 49 | 50 | print 'Receiving all the data the server sends back' 51 | 52 | received = 0 53 | while True: 54 | data = s.recv(42) 55 | if not received: 56 | print 'The first data received says', repr(data) 57 | received += len(data) 58 | if not data: 59 | break 60 | print '\r%d bytes received' % (received,), 61 | 62 | s.close() 63 | 64 | else: 65 | print >>sys.stderr, 'usage: tcp_deadlock.py server | client ' 66 | -------------------------------------------------------------------------------- /python2/03/tcp_sixteen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 3 - tcp_sixteen.py 3 | # Simple TCP client and server that send and receive 16 octets 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1' 9 | PORT = 1060 10 | 11 | def recvall(sock, length): 12 | data = '' 13 | while len(data) < length: 14 | more = sock.recv(length - len(data)) 15 | if not more: 16 | raise EOFError('socket closed %d bytes into a %d-byte message' 17 | % (len(data), length)) 18 | data += more 19 | return data 20 | 21 | if sys.argv[1:] == ['server']: 22 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 23 | s.bind((HOST, PORT)) 24 | s.listen(1) 25 | while True: 26 | print 'Listening at', s.getsockname() 27 | sc, sockname = s.accept() 28 | print 'We have accepted a connection from', sockname 29 | print 'Socket connects', sc.getsockname(), 'and', sc.getpeername() 30 | message = recvall(sc, 16) 31 | print 'The incoming sixteen-octet message says', repr(message) 32 | sc.sendall('Farewell, client') 33 | sc.close() 34 | print 'Reply sent, socket closed' 35 | 36 | elif sys.argv[1:] == ['client']: 37 | s.connect((HOST, PORT)) 38 | print 'Client has been assigned socket name', s.getsockname() 39 | s.sendall('Hi there, server') 40 | reply = recvall(s, 16) 41 | print 'The server said', repr(reply) 42 | s.close() 43 | 44 | else: 45 | print >>sys.stderr, 'usage: tcp_local.py server|client [host]' 46 | -------------------------------------------------------------------------------- /python2/04/dns_basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - dns_basic.py 3 | # Basic DNS query 4 | 5 | import sys, DNS 6 | 7 | if len(sys.argv) != 2: 8 | print >>sys.stderr, 'usage: dns_basic.py ' 9 | sys.exit(2) 10 | 11 | DNS.DiscoverNameServers() 12 | request = DNS.Request() 13 | for qt in DNS.Type.A, DNS.Type.AAAA, DNS.Type.CNAME, DNS.Type.MX, DNS.Type.NS: 14 | reply = request.req(name=sys.argv[1], qtype=qt) 15 | for answer in reply.answers: 16 | print answer['name'], answer['classstr'], answer['typename'], \ 17 | repr(answer['data']) 18 | -------------------------------------------------------------------------------- /python2/04/dns_mx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - dns_mx.py 3 | # Looking up a mail domain - the part of an email address after the `@` 4 | 5 | import sys, DNS 6 | 7 | if len(sys.argv) != 2: 8 | print >>sys.stderr, 'usage: dns_basic.py ' 9 | sys.exit(2) 10 | 11 | def resolve_hostname(hostname, indent=0): 12 | """Print an A or AAAA record for `hostname`; follow CNAMEs if necessary.""" 13 | indent = indent + 4 14 | istr = ' ' * indent 15 | request = DNS.Request() 16 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.A) 17 | if reply.answers: 18 | for answer in reply.answers: 19 | print istr, 'Hostname', hostname, '= A', answer['data'] 20 | return 21 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.AAAA) 22 | if reply.answers: 23 | for answer in reply.answers: 24 | print istr, 'Hostname', hostname, '= AAAA', answer['data'] 25 | return 26 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.CNAME) 27 | if reply.answers: 28 | cname = reply.answers[0]['data'] 29 | print istr, 'Hostname', hostname, 'is an alias for', cname 30 | resolve_hostname(cname, indent) 31 | return 32 | print istr, 'ERROR: no records for', hostname 33 | 34 | def resolve_email_domain(domain): 35 | """Print mail server IP addresses for an email address @ `domain`.""" 36 | request = DNS.Request() 37 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.MX) 38 | if reply.answers: 39 | print 'The domain %r has explicit MX records!' % (domain,) 40 | print 'Try the servers in this order:' 41 | datalist = [ answer['data'] for answer in reply.answers ] 42 | datalist.sort() # lower-priority integers go first 43 | for data in datalist: 44 | priority = data[0] 45 | hostname = data[1] 46 | print 'Priority:', priority, ' Hostname:', hostname 47 | resolve_hostname(hostname) 48 | else: 49 | print 'Drat, this domain has no explicit MX records' 50 | print 'We will have to try resolving it as an A, AAAA, or CNAME' 51 | resolve_hostname(domain) 52 | 53 | DNS.DiscoverNameServers() 54 | resolve_email_domain(sys.argv[1]) 55 | -------------------------------------------------------------------------------- /python2/04/forward_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - forward_reverse.py 3 | # Checking whether a host name works both forwards and backwards. 4 | 5 | import socket, sys 6 | 7 | if len(sys.argv) != 2: 8 | print >>sys.stderr, 'usage: forward_reverse.py ' 9 | sys.exit(2) 10 | 11 | hostname = sys.argv[1] 12 | 13 | try: 14 | infolist = socket.getaddrinfo( 15 | hostname, 0, 0, socket.SOCK_STREAM, 0, 16 | socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME, 17 | ) 18 | except socket.gaierror, e: 19 | print 'Forward name service failure:', e.args[1] 20 | sys.exit(1) 21 | 22 | info = infolist[0] # choose the first, if there are several addresses 23 | canonical = info[3] 24 | socketname = info[4] 25 | ip = socketname[0] 26 | 27 | if not canonical: 28 | print 'WARNING! The IP address', ip, 'has no reverse name' 29 | sys.exit(1) 30 | 31 | print hostname, 'has IP address', ip 32 | print ip, 'has the canonical hostname', canonical 33 | 34 | # Lowercase for case-insensitive comparison, and chop off hostnames. 35 | 36 | forward = hostname.lower().split('.') 37 | reverse = canonical.lower().split('.') 38 | 39 | if forward == reverse: 40 | print 'Wow, the names agree completely!' 41 | sys.exit(0) 42 | 43 | # Truncate the domain names, which now look like ['www', mit', 'edu'], 44 | # to the same length and compare. Failing that, be willing to try a 45 | # compare with the first element (the hostname?) lopped off if both of 46 | # they are the same length. 47 | 48 | length = min(len(forward), len(reverse)) 49 | if (forward[-length:] == reverse[-length:] 50 | or (len(forward) == len(reverse) 51 | and forward[-length+1:] == reverse[-length+1:] 52 | and len(forward[-2]) > 2)): # avoid thinking '.co.uk' means a match! 53 | print 'The forward and reverse names have a lot in common' 54 | else: 55 | print 'WARNING! The reverse name belongs to a different organization' 56 | -------------------------------------------------------------------------------- /python2/04/www_ping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - www_ping.py 3 | # Find the WWW service of an arbitrary host using getaddrinfo(). 4 | 5 | import socket, sys 6 | 7 | if len(sys.argv) != 2: 8 | print >>sys.stderr, 'usage: www_ping.py ' 9 | sys.exit(2) 10 | 11 | hostname_or_ip = sys.argv[1] 12 | 13 | try: 14 | infolist = socket.getaddrinfo( 15 | hostname_or_ip, 'www', 0, socket.SOCK_STREAM, 0, 16 | socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME, 17 | ) 18 | except socket.gaierror, e: 19 | print 'Name service failure:', e.args[1] 20 | sys.exit(1) 21 | 22 | info = infolist[0] # per standard recommendation, try the first one 23 | socket_args = info[0:3] 24 | address = info[4] 25 | s = socket.socket(*socket_args) 26 | try: 27 | s.connect(address) 28 | except socket.error, e: 29 | print 'Network failure:', e.args[1] 30 | else: 31 | print 'Success: host', info[3], 'is listening on port 80' 32 | -------------------------------------------------------------------------------- /python2/05/blocks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 5 - blocks.py 3 | # Sending data one block at a time. 4 | 5 | import socket, struct, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1' 9 | PORT = 1060 10 | format = struct.Struct('!I') # for messages up to 2**32 - 1 in length 11 | 12 | def recvall(sock, length): 13 | data = '' 14 | while len(data) < length: 15 | more = sock.recv(length - len(data)) 16 | if not more: 17 | raise EOFError('socket closed %d bytes into a %d-byte message' 18 | % (len(data), length)) 19 | data += more 20 | return data 21 | 22 | def get(sock): 23 | lendata = recvall(sock, format.size) 24 | (length,) = format.unpack(lendata) 25 | return recvall(sock, length) 26 | 27 | def put(sock, message): 28 | sock.send(format.pack(len(message)) + message) 29 | 30 | if sys.argv[1:] == ['server']: 31 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 32 | s.bind((HOST, PORT)) 33 | s.listen(1) 34 | print 'Listening at', s.getsockname() 35 | sc, sockname = s.accept() 36 | print 'Accepted connection from', sockname 37 | sc.shutdown(socket.SHUT_WR) 38 | while True: 39 | message = get(sc) 40 | if not message: 41 | break 42 | print 'Message says:', repr(message) 43 | sc.close() 44 | s.close() 45 | 46 | elif sys.argv[1:] == ['client']: 47 | s.connect((HOST, PORT)) 48 | s.shutdown(socket.SHUT_RD) 49 | put(s, 'Beautiful is better than ugly.') 50 | put(s, 'Explicit is better than implicit.') 51 | put(s, 'Simple is better than complex.') 52 | put(s, '') 53 | s.close() 54 | 55 | else: 56 | print >>sys.stderr, 'usage: streamer.py server|client [host]' 57 | -------------------------------------------------------------------------------- /python2/05/streamer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 5 - streamer.py 3 | # Client that sends data then closes the socket, not expecting a reply. 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1' 9 | PORT = 1060 10 | 11 | if sys.argv[1:] == ['server']: 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | s.bind((HOST, PORT)) 14 | s.listen(1) 15 | print 'Listening at', s.getsockname() 16 | sc, sockname = s.accept() 17 | print 'Accepted connection from', sockname 18 | sc.shutdown(socket.SHUT_WR) 19 | message = '' 20 | while True: 21 | more = sc.recv(8192) # arbitrary value of 8k 22 | if not more: # socket has closed when recv() returns '' 23 | break 24 | message += more 25 | print 'Done receiving the message; it says:' 26 | print message 27 | sc.close() 28 | s.close() 29 | 30 | elif sys.argv[1:] == ['client']: 31 | s.connect((HOST, PORT)) 32 | s.shutdown(socket.SHUT_RD) 33 | s.sendall('Beautiful is better than ugly.\n') 34 | s.sendall('Explicit is better than implicit.\n') 35 | s.sendall('Simple is better than complex.\n') 36 | s.close() 37 | 38 | else: 39 | print >>sys.stderr, 'usage: streamer.py server|client [host]' 40 | -------------------------------------------------------------------------------- /python2/06/sslclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 6 - sslclient.py 3 | # Using SSL to protect a socket in Python 2.6 or later 4 | 5 | import os, socket, ssl, sys 6 | from backports.ssl_match_hostname import match_hostname, CertificateError 7 | 8 | try: 9 | script_name, hostname = sys.argv 10 | except ValueError: 11 | print >>sys.stderr, 'usage: sslclient.py ' 12 | sys.exit(2) 13 | 14 | # First we connect, as usual, with a socket. 15 | 16 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 17 | sock.connect((hostname, 443)) 18 | 19 | # Next, we turn the socket over to the SSL library! 20 | 21 | ca_certs_path = os.path.join(os.path.dirname(script_name), 'certfiles.crt') 22 | sslsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv3, 23 | cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_certs_path) 24 | 25 | # Does the certificate that the server proffered *really* match the 26 | # hostname to which we are trying to connect? We need to check. 27 | 28 | try: 29 | match_hostname(sslsock.getpeercert(), hostname) 30 | except CertificateError, ce: 31 | print 'Certificate error:', str(ce) 32 | sys.exit(1) 33 | 34 | # From here on, our `sslsock` works like a normal socket. We can, for 35 | # example, make an impromptu HTTP call. 36 | 37 | sslsock.sendall('GET / HTTP/1.0\r\n\r\n') 38 | result = sslsock.makefile().read() # quick way to read until EOF 39 | sslsock.close() 40 | print 'The document https://%s/ is %d bytes long' % (hostname, len(result)) 41 | -------------------------------------------------------------------------------- /python2/07/Bench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for SERVER in server_*.py 4 | do 5 | echo '===========' $SERVER '===========' 6 | python $SERVER '' & 7 | ssh kenaniah <<'EOF' 8 | cd ~/apress 9 | source v/bin/activate 10 | cd fopnp/source/07 11 | LAUNCELOT_SERVER=192.168.5.130 fl-run-bench launcelot_tests.py TestLauncelot.test_dialog > OUT 2>&1 12 | EOF 13 | kill %1 14 | wait %1 2>/dev/null 15 | kill $(lsof | grep 'TCP.*1060' | awk '{print$2}') 16 | scp kenaniah:apress/fopnp/source/07/bench.xml ~/apress/bench 17 | (cd ~/apress/bench; fl-build-report --html bench.xml; rm -rf $SERVER; mv test_* $SERVER) 18 | done 19 | -------------------------------------------------------------------------------- /python2/07/Test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for SERVER in server_*.py 4 | do 5 | echo '===========' $SERVER '===========' 6 | python $SERVER localhost & 7 | sleep 1 8 | python client.py localhost 1060 9 | kill %1 10 | wait %1 2>/dev/null || true 11 | kill $(lsof | grep 'TCP.*1060' | awk '{print$2}') 12 | done 13 | -------------------------------------------------------------------------------- /python2/07/TestLancelot.conf: -------------------------------------------------------------------------------- 1 | # TestLauncelot.conf 2 | [main] 3 | title=Load Test For Chapter 7 4 | description=From the Foundations of Python Network Programming 5 | url=http://localhost:1060/ 6 | 7 | [ftest] 8 | log_path = ftest.log 9 | result_path = ftest.xml 10 | sleep_time_min = 0 11 | sleep_time_max = 0 12 | 13 | [bench] 14 | log_to = file 15 | log_path = bench.log 16 | result_path = bench.xml 17 | cycles = 1:2:3:5:7:10:13:16:20 18 | duration = 8 19 | startup_delay = 0.1 20 | sleep_time = 0.01 21 | cycle_time = 10 22 | sleep_time_min = 0 23 | sleep_time_max = 0 24 | -------------------------------------------------------------------------------- /python2/07/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - client.py 3 | # Simple Lancelot client that asks three questions then disconnects. 4 | 5 | import socket, sys, lancelot 6 | 7 | def client(hostname, port): 8 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | s.connect((hostname, port)) 10 | s.sendall(lancelot.qa[0][0]) 11 | answer1 = lancelot.recv_until(s, '.') # answers end with '.' 12 | s.sendall(lancelot.qa[1][0]) 13 | answer2 = lancelot.recv_until(s, '.') 14 | s.sendall(lancelot.qa[2][0]) 15 | answer3 = lancelot.recv_until(s, '.') 16 | s.close() 17 | print answer1 18 | print answer2 19 | print answer3 20 | 21 | if __name__ == '__main__': 22 | if not 2 <= len(sys.argv) <= 3: 23 | print >>sys.stderr, 'usage: client.py hostname [port]' 24 | sys.exit(2) 25 | port = int(sys.argv[2]) if len(sys.argv) > 2 else lancelot.PORT 26 | client(sys.argv[1], port) 27 | -------------------------------------------------------------------------------- /python2/07/lancelot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - lancelot.py 3 | # Constants and routines for supporting a certain network conversation. 4 | 5 | import socket, sys 6 | 7 | PORT = 1060 8 | qa = (('What is your name?', 'My name is Sir Lancelot of Camelot.'), 9 | ('What is your quest?', 'To seek the Holy Grail.'), 10 | ('What is your favorite color?', 'Blue.')) 11 | qadict = dict(qa) 12 | 13 | def recv_until(sock, suffix): 14 | message = '' 15 | while not message.endswith(suffix): 16 | data = sock.recv(4096) 17 | if not data: 18 | raise EOFError('socket closed before we saw %r' % suffix) 19 | message += data 20 | return message 21 | 22 | def setup(): 23 | if len(sys.argv) != 2: 24 | print >>sys.stderr, 'usage: %s interface' % sys.argv[0] 25 | exit(2) 26 | interface = sys.argv[1] 27 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 28 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 29 | sock.bind((interface, PORT)) 30 | sock.listen(128) 31 | print 'Ready and listening at %r port %d' % (interface, PORT) 32 | return sock 33 | -------------------------------------------------------------------------------- /python2/07/lancelot_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - lancelot_tests.py 3 | # Test suite that can be run against the Lancelot servers. 4 | 5 | from funkload.FunkLoadTestCase import FunkLoadTestCase 6 | import socket, os, unittest, lancelot 7 | 8 | SERVER_HOST = os.environ.get('LAUNCELOT_SERVER', 'localhost') 9 | 10 | class TestLancelot(FunkLoadTestCase): 11 | def test_dialog(self): 12 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 | sock.connect((SERVER_HOST, lancelot.PORT)) 14 | for i in range(10): 15 | question, answer = lancelot.qa[i % len(launcelot.qa)] 16 | sock.sendall(question) 17 | reply = lancelot.recv_until(sock, '.') 18 | self.assertEqual(reply, answer) 19 | sock.close() 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /python2/07/my_trace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - my_trace.py 3 | # Command-line tool for tracing a single function in a program. 4 | 5 | import linecache, sys, time 6 | 7 | def make_tracer(funcname): 8 | def mytrace(frame, event, arg): 9 | if frame.f_code.co_name == funcname: 10 | if event == 'line': 11 | _events.append((time.time(), frame.f_code.co_filename, 12 | frame.f_lineno)) 13 | return mytrace 14 | return mytrace 15 | 16 | if __name__ == '__main__': 17 | _events = [] 18 | if len(sys.argv) < 3: 19 | print >>sys.stderr, 'usage: my_trace.py funcname other_script.py ...' 20 | sys.exit(2) 21 | sys.settrace(make_tracer(sys.argv[1])) 22 | del sys.argv[0:2] # show the script only its own name and arguments 23 | try: 24 | execfile(sys.argv[0]) 25 | finally: 26 | for t, filename, lineno in _events: 27 | s = linecache.getline(filename, lineno) 28 | sys.stdout.write('%9.6f %s' % (t % 60.0, s)) 29 | -------------------------------------------------------------------------------- /python2/07/server_SocketServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_SocketServer.py 3 | # Answering Lancelot requests with a SocketServer. 4 | 5 | from SocketServer import ThreadingMixIn, TCPServer, BaseRequestHandler 6 | import lancelot, server_simple, socket 7 | 8 | class MyHandler(BaseRequestHandler): 9 | def handle(self): 10 | server_simple.handle_client(self.request) 11 | 12 | class MyServer(ThreadingMixIn, TCPServer): 13 | allow_reuse_address = 1 14 | # address_family = socket.AF_INET6 # if you need IPv6 15 | 16 | server = MyServer(('', lancelot.PORT), MyHandler) 17 | server.serve_forever() 18 | -------------------------------------------------------------------------------- /python2/07/server_async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_async.py 3 | # Using the ancient "asyncore" framework to write a server. 4 | 5 | import asyncore, asynchat, lancelot 6 | 7 | class LancelotRequestHandler(asynchat.async_chat): 8 | 9 | def __init__(self, sock): 10 | asynchat.async_chat.__init__(self, sock) 11 | self.set_terminator('?') 12 | self.data = '' 13 | 14 | def collect_incoming_data(self, more_data): 15 | self.data += more_data 16 | 17 | def found_terminator(self): 18 | answer = dict(lancelot.qa)[self.data + '?'] 19 | self.push(answer) 20 | self.initiate_send() 21 | self.data = '' 22 | 23 | class LancelotServer(asyncore.dispatcher): 24 | def handle_accept(self): 25 | sock, address = self.accept() 26 | LancelotRequestHandler(sock) 27 | 28 | sock = lancelot.setup() 29 | ls = LancelotServer(sock) 30 | ls.accepting = True # since we already called listen() 31 | asyncore.loop() 32 | -------------------------------------------------------------------------------- /python2/07/server_multi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_multi.py 3 | # Using multiple threads or processes to serve several clients in parallel. 4 | 5 | import sys, time, lancelot 6 | from multiprocessing import Process 7 | from server_simple import server_loop 8 | from threading import Thread 9 | 10 | WORKER_CLASSES = {'thread': Thread, 'process': Process} 11 | WORKER_MAX = 10 12 | 13 | def start_worker(Worker, listen_sock): 14 | worker = Worker(target=server_loop, args=(listen_sock,)) 15 | worker.daemon = True # exit when the main process does 16 | worker.start() 17 | return worker 18 | 19 | if __name__ == '__main__': 20 | if len(sys.argv) != 3 or sys.argv[2] not in WORKER_CLASSES: 21 | print >>sys.stderr, 'usage: server_multi.py interface thread|process' 22 | sys.exit(2) 23 | Worker = WORKER_CLASSES[sys.argv.pop()] # setup() wants len(argv)==2 24 | 25 | # Every worker will accept() forever on the same listening socket. 26 | 27 | listen_sock = lancelot.setup() 28 | workers = [] 29 | for i in range(WORKER_MAX): 30 | workers.append(start_worker(Worker, listen_sock)) 31 | 32 | # Check every two seconds for dead workers, and replace them. 33 | 34 | while True: 35 | time.sleep(2) 36 | for worker in workers: 37 | if not worker.is_alive(): 38 | print worker.name, "died; starting replacement worker" 39 | workers.remove(worker) 40 | workers.append(start_worker(Worker, listen_sock)) 41 | -------------------------------------------------------------------------------- /python2/07/server_poll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_poll.py 3 | # An event-driven approach to serving several clients with poll(). 4 | 5 | import lancelot 6 | import select 7 | 8 | listen_sock = lancelot.setup() 9 | sockets = { listen_sock.fileno(): listen_sock } 10 | requests = {} 11 | responses = {} 12 | 13 | poll = select.poll() 14 | poll.register(listen_sock, select.POLLIN) 15 | 16 | while True: 17 | for fd, event in poll.poll(): 18 | sock = sockets[fd] 19 | 20 | # Removed closed sockets from our list. 21 | if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): 22 | poll.unregister(fd) 23 | del sockets[fd] 24 | requests.pop(sock, None) 25 | responses.pop(sock, None) 26 | 27 | # Accept connections from new sockets. 28 | elif sock is listen_sock: 29 | newsock, sockname = sock.accept() 30 | newsock.setblocking(False) 31 | fd = newsock.fileno() 32 | sockets[fd] = newsock 33 | poll.register(fd, select.POLLIN) 34 | requests[newsock] = '' 35 | 36 | # Collect incoming data until it forms a question. 37 | elif event & select.POLLIN: 38 | data = sock.recv(4096) 39 | if not data: # end-of-file 40 | sock.close() # makes POLLNVAL happen next time 41 | continue 42 | requests[sock] += data 43 | if '?' in requests[sock]: 44 | question = requests.pop(sock) 45 | answer = dict(lancelot.qa)[question] 46 | poll.modify(sock, select.POLLOUT) 47 | responses[sock] = answer 48 | 49 | # Send out pieces of each reply until they are all sent. 50 | elif event & select.POLLOUT: 51 | response = responses.pop(sock) 52 | n = sock.send(response) 53 | if n < len(response): 54 | responses[sock] = response[n:] 55 | else: 56 | poll.modify(sock, select.POLLIN) 57 | requests[sock] = '' 58 | -------------------------------------------------------------------------------- /python2/07/server_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_simple.py 3 | # Simple server that only serves one client at a time; others have to wait. 4 | 5 | import lancelot 6 | 7 | def handle_client(client_sock): 8 | try: 9 | while True: 10 | question = lancelot.recv_until(client_sock, '?') 11 | answer = lancelot.qadict[question] 12 | client_sock.sendall(answer) 13 | except EOFError: 14 | client_sock.close() 15 | 16 | def server_loop(listen_sock): 17 | while True: 18 | client_sock, sockname = listen_sock.accept() 19 | handle_client(client_sock) 20 | 21 | if __name__ == '__main__': 22 | listen_sock = lancelot.setup() 23 | server_loop(listen_sock) 24 | -------------------------------------------------------------------------------- /python2/07/server_twisted.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_twisted.py 3 | # Using Twisted to serve Lancelot users. 4 | 5 | from twisted.internet.protocol import Protocol, ServerFactory 6 | from twisted.internet import reactor 7 | import lancelot 8 | 9 | class Lancelot(Protocol): 10 | def connectionMade(self): 11 | self.question = '' 12 | 13 | def dataReceived(self, data): 14 | self.question += data 15 | if self.question.endswith('?'): 16 | self.transport.write(dict(lancelot.qa)[self.question]) 17 | self.question = '' 18 | 19 | factory = ServerFactory() 20 | factory.protocol = Lancelot 21 | reactor.listenTCP(1060, factory) 22 | reactor.run() 23 | -------------------------------------------------------------------------------- /python2/08/hashing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 8 - hashing.py 3 | # Hashes are a great way to divide work. 4 | 5 | import hashlib 6 | 7 | def alpha_shard(word): 8 | """Do a poor job of assigning data to servers by using first letters.""" 9 | if word[0] in 'abcdef': 10 | return 'server0' 11 | elif word[0] in 'ghijklm': 12 | return 'server1' 13 | elif word[0] in 'nopqrs': 14 | return 'server2' 15 | else: 16 | return 'server3' 17 | 18 | def hash_shard(word): 19 | """Do a great job of assigning data to servers using a hash value.""" 20 | return 'server%d' % (hash(word) % 4) 21 | 22 | def md5_shard(word): 23 | """Do a great job of assigning data to servers using a hash value.""" 24 | # digest() is a byte string, so we ord() its last character 25 | return 'server%d' % (ord(hashlib.md5(word).digest()[-1]) % 4) 26 | 27 | words = open('/usr/share/dict/words').read().split() 28 | 29 | for function in alpha_shard, hash_shard, md5_shard: 30 | d = {'server0': 0, 'server1': 0, 'server2': 0, 'server3': 0} 31 | for word in words: 32 | d[function(word.lower())] += 1 33 | print function.__name__[:-6], d 34 | -------------------------------------------------------------------------------- /python2/08/queuecrazy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 8 - queuecrazy.py 3 | # Small application that uses several different message queues 4 | 5 | import random, threading, time, zmq 6 | zcontext = zmq.Context() 7 | 8 | def fountain(url): 9 | """Produces a steady stream of words.""" 10 | zsock = zcontext.socket(zmq.PUSH) 11 | zsock.bind(url) 12 | words = [ w for w in dir(__builtins__) if w.islower() ] 13 | while True: 14 | zsock.send(random.choice(words)) 15 | time.sleep(0.4) 16 | 17 | def responder(url, function): 18 | """Performs a string operation on each word received.""" 19 | zsock = zcontext.socket(zmq.REP) 20 | zsock.bind(url) 21 | while True: 22 | word = zsock.recv() 23 | zsock.send(function(word)) # send the modified word back 24 | 25 | def processor(n, fountain_url, responder_urls): 26 | """Read words as they are produced; get them processed; print them.""" 27 | zpullsock = zcontext.socket(zmq.PULL) 28 | zpullsock.connect(fountain_url) 29 | 30 | zreqsock = zcontext.socket(zmq.REQ) 31 | for url in responder_urls: 32 | zreqsock.connect(url) 33 | 34 | while True: 35 | word = zpullsock.recv() 36 | zreqsock.send(word) 37 | print n, zreqsock.recv() 38 | 39 | def start_thread(function, *args): 40 | thread = threading.Thread(target=function, args=args) 41 | thread.daemon = True # so you can easily Control-C the whole program 42 | thread.start() 43 | 44 | start_thread(fountain, 'tcp://127.0.0.1:6700') 45 | start_thread(responder, 'tcp://127.0.0.1:6701', str.upper) 46 | start_thread(responder, 'tcp://127.0.0.1:6702', str.lower) 47 | for n in range(3): 48 | start_thread(processor, n + 1, 'tcp://127.0.0.1:6700', 49 | ['tcp://127.0.0.1:6701', 'tcp://127.0.0.1:6702']) 50 | time.sleep(30) 51 | -------------------------------------------------------------------------------- /python2/08/squares.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 8 - squares.py 3 | # Using memcached to cache expensive results. 4 | 5 | import memcache, random, time, timeit 6 | mc = memcache.Client(['127.0.0.1:11211']) 7 | 8 | def compute_square(n): 9 | value = mc.get('sq:%d' % n) 10 | if value is None: 11 | time.sleep(0.001) # pretend that computing a square is expensive 12 | value = n * n 13 | mc.set('sq:%d' % n, value) 14 | return value 15 | 16 | def make_request(): 17 | compute_square(random.randint(0, 5000)) 18 | 19 | print 'Ten successive runs:', 20 | for i in range(1, 11): 21 | print '%.2fs' % timeit.timeit(make_request, number=2000), 22 | print 23 | -------------------------------------------------------------------------------- /python2/09/get_rfc2616.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 9 - verbose_handler.py 3 | # Example use of the verbose HTTP request handler. 4 | 5 | import urllib, urllib2 6 | from verbose_http import VerboseHTTPHandler 7 | opener = urllib2.build_opener(VerboseHTTPHandler) 8 | opener.open('http://www.ietf.org/rfc/rfc2616.txt') 9 | -------------------------------------------------------------------------------- /python2/09/verbose_http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 9 - verbose_http.py 3 | # HTTP request handler for urllib2 that prints requests and responses. 4 | 5 | import StringIO, httplib, urllib2 6 | 7 | class VerboseHTTPResponse(httplib.HTTPResponse): 8 | def _read_status(self): 9 | s = self.fp.read() 10 | print '-' * 20, 'Response', '-' * 20 11 | print s.split('\r\n\r\n')[0] 12 | self.fp = StringIO.StringIO(s) 13 | return httplib.HTTPResponse._read_status(self) 14 | 15 | class VerboseHTTPConnection(httplib.HTTPConnection): 16 | response_class = VerboseHTTPResponse 17 | def send(self, s): 18 | print '-' * 50 19 | print s.strip() 20 | httplib.HTTPConnection.send(self, s) 21 | 22 | class VerboseHTTPHandler(urllib2.HTTPHandler): 23 | def http_open(self, req): 24 | return self.do_open(VerboseHTTPConnection, req) 25 | -------------------------------------------------------------------------------- /python2/10/excerpt.html: -------------------------------------------------------------------------------- 1 | 2 | 7-Day Forecast for Latitude 33.45°N and Longitude 112.07°W (Elev. 1132 ft) 3 | ... 4 |
5 | 6 | 10 | 11 | 12 |
7 | Phoenix, Phoenix Sky Harbor International Airport
8 | Last Update on 29 Oct 7:51 MST

9 |
13 | 14 | 15 | 19 |
16 | 17 | A Few Clouds
18 |
71°F
(22°C)
20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
Humidity:30 %
Wind Speed:SE 5 MPH
26 |
Barometer:30.05 in (1015.90 mb)
Dewpoint:38°F (3°C)
Visibility:10.00 Miles
More Local Wx: 3 Day History:
40 | ... 41 | -------------------------------------------------------------------------------- /python2/10/fetch_mechanize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 10 - fetch_mechanize.py 3 | # Submitting a form and retrieving a page with mechanize 4 | 5 | import mechanize 6 | br = mechanize.Browser() 7 | br.open('http://www.weather.gov/') 8 | br.select_form(predicate=lambda(form): 'zipcity' in form.action) 9 | br['inputstring'] = 'Phoenix, AZ' 10 | response = br.submit() 11 | content = response.read() 12 | open('phoenix.html', 'w').write(content) 13 | -------------------------------------------------------------------------------- /python2/10/fetch_urllib2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 10 - fetch_urllib2.py 3 | # Submitting a form and retrieving a page with urllib2 4 | 5 | import urllib, urllib2 6 | data = urllib.urlencode({'inputstring': 'Phoenix, AZ'}) 7 | info = urllib2.urlopen('http://forecast.weather.gov/zipcity.php', data) 8 | content = info.read() 9 | open('phoenix.html', 'w').write(content) 10 | -------------------------------------------------------------------------------- /python2/10/weather.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 10 - weather.py 3 | # Fetch the weather forecast from the National Weather Service. 4 | 5 | import sys, urllib, urllib2 6 | import lxml.etree 7 | from lxml.cssselect import CSSSelector 8 | from BeautifulSoup import BeautifulSoup 9 | 10 | if len(sys.argv) < 2: 11 | print >>sys.stderr, 'usage: weather.py CITY, STATE' 12 | exit(2) 13 | 14 | data = urllib.urlencode({'inputstring': ' '.join(sys.argv[1:])}) 15 | info = urllib2.urlopen('http://forecast.weather.gov/zipcity.php', data) 16 | content = info.read() 17 | 18 | # Solution #1 19 | parser = lxml.etree.HTMLParser(encoding='utf-8') 20 | tree = lxml.etree.fromstring(content, parser) 21 | big = CSSSelector('td.big')(tree)[0] 22 | if big.find('font') is not None: 23 | big = big.find('font') 24 | print 'Condition:', big.text.strip() 25 | print 'Temperature:', big.findall('br')[1].tail 26 | tr = tree.xpath('.//td[b="Humidity"]')[0].getparent() 27 | print 'Humidity:', tr.findall('td')[1].text 28 | print 29 | 30 | # Solution #2 31 | soup = BeautifulSoup(content) # doctest: +SKIP 32 | big = soup.find('td', 'big') 33 | if big.font is not None: 34 | big = big.font 35 | print 'Condition:', big.contents[0].string.strip() 36 | temp = big.contents[3].string or big.contents[4].string # can be either 37 | print 'Temperature:', temp.replace('°', ' ') 38 | tr = soup.find('b', text='Humidity').parent.parent.parent 39 | print 'Humidity:', tr('td')[1].string 40 | print 41 | -------------------------------------------------------------------------------- /python2/11/bottle_app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 11 - bottle_app.py 3 | # A simple web application built using the Bottle micro-framework. 4 | 5 | import base64, bottle 6 | bottle.debug(True) 7 | app = bottle.Bottle() 8 | 9 | @app.route('/encode') 10 | @bottle.view('bottle_template.html') 11 | def encode(): 12 | mystring = bottle.request.GET.get('mystring') 13 | if mystring is None: 14 | bottle.abort(400, 'This form requires a "mystring" parameter') 15 | return dict(mystring=mystring, myb=base64.b64encode(mystring)) 16 | 17 | @app.route('/') 18 | @bottle.view('bottle_template.html') 19 | def index(): 20 | return dict(mystring=None) 21 | 22 | bottle.run(app=app, host='localhost', port=8080) 23 | -------------------------------------------------------------------------------- /python2/11/bottle_template.html: -------------------------------------------------------------------------------- 1 | %#!/usr/bin/env python 2 | %# Foundations of Python Network Programming - Chapter 11 - bottle_template.py 3 | %# The page template that goes with bottle_app.py. 4 | %# 5 | bottle_app.py 6 | 7 | %if mystring is None: 8 | Welcome! Enter a string: 9 |
10 | %else: 11 | {{mystring}} base64 encoded is: {{myb}}
12 | Return to the home page 13 | %end 14 | 15 | -------------------------------------------------------------------------------- /python2/11/wsgi_app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 11 - wsgi_app.py 3 | # A simple web application built directly against the low-level WSGI spec. 4 | 5 | import cgi, base64 6 | from wsgiref.simple_server import make_server 7 | 8 | def page(content, *args): 9 | yield 'wsgi_app.py' 10 | yield content % args 11 | yield '' 12 | 13 | def simple_app(environ, start_response): 14 | gohome = '
Return to the home page' 15 | q = cgi.parse_qs(environ['QUERY_STRING']) 16 | 17 | if environ['PATH_INFO'] == '/': 18 | 19 | if environ['REQUEST_METHOD'] != 'GET' or environ['QUERY_STRING']: 20 | start_response('400 Bad Request', [('Content-Type', 'text/plain')]) 21 | return ['Error: the front page is not a form'] 22 | 23 | start_response('200 OK', [('Content-Type', 'text/html')]) 24 | return page('Welcome! Enter a string:
' 25 | '
') 26 | 27 | elif environ['PATH_INFO'] == '/encode': 28 | 29 | if environ['REQUEST_METHOD'] != 'GET': 30 | start_response('400 Bad Request', [('Content-Type', 'text/plain')]) 31 | return ['Error: this form does not support POST parameters'] 32 | 33 | if 'mystring' not in q or not q['mystring'][0]: 34 | start_response('400 Bad Request', [('Content-Type', 'text/plain')]) 35 | return ['Error: this form requires a "mystring" parameter'] 36 | 37 | my = q['mystring'][0] 38 | start_response('200 OK', [('Content-Type', 'text/html')]) 39 | return page('%s base64 encoded is: %s' + gohome, 40 | cgi.escape(repr(my)), cgi.escape(base64.b64encode(my))) 41 | 42 | else: 43 | start_response('404 Not Found', [('Content-Type', 'text/plain')]) 44 | return ['That URL is not valid'] 45 | 46 | print 'Listening on localhost:8000' 47 | make_server('localhost', 8000, simple_app).serve_forever() 48 | -------------------------------------------------------------------------------- /python2/12/message.txt: -------------------------------------------------------------------------------- 1 | To: recipient@example.com 2 | From: Test Sender 3 | Subject: Test Message, Chapter 12 4 | Date: Mon, 02 Aug 2010 10:05:55 -0400 5 | Message-ID: <20100802140555.11734.89229@guinness.ten22> 6 | 7 | Hello, 8 | 9 | This is a test message from Chapter 12. I hope you enjoy it! 10 | 11 | -- Anonymous 12 | -------------------------------------------------------------------------------- /python2/12/mime_decode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_decode.py 3 | # This program requires Python 2.2.2 or above 4 | 5 | import sys, email 6 | counter = 0 7 | parts = [] 8 | 9 | def printmsg(msg, level = 0): 10 | global counter 11 | l = "| " * level 12 | if msg.is_multipart(): 13 | print l + "Found multipart:" 14 | for item in msg.get_payload(): 15 | printmsg(item, level + 1) 16 | else: 17 | disp = ['%d. Decodable part' % (counter + 1)] 18 | if 'content-type' in msg: 19 | disp.append(msg['content-type']) 20 | if 'content-disposition' in msg: 21 | disp.append(msg['content-disposition']) 22 | print l + ", ".join(disp) 23 | counter += 1 24 | parts.append(msg) 25 | 26 | inputfd = open(sys.argv[1]) 27 | msg = email.message_from_file(inputfd) 28 | printmsg(msg) 29 | 30 | while 1: 31 | print "Select part number to decode or q to quit: " 32 | part = sys.stdin.readline().strip() 33 | if part == 'q': 34 | sys.exit(0) 35 | try: 36 | part = int(part) 37 | msg = parts[part - 1] 38 | except: 39 | print "Invalid selection." 40 | continue 41 | 42 | print "Select file to write to:" 43 | filename = sys.stdin.readline().strip() 44 | try: 45 | fd = open(filename, 'wb') 46 | except: 47 | print "Invalid filename." 48 | continue 49 | 50 | fd.write(msg.get_payload(decode = 1)) 51 | -------------------------------------------------------------------------------- /python2/12/mime_gen_alt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_gen_alt.py 3 | # This program requires Python 2.2.2 or above 4 | 5 | from email.mime.base import MIMEBase 6 | from email.mime.multipart import MIMEMultipart 7 | from email.mime.text import MIMEText 8 | from email import utils, encoders 9 | 10 | def alternative(data, contenttype): 11 | maintype, subtype = contenttype.split('/') 12 | if maintype == 'text': 13 | retval = MIMEText(data, _subtype=subtype) 14 | else: 15 | retval = MIMEBase(maintype, subtype) 16 | retval.set_payload(data) 17 | encoders.encode_base64(retval) 18 | return retval 19 | 20 | messagetext = """Hello, 21 | 22 | This is a *great* test message from Chapter 12. I hope you enjoy it! 23 | 24 | -- Anonymous""" 25 | messagehtml = """Hello,

26 | This is a great test message from Chapter 12. I hope you enjoy 27 | it!

28 | -- Anonymous""" 29 | 30 | 31 | msg = MIMEMultipart('alternative') 32 | msg['To'] = 'recipient@example.com' 33 | msg['From'] = 'Test Sender ' 34 | msg['Subject'] = 'Test Message, Chapter 12' 35 | msg['Date'] = utils.formatdate(localtime = 1) 36 | msg['Message-ID'] = utils.make_msgid() 37 | 38 | msg.attach(alternative(messagetext, 'text/plain')) 39 | msg.attach(alternative(messagehtml, 'text/html')) 40 | print msg.as_string() 41 | -------------------------------------------------------------------------------- /python2/12/mime_gen_basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_gen_basic.py 3 | # This program requires Python 2.5 or above 4 | 5 | from email.mime.base import MIMEBase 6 | from email.mime.multipart import MIMEMultipart 7 | from email.mime.text import MIMEText 8 | from email import utils, encoders 9 | import mimetypes, sys 10 | 11 | def attachment(filename): 12 | fd = open(filename, 'rb') 13 | mimetype, mimeencoding = mimetypes.guess_type(filename) 14 | if mimeencoding or (mimetype is None): 15 | mimetype = 'application/octet-stream' 16 | maintype, subtype = mimetype.split('/') 17 | if maintype == 'text': 18 | retval = MIMEText(fd.read(), _subtype=subtype) 19 | else: 20 | retval = MIMEBase(maintype, subtype) 21 | retval.set_payload(fd.read()) 22 | encoders.encode_base64(retval) 23 | retval.add_header('Content-Disposition', 'attachment', 24 | filename = filename) 25 | fd.close() 26 | return retval 27 | 28 | message = """Hello, 29 | 30 | This is a test message from Chapter 12. I hope you enjoy it! 31 | 32 | -- Anonymous""" 33 | 34 | msg = MIMEMultipart() 35 | msg['To'] = 'recipient@example.com' 36 | msg['From'] = 'Test Sender ' 37 | msg['Subject'] = 'Test Message, Chapter 12' 38 | msg['Date'] = utils.formatdate(localtime = 1) 39 | msg['Message-ID'] = utils.make_msgid() 40 | 41 | body = MIMEText(message, _subtype='plain') 42 | msg.attach(body) 43 | for filename in sys.argv[1:]: 44 | msg.attach(attachment(filename)) 45 | print msg.as_string() 46 | -------------------------------------------------------------------------------- /python2/12/mime_gen_both.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_gen_both.py 3 | 4 | from email.mime.text import MIMEText 5 | from email.mime.multipart import MIMEMultipart 6 | from email.mime.base import MIMEBase 7 | from email import utils, encoders 8 | import mimetypes, sys 9 | 10 | def genpart(data, contenttype): 11 | maintype, subtype = contenttype.split('/') 12 | if maintype == 'text': 13 | retval = MIMEText(data, _subtype=subtype) 14 | else: 15 | retval = MIMEBase(maintype, subtype) 16 | retval.set_payload(data) 17 | encoders.encode_base64(retval) 18 | return retval 19 | 20 | 21 | def attachment(filename): 22 | fd = open(filename, 'rb') 23 | mimetype, mimeencoding = mimetypes.guess_type(filename) 24 | if mimeencoding or (mimetype is None): 25 | mimetype = 'application/octet-stream' 26 | retval = genpart(fd.read(), mimetype) 27 | retval.add_header('Content-Disposition', 'attachment', 28 | filename = filename) 29 | fd.close() 30 | return retval 31 | 32 | messagetext = """Hello, 33 | 34 | This is a *great* test message from Chapter 12. I hope you enjoy it! 35 | 36 | -- Anonymous""" 37 | messagehtml = """Hello,

38 | This is a great test message from Chapter 12. I hope you enjoy 39 | it!

40 | -- Anonymous""" 41 | 42 | msg = MIMEMultipart() 43 | msg['To'] = 'recipient@example.com' 44 | msg['From'] = 'Test Sender ' 45 | msg['Subject'] = 'Test Message, Chapter 12' 46 | msg['Date'] = utils.formatdate(localtime = 1) 47 | msg['Message-ID'] = utils.make_msgid() 48 | 49 | body = MIMEMultipart('alternative') 50 | body.attach(genpart(messagetext, 'text/plain')) 51 | body.attach(genpart(messagehtml, 'text/html')) 52 | msg.attach(body) 53 | 54 | for filename in sys.argv[1:]: 55 | msg.attach(attachment(filename)) 56 | print msg.as_string() 57 | -------------------------------------------------------------------------------- /python2/12/mime_headers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_headers.py 3 | # This program requires Python 2.5 or above 4 | 5 | from email.mime.text import MIMEText 6 | from email.header import Header 7 | 8 | message = """Hello, 9 | 10 | This is a test message from Chapter 12. I hope you enjoy it! 11 | 12 | -- Anonymous""" 13 | 14 | msg = MIMEText(message) 15 | msg['To'] = 'recipient@example.com' 16 | fromhdr = Header() 17 | fromhdr.append(u"Michael M\xfcller") 18 | fromhdr.append('') 19 | msg['From'] = fromhdr 20 | msg['Subject'] = 'Test Message, Chapter 12' 21 | 22 | print msg.as_string() 23 | -------------------------------------------------------------------------------- /python2/12/mime_parse_headers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_parse_headers.py 3 | 4 | import sys, email, codecs 5 | from email import Header 6 | 7 | msg = email.message_from_file(sys.stdin) 8 | for header, value in msg.items(): 9 | headerparts = Header.decode_header(value) 10 | headerval = [] 11 | for part in headerparts: 12 | data, charset = part 13 | if charset is None: 14 | charset = 'ascii' 15 | dec = codecs.getdecoder(charset) 16 | enc = codecs.getencoder('iso-8859-1') 17 | data = enc(dec(data)[0])[0] 18 | headerval.append(data) 19 | print "%s: %s" % (header, " ".join(headerval)) 20 | 21 | -------------------------------------------------------------------------------- /python2/12/mime_structure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_structure.py 3 | # This program requires Python 2.2.2 or above 4 | 5 | import sys, email 6 | 7 | def printmsg(msg, level = 0): 8 | prefix = "| " * level 9 | prefix2 = prefix + "|" 10 | print prefix + "+ Message Headers:" 11 | for header, value in msg.items(): 12 | print prefix2, header + ":", value 13 | if msg.is_multipart(): 14 | for item in msg.get_payload(): 15 | printmsg(item, level + 1) 16 | 17 | msg = email.message_from_file(sys.stdin) 18 | printmsg(msg) 19 | -------------------------------------------------------------------------------- /python2/12/test.txt: -------------------------------------------------------------------------------- 1 | This is a test 2 | -------------------------------------------------------------------------------- /python2/12/test.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/misheska/foundations-of-python-network-programming/63c0eaadc902f93f51f18e54bd5abf5f046238a5/python2/12/test.txt.gz -------------------------------------------------------------------------------- /python2/12/trad_gen_newhdrs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - trad_gen_newhdrs.py 3 | # Traditional Message Generation with Date and Message-ID 4 | # This program requires Python 2.5 or above 5 | 6 | import email.utils 7 | from email.message import Message 8 | 9 | message = """Hello, 10 | 11 | This is a test message from Chapter 12. I hope you enjoy it! 12 | 13 | -- Anonymous""" 14 | 15 | msg = Message() 16 | msg['To'] = 'recipient@example.com' 17 | msg['From'] = 'Test Sender ' 18 | msg['Subject'] = 'Test Message, Chapter 12' 19 | msg['Date'] = email.utils.formatdate(localtime = 1) 20 | msg['Message-ID'] = email.utils.make_msgid() 21 | msg.set_payload(message) 22 | 23 | print msg.as_string() 24 | -------------------------------------------------------------------------------- /python2/12/trad_gen_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - trad_gen_simple.py 3 | # Traditional Message Generation, Simple 4 | # This program requires Python 2.5 or above 5 | 6 | from email.message import Message 7 | text = """Hello, 8 | 9 | This is a test message from Chapter 12. I hope you enjoy it! 10 | 11 | -- Anonymous""" 12 | 13 | msg = Message() 14 | msg['To'] = 'recipient@example.com' 15 | msg['From'] = 'Test Sender ' 16 | msg['Subject'] = 'Test Message, Chapter 12' 17 | msg.set_payload(text) 18 | 19 | print msg.as_string() 20 | -------------------------------------------------------------------------------- /python2/12/trad_parse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - trad_parse.py 3 | # Traditional Message Parsing 4 | # This program requires Python 2.5 or above 5 | 6 | import email 7 | 8 | banner = '-' * 48 9 | popular_headers = ('From', 'To', 'Subject', 'Date') 10 | msg = email.message_from_file(open('message.txt')) 11 | headers = sorted(msg.keys()) 12 | 13 | print banner 14 | for header in headers: 15 | if header not in popular_headers: 16 | print header + ':', msg[header] 17 | print banner 18 | for header in headers: 19 | if header in popular_headers: 20 | print header + ':', msg[header] 21 | 22 | print banner 23 | if msg.is_multipart(): 24 | print "This program cannot handle MIME multipart messages." 25 | else: 26 | print msg.get_payload() 27 | -------------------------------------------------------------------------------- /python2/13/debug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with debugging - Chapter 13 - debug.py 3 | 4 | import sys, smtplib, socket 5 | 6 | if len(sys.argv) < 4: 7 | print "usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0] 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the debug.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | try: 23 | s = smtplib.SMTP(server) 24 | s.set_debuglevel(1) 25 | s.sendmail(fromaddr, toaddrs, message) 26 | except (socket.gaierror, socket.error, socket.herror, 27 | smtplib.SMTPException), e: 28 | print " *** Your message may not have been sent!" 29 | print e 30 | sys.exit(1) 31 | else: 32 | print "Message successfully sent to %d recipient(s)" % len(toaddrs) 33 | -------------------------------------------------------------------------------- /python2/13/ehlo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with manual EHLO - Chapter 13 - ehlo.py 3 | 4 | import sys, smtplib, socket 5 | 6 | if len(sys.argv) < 4: 7 | print "usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0] 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the ehlo.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | try: 23 | s = smtplib.SMTP(server) 24 | code = s.ehlo()[0] 25 | uses_esmtp = (200 <= code <= 299) 26 | if not uses_esmtp: 27 | code = s.helo()[0] 28 | if not (200 <= code <= 299): 29 | print "Remote server refused HELO; code:", code 30 | sys.exit(1) 31 | 32 | if uses_esmtp and s.has_extn('size'): 33 | print "Maximum message size is", s.esmtp_features['size'] 34 | if len(message) > int(s.esmtp_features['size']): 35 | print "Message too large; aborting." 36 | sys.exit(1) 37 | 38 | s.sendmail(fromaddr, toaddrs, message) 39 | 40 | except (socket.gaierror, socket.error, socket.herror, 41 | smtplib.SMTPException), e: 42 | print " *** Your message may not have been sent!" 43 | print e 44 | sys.exit(1) 45 | else: 46 | print "Message successfully sent to %d recipient(s)" % len(toaddrs) 47 | -------------------------------------------------------------------------------- /python2/13/login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with authentication - Chapter 13 - login.py 3 | 4 | import sys, smtplib, socket 5 | from getpass import getpass 6 | 7 | if len(sys.argv) < 4: 8 | print "Syntax: %s server fromaddr toaddr [toaddr...]" % sys.argv[0] 9 | sys.exit(2) 10 | 11 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 12 | 13 | message = """To: %s 14 | From: %s 15 | Subject: Test Message from simple.py 16 | 17 | Hello, 18 | 19 | This is a test message sent to you from the login.py program 20 | in Foundations of Python Network Programming. 21 | """ % (', '.join(toaddrs), fromaddr) 22 | 23 | sys.stdout.write("Enter username: ") 24 | username = sys.stdin.readline().strip() 25 | password = getpass("Enter password: ") 26 | 27 | try: 28 | s = smtplib.SMTP(server) 29 | try: 30 | s.login(username, password) 31 | except smtplib.SMTPException, e: 32 | print "Authentication failed:", e 33 | sys.exit(1) 34 | s.sendmail(fromaddr, toaddrs, message) 35 | except (socket.gaierror, socket.error, socket.herror, 36 | smtplib.SMTPException), e: 37 | print " *** Your message may not have been sent!" 38 | print e 39 | sys.exit(1) 40 | else: 41 | print "Message successfully sent to %d recipient(s)" % len(toaddrs) 42 | -------------------------------------------------------------------------------- /python2/13/simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Basic SMTP transmission - Chapter 13 - simple.py 3 | 4 | import sys, smtplib 5 | 6 | if len(sys.argv) < 4: 7 | print "usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0] 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the simple.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | s = smtplib.SMTP(server) 23 | s.sendmail(fromaddr, toaddrs, message) 24 | 25 | print "Message successfully sent to %d recipient(s)" % len(toaddrs) 26 | -------------------------------------------------------------------------------- /python2/13/tls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with TLS - Chapter 13 - tls.py 3 | 4 | import sys, smtplib, socket 5 | 6 | if len(sys.argv) < 4: 7 | print "Syntax: %s server fromaddr toaddr [toaddr...]" % sys.argv[0] 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the tls.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | try: 23 | s = smtplib.SMTP(server) 24 | code = s.ehlo()[0] 25 | uses_esmtp = (200 <= code <= 299) 26 | if not uses_esmtp: 27 | code = s.helo()[0] 28 | if not (200 <= code <= 299): 29 | print "Remove server refused HELO; code:", code 30 | sys.exit(1) 31 | 32 | if uses_esmtp and s.has_extn('starttls'): 33 | print "Negotiating TLS...." 34 | s.starttls() 35 | code = s.ehlo()[0] 36 | if not (200 <= code <= 299): 37 | print "Couldn't EHLO after STARTTLS" 38 | sys.exit(5) 39 | print "Using TLS connection." 40 | else: 41 | print "Server does not support TLS; using normal connection." 42 | s.sendmail(fromaddr, toaddrs, message) 43 | 44 | except (socket.gaierror, socket.error, socket.herror, 45 | smtplib.SMTPException), e: 46 | print " *** Your message may not have been sent!" 47 | print e 48 | sys.exit(1) 49 | else: 50 | print "Message successfully sent to %d recipient(s)" % len(toaddrs) 51 | -------------------------------------------------------------------------------- /python2/14/download-and-delete.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # POP mailbox downloader with deletion - Chapter 14 3 | # download-and-delete.py 4 | 5 | import email, getpass, poplib, sys 6 | 7 | if len(sys.argv) != 3: 8 | print 'usage: %s hostname user' % sys.argv[0] 9 | exit(2) 10 | 11 | hostname, user = sys.argv[1:] 12 | passwd = getpass.getpass() 13 | 14 | p = poplib.POP3_SSL(hostname) 15 | try: 16 | p.user(user) 17 | p.pass_(passwd) 18 | except poplib.error_proto, e: 19 | print "Login failed:", e 20 | else: 21 | response, listings, octets = p.list() 22 | for listing in listings: 23 | number, size = listing.split() 24 | print 'Message', number, '(size is', size, 'bytes):' 25 | print 26 | response, lines, octets = p.top(number, 0) 27 | message = email.message_from_string('\n'.join(lines)) 28 | for header in 'From', 'To', 'Subject', 'Date': 29 | if header in message: 30 | print header + ':', message[header] 31 | print 32 | print 'Read this message [ny]?' 33 | answer = raw_input() 34 | if answer.lower().startswith('y'): 35 | response, lines, octets = p.retr(number) 36 | message = email.message_from_string('\n'.join(lines)) 37 | print '-' * 72 38 | for part in message.walk(): 39 | if part.get_content_type() == 'text/plain': 40 | print part.get_payload() 41 | print '-' * 72 42 | print 43 | print 'Delete this message [ny]?' 44 | answer = raw_input() 45 | if answer.lower().startswith('y'): 46 | p.dele(number) 47 | print 'Deleted.' 48 | finally: 49 | p.quit() 50 | -------------------------------------------------------------------------------- /python2/14/mailbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # POP mailbox scanning - Chapter 14 - mailbox.py 3 | 4 | import getpass, poplib, sys 5 | 6 | if len(sys.argv) != 3: 7 | print 'usage: %s hostname user' % sys.argv[0] 8 | exit(2) 9 | 10 | hostname, user = sys.argv[1:] 11 | passwd = getpass.getpass() 12 | 13 | p = poplib.POP3_SSL(hostname) 14 | try: 15 | p.user(user) 16 | p.pass_(passwd) 17 | except poplib.error_proto, e: 18 | print "Login failed:", e 19 | else: 20 | response, listings, octet_count = p.list() 21 | for listing in listings: 22 | number, size = listing.split() 23 | print "Message %s has %s bytes" % (number, size) 24 | finally: 25 | p.quit() 26 | -------------------------------------------------------------------------------- /python2/14/popconn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # POP connection and authentication - Chapter 14 - popconn.py 3 | 4 | import getpass, poplib, sys 5 | 6 | if len(sys.argv) != 3: 7 | print 'usage: %s hostname user' % sys.argv[0] 8 | exit(2) 9 | 10 | hostname, user = sys.argv[1:] 11 | passwd = getpass.getpass() 12 | 13 | p = poplib.POP3_SSL(hostname) # or "POP3" if SSL is not supported 14 | try: 15 | p.user(user) 16 | p.pass_(passwd) 17 | except poplib.error_proto, e: 18 | print "Login failed:", e 19 | else: 20 | status = p.stat() 21 | print "You have %d messages totaling %d bytes" % status 22 | finally: 23 | p.quit() 24 | -------------------------------------------------------------------------------- /python2/15/folder_info.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - folder_info.py 3 | # Opening an IMAP connection with IMAPClient and listing folder information. 4 | 5 | import getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username = sys.argv[1:] 10 | except ValueError: 11 | print 'usage: %s hostname username' % sys.argv[0] 12 | sys.exit(2) 13 | 14 | c = IMAPClient(hostname, ssl=True) 15 | try: 16 | c.login(username, getpass.getpass()) 17 | except c.Error, e: 18 | print 'Could not log in:', e 19 | sys.exit(1) 20 | else: 21 | select_dict = c.select_folder('INBOX', readonly=True) 22 | for k, v in select_dict.items(): 23 | print '%s: %r' % (k, v) 24 | c.logout() 25 | -------------------------------------------------------------------------------- /python2/15/mailbox_summary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - mailbox_summary.py 3 | # Opening an IMAP connection with IMAPClient and retrieving mailbox messages. 4 | 5 | import email, getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username, foldername = sys.argv[1:] 10 | except ValueError: 11 | print 'usage: %s hostname username folder' % sys.argv[0] 12 | sys.exit(2) 13 | 14 | c = IMAPClient(hostname, ssl=True) 15 | try: 16 | c.login(username, getpass.getpass()) 17 | except c.Error, e: 18 | print 'Could not log in:', e 19 | sys.exit(1) 20 | 21 | c.select_folder(foldername, readonly=True) 22 | msgdict = c.fetch('1:*', ['BODY.PEEK[]']) 23 | for message_id, message in msgdict.items(): 24 | e = email.message_from_string(message['BODY[]']) 25 | print message_id, e['From'] 26 | payload = e.get_payload() 27 | if isinstance(payload, list): 28 | part_content_types = [ part.get_content_type() for part in payload ] 29 | print ' Parts:', ' '.join(part_content_types) 30 | else: 31 | print ' ', ' '.join(payload[:60].split()), '...' 32 | 33 | c.logout() 34 | -------------------------------------------------------------------------------- /python2/15/open_imap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - open_imap.py 3 | # Opening an IMAP connection with the powerful IMAPClient 4 | 5 | import getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username = sys.argv[1:] 10 | except ValueError: 11 | print 'usage: %s hostname username' % sys.argv[0] 12 | sys.exit(2) 13 | 14 | c = IMAPClient(hostname, ssl=True) 15 | try: 16 | c.login(username, getpass.getpass()) 17 | except c.Error, e: 18 | print 'Could not log in:', e 19 | sys.exit(1) 20 | 21 | print 'Capabilities:', c.capabilities() 22 | print 'Listing mailboxes:' 23 | data = c.list_folders() 24 | for flags, delimiter, folder_name in data: 25 | print ' %-30s%s %s' % (' '.join(flags), delimiter, folder_name) 26 | c.logout() 27 | -------------------------------------------------------------------------------- /python2/15/open_imap.txt: -------------------------------------------------------------------------------- 1 | Capabilities: ('IMAP4REV1', 'UNSELECT', 'IDLE', 'NAMESPACE', 'QUOTA', 'XLIST', 'CHILDREN', 'XYZZY', 'SASL-IR', 'AUTH=XOAUTH') 2 | Listing mailboxes: 3 | \HasNoChildren / INBOX 4 | \HasNoChildren / Personal 5 | \HasNoChildren / Receipts 6 | \HasNoChildren / Travel 7 | \HasNoChildren / Work 8 | \Noselect \HasChildren / [Gmail] 9 | \HasChildren \HasNoChildren / [Gmail]/All Mail 10 | \HasNoChildren / [Gmail]/Drafts 11 | \HasChildren \HasNoChildren / [Gmail]/Sent Mail 12 | \HasNoChildren / [Gmail]/Spam 13 | \HasNoChildren / [Gmail]/Starred 14 | \HasChildren \HasNoChildren / [Gmail]/Trash 15 | -------------------------------------------------------------------------------- /python2/15/open_imaplib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - open_imaplib.py 3 | # Opening an IMAP connection with the pitiful Python Standard Library 4 | 5 | import getpass, imaplib, sys 6 | 7 | try: 8 | hostname, username = sys.argv[1:] 9 | except ValueError: 10 | print 'usage: %s hostname username' % sys.argv[0] 11 | sys.exit(2) 12 | 13 | m = imaplib.IMAP4_SSL(hostname) 14 | m.login(username, getpass.getpass()) 15 | print 'Capabilities:', m.capabilities 16 | print 'Listing mailboxes ' 17 | status, data = m.list() 18 | print 'Status:', repr(status) 19 | print 'Data:' 20 | for datum in data: 21 | print repr(datum) 22 | m.logout() 23 | -------------------------------------------------------------------------------- /python2/15/open_imaplib.txt: -------------------------------------------------------------------------------- 1 | Capabilities: ('IMAP4REV1', 'UNSELECT', 'IDLE', 'NAMESPACE', 'QUOTA', 2 | 'XLIST', 'CHILDREN', 'XYZZY', 'SASL-IR', 'AUTH=XOAUTH') 3 | Listing mailboxes 4 | Status: 'OK' 5 | Data: 6 | '(\\HasNoChildren) "/" "INBOX"' 7 | '(\\HasNoChildren) "/" "Personal"' 8 | '(\\HasNoChildren) "/" "Receipts"' 9 | '(\\HasNoChildren) "/" "Travel"' 10 | '(\\HasNoChildren) "/" "Work"' 11 | '(\\Noselect \\HasChildren) "/" "[Gmail]"' 12 | '(\\HasChildren \\HasNoChildren) "/" "[Gmail]/All Mail"' 13 | '(\\HasNoChildren) "/" "[Gmail]/Drafts"' 14 | '(\\HasChildren \\HasNoChildren) "/" "[Gmail]/Sent Mail"' 15 | '(\\HasNoChildren) "/" "[Gmail]/Spam"' 16 | '(\\HasNoChildren) "/" "[Gmail]/Starred"' 17 | '(\\HasChildren \\HasNoChildren) "/" "[Gmail]/Trash"' 18 | -------------------------------------------------------------------------------- /python2/15/simple_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - simple_client.py 3 | # Letting a user browse folders, messages, and message parts. 4 | 5 | import getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username = sys.argv[1:] 10 | except ValueError: 11 | print 'usage: %s hostname username' % sys.argv[0] 12 | sys.exit(2) 13 | 14 | banner = '-' * 72 15 | 16 | c = IMAPClient(hostname, ssl=True) 17 | try: 18 | c.login(username, getpass.getpass()) 19 | except c.Error, e: 20 | print 'Could not log in:', e 21 | sys.exit(1) 22 | 23 | def display_structure(structure, parentparts=[]): 24 | """Attractively display a given message structure.""" 25 | 26 | # The whole body of the message is named 'TEXT'. 27 | 28 | if parentparts: 29 | name = '.'.join(parentparts) 30 | else: 31 | print 'HEADER' 32 | name = 'TEXT' 33 | 34 | # Print this part's designation and its MIME type. 35 | 36 | is_multipart = isinstance(structure[0], list) 37 | if is_multipart: 38 | parttype = 'multipart/%s' % structure[1].lower() 39 | else: 40 | parttype = ('%s/%s' % structure[:2]).lower() 41 | print '%-9s' % name, parttype, 42 | 43 | # For a multipart part, print all of its subordinate parts; for 44 | # other parts, print their disposition (if available). 45 | 46 | if is_multipart: 47 | print 48 | subparts = structure[0] 49 | for i in range(len(subparts)): 50 | display_structure(subparts[i], parentparts + [ str(i + 1) ]) 51 | else: 52 | if structure[6]: 53 | print 'size=%s' % structure[6], 54 | if structure[8]: 55 | disposition, namevalues = structure[8] 56 | print disposition, 57 | for i in range(0, len(namevalues), 2): 58 | print '%s=%r' % namevalues[i:i+2] 59 | print 60 | 61 | def explore_message(c, uid): 62 | """Let the user view various parts of a given message.""" 63 | 64 | msgdict = c.fetch(uid, ['BODYSTRUCTURE', 'FLAGS']) 65 | 66 | while True: 67 | print 68 | print 'Flags:', 69 | flaglist = msgdict[uid]['FLAGS'] 70 | if flaglist: 71 | print ' '.join(flaglist) 72 | else: 73 | print 'none' 74 | display_structure(msgdict[uid]['BODYSTRUCTURE']) 75 | print 76 | reply = raw_input('Message %s - type a part name, or "q" to quit: ' 77 | % uid).strip() 78 | print 79 | if reply.lower().startswith('q'): 80 | break 81 | key = 'BODY[%s]' % reply 82 | try: 83 | msgdict2 = c.fetch(uid, [key]) 84 | except c._imap.error: 85 | print 'Error - cannot fetch section %r' % reply 86 | else: 87 | content = msgdict2[uid][key] 88 | if content: 89 | print banner 90 | print content.strip() 91 | print banner 92 | else: 93 | print '(No such section)' 94 | 95 | def explore_folder(c, name): 96 | """List the messages in folder `name` and let the user choose one.""" 97 | 98 | while True: 99 | c.select_folder(name, readonly=True) 100 | msgdict = c.fetch('1:*', ['BODY.PEEK[HEADER.FIELDS (FROM SUBJECT)]', 101 | 'FLAGS', 'INTERNALDATE', 'RFC822.SIZE']) 102 | print 103 | for uid in sorted(msgdict): 104 | items = msgdict[uid] 105 | print '%6d %20s %6d bytes %s' % ( 106 | uid, items['INTERNALDATE'], items['RFC822.SIZE'], 107 | ' '.join(items['FLAGS'])) 108 | for i in items['BODY[HEADER.FIELDS (FROM SUBJECT)]'].splitlines(): 109 | print ' ' * 6, i.strip() 110 | 111 | reply = raw_input('Folder %s - type a message UID, or "q" to quit: ' 112 | % name).strip() 113 | if reply.lower().startswith('q'): 114 | break 115 | try: 116 | reply = int(reply) 117 | except ValueError: 118 | print 'Please type an integer or "q" to quit' 119 | else: 120 | if reply in msgdict: 121 | explore_message(c, reply) 122 | 123 | c.close_folder() 124 | 125 | def explore_account(c): 126 | """Display the folders in this IMAP account and let the user choose one.""" 127 | 128 | while True: 129 | 130 | print 131 | folderflags = {} 132 | data = c.list_folders() 133 | for flags, delimiter, name in data: 134 | folderflags[name] = flags 135 | for name in sorted(folderflags.keys()): 136 | print '%-30s %s' % (name, ' '.join(folderflags[name])) 137 | print 138 | 139 | reply = raw_input('Type a folder name, or "q" to quit: ').strip() 140 | if reply.lower().startswith('q'): 141 | break 142 | if reply in folderflags: 143 | explore_folder(c, reply) 144 | else: 145 | print 'Error: no folder named', repr(reply) 146 | 147 | if __name__ == '__main__': 148 | explore_account(c) 149 | -------------------------------------------------------------------------------- /python2/16/fabfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - fabfile.py 3 | # A sample Fabric script 4 | 5 | # Even though this chapter will not cover Fabric, you might want to try 6 | # using Fabric to automate your SSH commands instead of re-inventing the 7 | # wheel. Here is a script that checks for Python on remote machines. 8 | # Fabric finds this "fabfile.py" automatically if you are in the same 9 | # directory. Try running both verbosely, and with most messages off: 10 | # 11 | # $ fab versions:host=server.example.com 12 | # $ fab --hide=everything versions:host=server.example.com 13 | 14 | from fabric.api import * 15 | 16 | def versions(): 17 | with cd('/usr/bin'): 18 | with settings(hide('warnings'), warn_only=True): 19 | for version in '2.4', '2.5', '2.6', '2.7', '3.0', '3.1': 20 | result = run('python%s -c "None"' % version) 21 | if not result.failed: 22 | print "Host", env.host, "has Python", version 23 | -------------------------------------------------------------------------------- /python2/16/sftp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - sftp.py 3 | # Fetching files with SFTP 4 | 5 | import functools 6 | import paramiko 7 | 8 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 9 | def missing_host_key(self, client, hostname, key): 10 | return 11 | 12 | client = paramiko.SSHClient() 13 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 14 | client.connect('127.0.0.1', username='test') # password='') 15 | 16 | def my_callback(filename, bytes_so_far, bytes_total): 17 | print 'Transfer of %r is at %d/%d bytes (%.1f%%)' % ( 18 | filename, bytes_so_far, bytes_total, 100. * bytes_so_far / bytes_total) 19 | 20 | sftp = client.open_sftp() 21 | sftp.chdir('/var/log') 22 | for filename in sorted(sftp.listdir()): 23 | if filename.startswith('messages.'): 24 | callback_for_filename = functools.partial(my_callback, filename) 25 | sftp.get(filename, filename, callback=callback_for_filename) 26 | 27 | client.close() 28 | -------------------------------------------------------------------------------- /python2/16/shell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - shell.py 3 | # A simple shell, so you can try running commands in the absence of 4 | # any special characters (except for whitespace, used for splitting). 5 | 6 | import subprocess 7 | 8 | while True: 9 | args = raw_input('] ').split() 10 | if not args: 11 | pass 12 | elif args == ['exit']: 13 | break 14 | elif args[0] == 'show': 15 | print "Arguments:", args[1:] 16 | else: 17 | subprocess.call(args) 18 | -------------------------------------------------------------------------------- /python2/16/ssh_commands.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - ssh_commands.py 3 | # Running separate commands instead of using a shell 4 | 5 | import paramiko 6 | 7 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 8 | def missing_host_key(self, client, hostname, key): 9 | return 10 | 11 | client = paramiko.SSHClient() 12 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 13 | client.connect('127.0.0.1', username='test') # password='') 14 | 15 | for command in 'echo "Hello, world!"', 'uname', 'uptime': 16 | stdin, stdout, stderr = client.exec_command(command) 17 | stdin.close() 18 | print repr(stdout.read()) 19 | stdout.close() 20 | stderr.close() 21 | 22 | client.close() 23 | -------------------------------------------------------------------------------- /python2/16/ssh_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - ssh_simple.py 3 | # Using SSH like Telnet: connecting and running two commands 4 | 5 | import paramiko 6 | 7 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 8 | def missing_host_key(self, client, hostname, key): 9 | return 10 | 11 | client = paramiko.SSHClient() 12 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 13 | client.connect('127.0.0.1', username='test') # password='') 14 | 15 | channel = client.invoke_shell() 16 | stdin = channel.makefile('wb') 17 | stdout = channel.makefile('rb') 18 | 19 | stdin.write('echo Hello, world\rexit\r') 20 | print stdout.read() 21 | 22 | client.close() 23 | -------------------------------------------------------------------------------- /python2/16/ssh_simple.txt: -------------------------------------------------------------------------------- 1 | Linux guinness 2.6.32-24-generic #42-Ubuntu SMP Fri Aug 20 14:24:04 UTC 2 | 2010 i686 GNU/Linux 3 | Ubuntu 10.04.1 LTS 4 | 5 | Welcome to Ubuntu! 6 | * Documentation: https://help.ubuntu.com/ 7 | 8 | Last login: Mon Sep 6 01:02:46 2010 from localhost 9 | echo Hello, world 10 | exit 11 | test@guinness:~$ echo Hello, world 12 | Hello, world 13 | test@guinness:~$ exit 14 | logout 15 | -------------------------------------------------------------------------------- /python2/16/ssh_threads.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - ssh_threads.py 3 | # Running two remote commands simultaneously in different channels 4 | 5 | import threading 6 | import paramiko 7 | 8 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 9 | def missing_host_key(self, client, hostname, key): 10 | return 11 | 12 | client = paramiko.SSHClient() 13 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 14 | client.connect('127.0.0.1', username='test') # password='') 15 | 16 | def read_until_EOF(fileobj): 17 | s = fileobj.readline() 18 | while s: 19 | print s.strip() 20 | s = fileobj.readline() 21 | 22 | out1 = client.exec_command('echo One;sleep 2;echo Two;sleep 1;echo Three')[1] 23 | out2 = client.exec_command('echo A;sleep 1;echo B;sleep 2;echo C')[1] 24 | thread1 = threading.Thread(target=read_until_EOF, args=(out1,)) 25 | thread2 = threading.Thread(target=read_until_EOF, args=(out2,)) 26 | thread1.start() 27 | thread2.start() 28 | thread1.join() 29 | thread2.join() 30 | 31 | client.close() 32 | -------------------------------------------------------------------------------- /python2/16/telnet_codes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - telnet_codes.py 3 | # How your code might look if you intercept Telnet options yourself 4 | 5 | from telnetlib import Telnet, IAC, DO, DONT, WILL, WONT, SB, SE, TTYPE 6 | 7 | def process_option(tsocket, command, option): 8 | if command == DO and option == TTYPE: 9 | tsocket.sendall(IAC + WILL + TTYPE) 10 | print 'Sending terminal type "mypython"' 11 | tsocket.sendall(IAC + SB + TTYPE + '\0' + 'mypython' + IAC + SE) 12 | elif command in (DO, DONT): 13 | print 'Will not', ord(option) 14 | tsocket.sendall(IAC + WONT + option) 15 | elif command in (WILL, WONT): 16 | print 'Do not', ord(option) 17 | tsocket.sendall(IAC + DONT + option) 18 | 19 | t = Telnet('localhost') 20 | # t.set_debuglevel(1) # uncomment this for debugging messages 21 | 22 | t.set_option_negotiation_callback(process_option) 23 | t.read_until('login:', 5) 24 | t.write('brandon\n') 25 | t.read_until('assword:', 5) # so P can be capitalized or not 26 | t.write('mypass\n') 27 | n, match, previous_text = t.expect([r'Login incorrect', r'\$'], 10) 28 | if n == 0: 29 | print "Username and password failed - giving up" 30 | else: 31 | t.write('exec echo $TERM\n') 32 | print t.read_all() 33 | -------------------------------------------------------------------------------- /python2/16/telnet_login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - telnet_login.py 3 | # Connect to localhost, watch for a login prompt, and try logging in 4 | 5 | import telnetlib 6 | 7 | t = telnetlib.Telnet('localhost') 8 | # t.set_debuglevel(1) # uncomment this for debugging messages 9 | 10 | t.read_until('login:') 11 | t.write('brandon\n') 12 | t.read_until('assword:') # let "P" be capitalized or not 13 | t.write('mypass\n') 14 | n, match, previous_text = t.expect([r'Login incorrect', r'\$'], 10) 15 | if n == 0: 16 | print "Username and password failed - giving up" 17 | else: 18 | t.write('exec uptime\n') 19 | print t.read_all() # keep reading until the connection closes 20 | -------------------------------------------------------------------------------- /python2/17/advbinarydl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Advanced binary download - Chapter 17 - advbinarydl.py 3 | 4 | import os, sys 5 | from ftplib import FTP 6 | 7 | if os.path.exists('linux-1.0.tar.gz'): 8 | raise IOError('refusing to overwrite your linux-1.0.tar.gz file') 9 | 10 | f = FTP('ftp.kernel.org') 11 | f.login() 12 | 13 | f.cwd('/pub/linux/kernel/v1.0') 14 | f.voidcmd("TYPE I") 15 | 16 | datasock, size = f.ntransfercmd("RETR linux-1.0.tar.gz") 17 | bytes_so_far = 0 18 | fd = open('linux-1.0.tar.gz', 'wb') 19 | 20 | while 1: 21 | buf = datasock.recv(2048) 22 | if not buf: 23 | break 24 | fd.write(buf) 25 | bytes_so_far += len(buf) 26 | print "\rReceived", bytes_so_far, 27 | if size: 28 | print "of %d total bytes (%.1f%%)" % ( 29 | size, 100 * bytes_so_far / float(size)), 30 | else: 31 | print "bytes", 32 | sys.stdout.flush() 33 | 34 | print 35 | fd.close() 36 | datasock.close() 37 | f.voidresp() 38 | f.quit() 39 | -------------------------------------------------------------------------------- /python2/17/advbinaryul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Advanced binary upload - Chapter 17 - advbinaryul.py 3 | 4 | from ftplib import FTP 5 | import sys, getpass, os.path 6 | 7 | BLOCKSIZE = 8192 # chunk size to read and transmit: 8 kB 8 | 9 | if len(sys.argv) != 5: 10 | print "usage: %s " % ( 11 | sys.argv[0]) 12 | exit(2) 13 | 14 | host, username, localfile, remotedir = sys.argv[1:] 15 | password = getpass.getpass("Enter password for %s on %s: " % \ 16 | (username, host)) 17 | f = FTP(host) 18 | f.login(username, password) 19 | 20 | f.cwd(remotedir) 21 | f.voidcmd("TYPE I") 22 | 23 | fd = open(localfile, 'rb') 24 | datasock, esize = f.ntransfercmd('STOR %s' % os.path.basename(localfile)) 25 | size = os.stat(localfile)[6] 26 | bytes_so_far = 0 27 | 28 | while 1: 29 | buf = fd.read(BLOCKSIZE) 30 | if not buf: 31 | break 32 | datasock.sendall(buf) 33 | bytes_so_far += len(buf) 34 | print "\rSent", bytes_so_far, "of", size, "bytes", \ 35 | "(%.1f%%)\r" % (100 * bytes_so_far / float(size)) 36 | sys.stdout.flush() 37 | 38 | print 39 | datasock.close() 40 | fd.close() 41 | f.voidresp() 42 | f.quit() 43 | -------------------------------------------------------------------------------- /python2/17/asciidl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ASCII download - Chapter 17 - asciidl.py 3 | # Downloads README from remote and writes it to disk. 4 | 5 | import os 6 | from ftplib import FTP 7 | 8 | if os.path.exists('README'): 9 | raise IOError('refusing to overwrite your README file') 10 | 11 | def writeline(data): 12 | fd.write(data) 13 | fd.write(os.linesep) 14 | 15 | f = FTP('ftp.kernel.org') 16 | f.login() 17 | f.cwd('/pub/linux/kernel') 18 | 19 | fd = open('README', 'w') 20 | f.retrlines('RETR README', writeline) 21 | fd.close() 22 | 23 | f.quit() 24 | -------------------------------------------------------------------------------- /python2/17/binarydl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Binary upload - Chapter 17 - binarydl.py 3 | 4 | import os 5 | from ftplib import FTP 6 | 7 | if os.path.exists('patch8.gz'): 8 | raise IOError('refusing to overwrite your patch8.gz file') 9 | 10 | f = FTP('ftp.kernel.org') 11 | f.login() 12 | f.cwd('/pub/linux/kernel/v1.0') 13 | 14 | fd = open('patch8.gz', 'wb') 15 | f.retrbinary('RETR patch8.gz', fd.write) 16 | fd.close() 17 | 18 | f.quit() 19 | -------------------------------------------------------------------------------- /python2/17/binaryul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Binary download - Chapter 17 - binaryul.py 3 | 4 | from ftplib import FTP 5 | import sys, getpass, os.path 6 | 7 | if len(sys.argv) != 5: 8 | print "usage: %s " % ( 9 | sys.argv[0]) 10 | exit(2) 11 | 12 | host, username, localfile, remotedir = sys.argv[1:] 13 | password = getpass.getpass( 14 | "Enter password for %s on %s: " % (username, host)) 15 | 16 | f = FTP(host) 17 | f.login(username, password) 18 | f.cwd(remotedir) 19 | 20 | fd = open(localfile, 'rb') 21 | f.storbinary('STOR %s' % os.path.basename(localfile), fd) 22 | fd.close() 23 | 24 | f.quit() 25 | -------------------------------------------------------------------------------- /python2/17/connect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Basic connection - Chapter 17 - connect.py 3 | 4 | from ftplib import FTP 5 | 6 | f = FTP('ftp.ibiblio.org') 7 | print "Welcome:", f.getwelcome() 8 | f.login() 9 | 10 | print "Current working directory:", f.pwd() 11 | f.quit() 12 | -------------------------------------------------------------------------------- /python2/17/dir.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # dir() example - Chapter 17 - dir.py 3 | 4 | from ftplib import FTP 5 | 6 | f = FTP('ftp.ibiblio.org') 7 | f.login() 8 | f.cwd('/pub/academic/astronomy/') 9 | entries = [] 10 | f.dir(entries.append) 11 | print "%d entries:" % len(entries) 12 | for entry in entries: 13 | print entry 14 | f.quit() 15 | -------------------------------------------------------------------------------- /python2/17/nlst.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # NLST example - Chapter 17 - nlst.py 3 | 4 | from ftplib import FTP 5 | 6 | f = FTP('ftp.ibiblio.org') 7 | f.login() 8 | f.cwd('/pub/academic/astronomy/') 9 | entries = f.nlst() 10 | entries.sort() 11 | print len(entries), "entries:" 12 | for entry in entries: 13 | print entry 14 | f.quit() 15 | -------------------------------------------------------------------------------- /python2/17/recursedl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Recursive downloader - Chapter 17 - recursedl.py 3 | 4 | import os, sys 5 | from ftplib import FTP, error_perm 6 | 7 | def walk_dir(f, dirpath): 8 | original_dir = f.pwd() 9 | try: 10 | f.cwd(dirpath) 11 | except error_perm: 12 | return # ignore non-directores and ones we cannot enter 13 | print dirpath 14 | names = f.nlst() 15 | for name in names: 16 | walk_dir(f, dirpath + '/' + name) 17 | f.cwd(original_dir) # return to cwd of our caller 18 | 19 | f = FTP('ftp.kernel.org') 20 | f.login() 21 | walk_dir(f, '/pub/linux/kernel/Historic/old-versions') 22 | f.quit() 23 | -------------------------------------------------------------------------------- /python2/18/jsonrpc_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - jsonrpc_client.py 3 | # JSON-RPC client 4 | 5 | from lovely.jsonrpc import proxy 6 | proxy = proxy.ServerProxy('http://localhost:7002') 7 | print proxy.lengths((1,2,3), 27, {'Sirius': -1.46, 'Rigel': 0.12}) 8 | -------------------------------------------------------------------------------- /python2/18/jsonrpc_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - jsonrpc_server.py 3 | # JSON-RPC server 4 | 5 | from wsgiref.simple_server import make_server 6 | import lovely.jsonrpc.dispatcher, lovely.jsonrpc.wsgi 7 | 8 | def lengths(*args): 9 | results = [] 10 | for arg in args: 11 | try: 12 | arglen = len(arg) 13 | except TypeError: 14 | arglen = None 15 | results.append((arglen, arg)) 16 | return results 17 | 18 | dispatcher = lovely.jsonrpc.dispatcher.JSONRPCDispatcher() 19 | dispatcher.register_method(lengths) 20 | app = lovely.jsonrpc.wsgi.WSGIJSONRPCApplication({'': dispatcher}) 21 | server = make_server('localhost', 7002, app) 22 | print "Starting server" 23 | while True: 24 | server.handle_request() 25 | -------------------------------------------------------------------------------- /python2/18/rpyc_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - rpyc_client.py 3 | # RPyC client 4 | 5 | import rpyc 6 | 7 | def noisy(string): 8 | print 'Noisy:', repr(string) 9 | 10 | proxy = rpyc.connect('localhost', 18861, config={'allow_public_attrs': True}) 11 | fileobj = open('testfile.txt') 12 | linecount = proxy.root.line_counter(fileobj, noisy) 13 | print 'The number of lines in the file was', linecount 14 | -------------------------------------------------------------------------------- /python2/18/rpyc_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - rpyc_server.py 3 | # RPyC server 4 | 5 | import rpyc 6 | 7 | class MyService(rpyc.Service): 8 | def exposed_line_counter(self, fileobj, function): 9 | for linenum, line in enumerate(fileobj.readlines()): 10 | function(line) 11 | return linenum + 1 12 | 13 | from rpyc.utils.server import ThreadedServer 14 | t = ThreadedServer(MyService, port = 18861) 15 | t.start() 16 | -------------------------------------------------------------------------------- /python2/18/testfile.txt: -------------------------------------------------------------------------------- 1 | Simple 2 | is 3 | better 4 | than 5 | complex. 6 | -------------------------------------------------------------------------------- /python2/18/xmlrpc_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_client.py 4 | # XML-RPC client 5 | 6 | import xmlrpclib 7 | proxy = xmlrpclib.ServerProxy('http://127.0.0.1:7001') 8 | print proxy.addtogether('x', 'ÿ', 'z') 9 | print proxy.addtogether(20, 30, 4, 1) 10 | print proxy.quadratic(2, -4, 0) 11 | print proxy.quadratic(1, 2, 1) 12 | print proxy.remote_repr((1, 2.0, 'three')) 13 | print proxy.remote_repr([1, 2.0, 'three']) 14 | print proxy.remote_repr({'name': 'Arthur', 'data': {'age': 42, 'sex': 'M'}}) 15 | print proxy.quadratic(1, 0, 1) 16 | -------------------------------------------------------------------------------- /python2/18/xmlrpc_introspect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_introspect.py 3 | # XML-RPC client 4 | 5 | import xmlrpclib 6 | proxy = xmlrpclib.ServerProxy('http://127.0.0.1:7001') 7 | 8 | print 'Here are the functions supported by this server:' 9 | for method_name in proxy.system.listMethods(): 10 | 11 | if method_name.startswith('system.'): 12 | continue 13 | 14 | signatures = proxy.system.methodSignature(method_name) 15 | if isinstance(signatures, list) and signatures: 16 | for signature in signatures: 17 | print '%s(%s)' % (method_name, signature) 18 | else: 19 | print '%s(...)' % (method_name,) 20 | 21 | method_help = proxy.system.methodHelp(method_name) 22 | if method_help: 23 | print ' ', method_help 24 | -------------------------------------------------------------------------------- /python2/18/xmlrpc_multicall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_multicall.py 3 | # XML-RPC client performing a multicall 4 | 5 | import xmlrpclib 6 | proxy = xmlrpclib.ServerProxy('http://127.0.0.1:7001') 7 | multicall = xmlrpclib.MultiCall(proxy) 8 | multicall.addtogether('a', 'b', 'c') 9 | multicall.quadratic(2, -4, 0) 10 | multicall.remote_repr([1, 2.0, 'three']) 11 | for answer in multicall(): 12 | print answer 13 | -------------------------------------------------------------------------------- /python2/18/xmlrpc_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_server.py 3 | # XML-RPC server 4 | 5 | import operator, math 6 | from SimpleXMLRPCServer import SimpleXMLRPCServer 7 | 8 | def addtogether(*things): 9 | """Add together everything in the list `things`.""" 10 | return reduce(operator.add, things) 11 | 12 | def quadratic(a, b, c): 13 | """Determine `x` values satisfying: `a` * x*x + `b` * x + c == 0""" 14 | b24ac = math.sqrt(b*b - 4.0*a*c) 15 | return list(set([ (-b-b24ac) / 2.0*a, 16 | (-b+b24ac) / 2.0*a ])) 17 | 18 | def remote_repr(arg): 19 | """Return the `repr()` rendering of the supplied `arg`.""" 20 | return arg 21 | 22 | server = SimpleXMLRPCServer(('127.0.0.1', 7001)) 23 | server.register_introspection_functions() 24 | server.register_multicall_functions() 25 | server.register_function(addtogether) 26 | server.register_function(quadratic) 27 | server.register_function(remote_repr) 28 | print "Server ready" 29 | server.serve_forever() 30 | -------------------------------------------------------------------------------- /python3/01/getname.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - getname.py 3 | 4 | import socket 5 | hostname = 'maps.google.com' 6 | addr = socket.gethostbyname(hostname) 7 | print('The address of', hostname, 'is', addr) 8 | -------------------------------------------------------------------------------- /python3/01/search1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search1.py 3 | 4 | from googlemaps import GoogleMaps 5 | address = '207 N. Defiance St, Archbold, OH' 6 | print(GoogleMaps().address_to_latlng(address)) 7 | -------------------------------------------------------------------------------- /python3/01/search2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search2.py 3 | 4 | import json 5 | import urllib, urllib.request, urllib.error, urllib.parse 6 | 7 | params = {'q': '207 N. Defiance St, Archbold, OH', 8 | 'output': 'json', 'oe': 'utf8'} 9 | url = 'http://maps.google.com/maps/geo?' + urllib.parse.urlencode(params) 10 | 11 | rawreply = urllib.request.urlopen(url).read() 12 | 13 | reply = json.loads(rawreply.decode('utf-8')) 14 | print(reply['Placemark'][0]['Point']['coordinates'][:-1]) 15 | -------------------------------------------------------------------------------- /python3/01/search3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search3.py 3 | 4 | import http.client 5 | import json 6 | 7 | path = ('/maps/geo?q=207+N.+Defiance+St%2C+Archbold%2C+OH' 8 | '&output=json&oe=utf8') 9 | 10 | connection = http.client.HTTPConnection('maps.google.com') 11 | connection.request('GET', path) 12 | rawreply = connection.getresponse().read() 13 | 14 | reply = json.loads(rawreply.decode('utf-8')) 15 | print(reply['Placemark'][0]['Point']['coordinates'][:-1]) 16 | -------------------------------------------------------------------------------- /python3/01/search4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 1 - search4.py 3 | 4 | import socket 5 | sock = socket.socket() 6 | sock.connect(('maps.google.com', 80)) 7 | sock.sendall( 8 | b'GET /maps/geo?q=207+N.+Defiance+St%2C+Archbold%2C+OH' 9 | b'&output=json&oe=utf8&sensor=false HTTP/1.1\r\n' 10 | b'Host: maps.google.com:80\r\n' 11 | b'User-Agent: search4.py\r\n' 12 | b'Connection: close\r\n' 13 | b'\r\n') 14 | rawreply = sock.recv(4096) 15 | print(rawreply.decode('utf-8')) 16 | -------------------------------------------------------------------------------- /python3/01/search4.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Content-Type: text/javascript; charset=UTF-8 3 | Vary: Accept-Language 4 | Date: Wed, 21 Jul 2010 16:10:38 GMT 5 | Server: mafe 6 | Cache-Control: private, x-gzip-ok="" 7 | X-XSS-Protection: 1; mode=block 8 | Connection: close 9 | 10 | { 11 | "name": "207 N. Defiance St, Archbold, OH", 12 | "Status": { 13 | "code": 200, 14 | "request": "geocode" 15 | }, 16 | "Placemark": [ { 17 | ... 18 | "Point": { 19 | "coordinates": [ -84.3063479, 41.5228242, 0 ] 20 | } 21 | } ] 22 | } 23 | 24 | -------------------------------------------------------------------------------- /python3/02/big_sender.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - big_sender.py 3 | # Send a big UDP packet to our server. 4 | 5 | import IN, socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | MAX = 65535 9 | PORT = 1060 10 | 11 | if len(sys.argv) != 2: 12 | print('usage: big_sender.py host', file=sys.stderr) 13 | sys.exit(2) 14 | 15 | hostname = sys.argv[1] 16 | s.connect((hostname, PORT)) 17 | s.setsockopt(socket.IPPROTO_IP, IN.IP_MTU_DISCOVER, IN.IP_PMTUDISC_DO) 18 | try: 19 | s.send(b'#' * 65000) 20 | except socket.error: 21 | print('The message did not make it') 22 | option = getattr(IN, 'IP_MTU', 14) # constant taken from 23 | print('MTU:', s.getsockopt(socket.IPPROTO_IP, option)) 24 | else: 25 | print('The big message was sent! Your network supports really big packets!') 26 | -------------------------------------------------------------------------------- /python3/02/udp_broadcast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - udp_broadcast.py 3 | # UDP client and server for broadcast messages on a local LAN 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 8 | 9 | MAX = 65535 10 | PORT = 1060 11 | 12 | if 2 <= len(sys.argv) <= 3 and sys.argv[1] == 'server': 13 | s.bind(('', PORT)) 14 | print('Listening for broadcasts at', s.getsockname()) 15 | while True: 16 | data, address = s.recvfrom(MAX) 17 | print('The client at %r says: %r' % (address, data)) 18 | 19 | elif len(sys.argv) == 3 and sys.argv[1] == 'client': 20 | network = sys.argv[2] 21 | s.sendto(b'Broadcast message!', (network, PORT)) 22 | 23 | else: 24 | print('usage: udp_broadcast.py server', file=sys.stderr) 25 | print(' or: udp_broadcast.py client ', file=sys.stderr) 26 | sys.exit(2) 27 | -------------------------------------------------------------------------------- /python3/02/udp_local.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - udp_local.py 3 | # UDP client and server on localhost 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | MAX = 65535 9 | PORT = 1060 10 | 11 | if sys.argv[1:] == ['server']: 12 | s.bind(('127.0.0.1', PORT)) 13 | print('Listening at', s.getsockname()) 14 | while True: 15 | data, address = s.recvfrom(MAX) 16 | print('The client at', address, 'says', repr(data)) 17 | message = 'Your data was %d bytes' % len(data) 18 | s.sendto(message.encode('ascii'), address) 19 | 20 | elif sys.argv[1:] == ['client']: 21 | print('Address before sending:', s.getsockname()) 22 | s.sendto(b'This is my message', ('127.0.0.1', PORT)) 23 | print('Address after sending', s.getsockname()) 24 | data, address = s.recvfrom(MAX) # overly promiscuous - see Chapter 2 25 | print('The server', address, 'says', data) 26 | 27 | else: 28 | print('usage: udp_local.py server|client', file=sys.stderr) 29 | -------------------------------------------------------------------------------- /python3/02/udp_remote.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 2 - udp_remote.py 3 | # UDP client and server for talking over the network 4 | 5 | import random, socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | MAX = 65535 9 | PORT = 1060 10 | 11 | if 2 <= len(sys.argv) <= 3 and sys.argv[1] == 'server': 12 | interface = sys.argv[2] if len(sys.argv) > 2 else '' 13 | s.bind((interface, PORT)) 14 | print('Listening at', s.getsockname()) 15 | while True: 16 | data, address = s.recvfrom(MAX) 17 | if random.randint(0, 1): 18 | print('The client at', address, 'says:', repr(data)) 19 | message = 'Your data was %d bytes' % len(data) 20 | s.sendto(message.encode('ascii'), address) 21 | else: 22 | print('Pretending to drop packet from', address) 23 | 24 | elif len(sys.argv) == 3 and sys.argv[1] == 'client': 25 | hostname = sys.argv[2] 26 | s.connect((hostname, PORT)) 27 | print('Client socket name is', s.getsockname()) 28 | delay = 0.1 29 | while True: 30 | s.send(b'This is another message') 31 | print('Waiting up to', delay, 'seconds for a reply') 32 | s.settimeout(delay) 33 | try: 34 | data = s.recv(MAX) 35 | except socket.timeout: 36 | delay *= 2 # wait even longer for the next request 37 | if delay > 2.0: 38 | raise RuntimeError('I think the server is down') 39 | else: 40 | break # we are done, and can stop looping 41 | 42 | print('The server says', repr(data)) 43 | 44 | else: 45 | print('usage: udp_remote.py server [ ]', file=sys.stderr) 46 | print(' or: udp_remote.py client ', file=sys.stderr) 47 | sys.exit(2) 48 | -------------------------------------------------------------------------------- /python3/03/tcp_deadlock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 3 - tcp_deadlock.py 3 | # TCP client and server that leave too much data waiting 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = '127.0.0.1' 9 | PORT = 1060 10 | 11 | if sys.argv[1:] == ['server']: 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | s.bind((HOST, PORT)) 14 | s.listen(1) 15 | while True: 16 | print('Listening at', s.getsockname()) 17 | sc, sockname = s.accept() 18 | print('Processing up to 1024 bytes at a time from', sockname) 19 | n = 0 20 | while True: 21 | data = sc.recv(1024) 22 | if not data: 23 | break 24 | output = data.decode('ascii').upper().encode('ascii') 25 | sc.sendall(output) # send it back uppercase 26 | n += len(data) 27 | print('\r%d bytes processed so far' % (n,), end=' ') 28 | sys.stdout.flush() 29 | print() 30 | sc.close() 31 | print('Completed processing') 32 | 33 | elif len(sys.argv) == 3 and sys.argv[1] == 'client' and sys.argv[2].isdigit(): 34 | 35 | bytecount = (int(sys.argv[2]) + 15) // 16 * 16 # round up to // 16 36 | message = b'capitalize this!' # 16-byte message to repeat over and over 37 | 38 | print('Sending', bytecount, 'bytes of data, in chunks of 16 bytes') 39 | s.connect((HOST, PORT)) 40 | 41 | sent = 0 42 | while sent < bytecount: 43 | s.sendall(message) 44 | sent += len(message) 45 | print('\r%d bytes sent' % (sent,), end=' ') 46 | sys.stdout.flush() 47 | 48 | print() 49 | s.shutdown(socket.SHUT_WR) 50 | 51 | print('Receiving all the data the server sends back') 52 | 53 | received = 0 54 | while True: 55 | data = s.recv(42) 56 | if not received: 57 | print('The first data received says', repr(data)) 58 | received += len(data) 59 | if not data: 60 | break 61 | print('\r%d bytes received' % (received,), end=' ') 62 | 63 | print() 64 | s.close() 65 | 66 | else: 67 | print('usage: tcp_deadlock.py server | client ', file=sys.stderr) 68 | -------------------------------------------------------------------------------- /python3/03/tcp_sixteen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 3 - tcp_sixteen.py 3 | # Simple TCP client and server that send and receive 16 octets 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1' 9 | PORT = 1060 10 | 11 | def recvall(sock, length): 12 | data = b'' 13 | while len(data) < length: 14 | more = sock.recv(length - len(data)) 15 | if not more: 16 | raise EOFError('socket closed %d bytes into a %d-byte message' 17 | % (len(data), length)) 18 | data += more 19 | return data 20 | 21 | if sys.argv[1:] == ['server']: 22 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 23 | s.bind((HOST, PORT)) 24 | s.listen(1) 25 | while True: 26 | print('Listening at', s.getsockname()) 27 | sc, sockname = s.accept() 28 | print('We have accepted a connection from', sockname) 29 | print('Socket connects', sc.getsockname(), 'and', sc.getpeername()) 30 | message = recvall(sc, 16) 31 | print('The incoming sixteen-octet message says', repr(message)) 32 | sc.sendall(b'Farewell, client') 33 | sc.close() 34 | print('Reply sent, socket closed') 35 | 36 | elif sys.argv[1:] == ['client']: 37 | s.connect((HOST, PORT)) 38 | print('Client has been assigned socket name', s.getsockname()) 39 | s.sendall(b'Hi there, server') 40 | reply = recvall(s, 16) 41 | print('The server said', repr(reply)) 42 | s.close() 43 | 44 | else: 45 | print('usage: tcp_local.py server|client [host]', file=sys.stderr) 46 | -------------------------------------------------------------------------------- /python3/04/dns_basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - dns_basic.py 3 | # Basic DNS query 4 | 5 | import sys, DNS 6 | 7 | if len(sys.argv) != 2: 8 | print('usage: dns_basic.py ', file=sys.stderr) 9 | sys.exit(2) 10 | 11 | DNS.DiscoverNameServers() 12 | request = DNS.Request() 13 | for qt in DNS.Type.A, DNS.Type.AAAA, DNS.Type.CNAME, DNS.Type.MX, DNS.Type.NS: 14 | reply = request.req(name=sys.argv[1], qtype=qt) 15 | for answer in reply.answers: 16 | print(answer['name'], answer['classstr'], answer['typename'], \ 17 | repr(answer['data'])) 18 | -------------------------------------------------------------------------------- /python3/04/dns_mx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - dns_mx.py 3 | # Looking up a mail domain - the part of an email address after the `@` 4 | 5 | import sys, DNS 6 | 7 | if len(sys.argv) != 2: 8 | print('usage: dns_basic.py ', file=sys.stderr) 9 | sys.exit(2) 10 | 11 | def resolve_hostname(hostname, indent=0): 12 | """Print an A or AAAA record for `hostname`; follow CNAMEs if necessary.""" 13 | indent = indent + 4 14 | istr = ' ' * indent 15 | request = DNS.Request() 16 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.A) 17 | if reply.answers: 18 | for answer in reply.answers: 19 | print(istr, 'Hostname', hostname, '= A', answer['data']) 20 | return 21 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.AAAA) 22 | if reply.answers: 23 | for answer in reply.answers: 24 | print(istr, 'Hostname', hostname, '= AAAA', answer['data']) 25 | return 26 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.CNAME) 27 | if reply.answers: 28 | cname = reply.answers[0]['data'] 29 | print(istr, 'Hostname', hostname, 'is an alias for', cname) 30 | resolve_hostname(cname, indent) 31 | return 32 | print(istr, 'ERROR: no records for', hostname) 33 | 34 | def resolve_email_domain(domain): 35 | """Print mail server IP addresses for an email address @ `domain`.""" 36 | request = DNS.Request() 37 | reply = request.req(name=sys.argv[1], qtype=DNS.Type.MX) 38 | if reply.answers: 39 | print('The domain %r has explicit MX records!' % (domain,)) 40 | print('Try the servers in this order:') 41 | datalist = [ answer['data'] for answer in reply.answers ] 42 | datalist.sort() # lower-priority integers go first 43 | for data in datalist: 44 | priority = data[0] 45 | hostname = data[1] 46 | print('Priority:', priority, ' Hostname:', hostname) 47 | resolve_hostname(hostname) 48 | else: 49 | print('Drat, this domain has no explicit MX records') 50 | print('We will have to try resolving it as an A, AAAA, or CNAME') 51 | resolve_hostname(domain) 52 | 53 | DNS.DiscoverNameServers() 54 | resolve_email_domain(sys.argv[1]) 55 | -------------------------------------------------------------------------------- /python3/04/forward_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - forward_reverse.py 3 | # Checking whether a host name works both forwards and backwards. 4 | 5 | import socket, sys 6 | 7 | if len(sys.argv) != 2: 8 | print('usage: forward_reverse.py ', file=sys.stderr) 9 | sys.exit(2) 10 | 11 | hostname = sys.argv[1] 12 | 13 | try: 14 | infolist = socket.getaddrinfo( 15 | hostname, 0, 0, socket.SOCK_STREAM, 0, 16 | socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME, 17 | ) 18 | except socket.gaierror as e: 19 | print('Forward name service failure:', e.args[1]) 20 | sys.exit(1) 21 | 22 | info = infolist[0] # choose the first, if there are several addresses 23 | canonical = info[3] 24 | socketname = info[4] 25 | ip = socketname[0] 26 | 27 | if not canonical: 28 | print('WARNING! The IP address', ip, 'has no reverse name') 29 | sys.exit(1) 30 | 31 | print(hostname, 'has IP address', ip) 32 | print(ip, 'has the canonical hostname', canonical) 33 | 34 | # Lowercase for case-insensitive comparison, and chop off hostnames. 35 | 36 | forward = hostname.lower().split('.') 37 | reverse = canonical.lower().split('.') 38 | 39 | if forward == reverse: 40 | print('Wow, the names agree completely!') 41 | sys.exit(0) 42 | 43 | # Truncate the domain names, which now look like ['www', mit', 'edu'], 44 | # to the same length and compare. Failing that, be willing to try a 45 | # compare with the first element (the hostname?) lopped off if both of 46 | # they are the same length. 47 | 48 | length = min(len(forward), len(reverse)) 49 | if (forward[-length:] == reverse[-length:] 50 | or (len(forward) == len(reverse) 51 | and forward[-length+1:] == reverse[-length+1:] 52 | and len(forward[-2]) > 2)): # avoid thinking '.co.uk' means a match! 53 | print('The forward and reverse names have a lot in common') 54 | else: 55 | print('WARNING! The reverse name belongs to a different organization') 56 | -------------------------------------------------------------------------------- /python3/04/www_ping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 4 - www_ping.py 3 | # Find the WWW service of an arbitrary host using getaddrinfo(). 4 | 5 | import socket, sys 6 | 7 | if len(sys.argv) != 2: 8 | print('usage: www_ping.py ', file=sys.stderr) 9 | sys.exit(2) 10 | 11 | hostname_or_ip = sys.argv[1] 12 | 13 | try: 14 | infolist = socket.getaddrinfo( 15 | hostname_or_ip, 'www', 0, socket.SOCK_STREAM, 0, 16 | socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME, 17 | ) 18 | except socket.gaierror as e: 19 | print('Name service failure:', e.args[1]) 20 | sys.exit(1) 21 | 22 | info = infolist[0] # per standard recommendation, try the first one 23 | socket_args = info[0:3] 24 | address = info[4] 25 | s = socket.socket(*socket_args) 26 | try: 27 | s.connect(address) 28 | except socket.error as e: 29 | print('Network failure:', e.args[1]) 30 | else: 31 | print('Success: host', info[3], 'is listening on port 80') 32 | -------------------------------------------------------------------------------- /python3/05/blocks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 5 - blocks.py 3 | # Sending data one block at a time. 4 | 5 | import socket, struct, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1' 9 | PORT = 1060 10 | format = struct.Struct('!I') # for messages up to 2**32 - 1 in length 11 | 12 | def recvall(sock, length): 13 | data = b'' 14 | while len(data) < length: 15 | more = sock.recv(length - len(data)) 16 | if not more: 17 | raise EOFError('socket closed %d bytes into a %d-byte message' 18 | % (len(data), length)) 19 | data += more 20 | return data 21 | 22 | def get(sock): 23 | lendata = recvall(sock, format.size) 24 | (length,) = format.unpack(lendata) 25 | return recvall(sock, length) 26 | 27 | def put(sock, message): 28 | sock.send(format.pack(len(message)) + message) 29 | 30 | if sys.argv[1:] == ['server']: 31 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 32 | s.bind((HOST, PORT)) 33 | s.listen(1) 34 | print('Listening at', s.getsockname()) 35 | sc, sockname = s.accept() 36 | print('Accepted connection from', sockname) 37 | sc.shutdown(socket.SHUT_WR) 38 | while True: 39 | message = get(sc) 40 | if not message: 41 | break 42 | print('Message says:', repr(message)) 43 | sc.close() 44 | s.close() 45 | 46 | elif sys.argv[1:] == ['client']: 47 | s.connect((HOST, PORT)) 48 | s.shutdown(socket.SHUT_RD) 49 | put(s, b'Beautiful is better than ugly.') 50 | put(s, b'Explicit is better than implicit.') 51 | put(s, b'Simple is better than complex.') 52 | put(s, b'') 53 | s.close() 54 | 55 | else: 56 | print('usage: streamer.py server|client [host]', file=sys.stderr) 57 | -------------------------------------------------------------------------------- /python3/05/streamer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 5 - streamer.py 3 | # Client that sends data then closes the socket, not expecting a reply. 4 | 5 | import socket, sys 6 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | 8 | HOST = sys.argv.pop() if len(sys.argv) == 3 else '127.0.0.1' 9 | PORT = 1060 10 | 11 | if sys.argv[1:] == ['server']: 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | s.bind((HOST, PORT)) 14 | s.listen(1) 15 | print('Listening at', s.getsockname()) 16 | sc, sockname = s.accept() 17 | print('Accepted connection from', sockname) 18 | sc.shutdown(socket.SHUT_WR) 19 | message = b'' 20 | while True: 21 | more = sc.recv(8192) # arbitrary value of 8k 22 | if not more: # socket has closed when recv() returns '' 23 | break 24 | message += more 25 | print('Done receiving the message; it says:') 26 | print(message.decode('ascii')) 27 | sc.close() 28 | s.close() 29 | 30 | elif sys.argv[1:] == ['client']: 31 | s.connect((HOST, PORT)) 32 | s.shutdown(socket.SHUT_RD) 33 | s.sendall(b'Beautiful is better than ugly.\n') 34 | s.sendall(b'Explicit is better than implicit.\n') 35 | s.sendall(b'Simple is better than complex.\n') 36 | s.close() 37 | 38 | else: 39 | print('usage: streamer.py server|client [host]', file=sys.stderr) 40 | -------------------------------------------------------------------------------- /python3/06/sslclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 6 - sslclient.py 3 | # Using SSL to protect a socket in Python 2.6 or later 4 | 5 | import os, socket, ssl, sys 6 | 7 | try: 8 | script_name, hostname = sys.argv 9 | except ValueError: 10 | print('usage: sslclient.py ', file=sys.stderr) 11 | sys.exit(2) 12 | 13 | # First we connect, as usual, with a socket. 14 | 15 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 16 | sock.connect((hostname, 443)) 17 | 18 | # Next, we turn the socket over to the SSL library! 19 | 20 | ca_certs_path = os.path.join(os.path.dirname(script_name), 'certfiles.crt') 21 | sslsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv3, 22 | cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_certs_path) 23 | 24 | # Does the certificate that the server proffered *really* match the 25 | # hostname to which we are trying to connect? We need to check. 26 | 27 | try: 28 | ssl.match_hostname(sslsock.getpeercert(), hostname) 29 | except ssl.CertificateError as ce: 30 | print('Certificate error:', str(ce)) 31 | sys.exit(1) 32 | 33 | # From here on, our `sslsock` works like a normal socket. We can, for 34 | # example, make an impromptu HTTP call. 35 | 36 | sslsock.sendall(b'GET / HTTP/1.0\r\n\r\n') 37 | result = sslsock.makefile().read() # quick way to read until EOF 38 | sslsock.close() 39 | print('The document https://%s/ is %d bytes long' % (hostname, len(result))) 40 | -------------------------------------------------------------------------------- /python3/07/Bench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for SERVER in server_*.py 4 | do 5 | echo '===========' $SERVER '===========' 6 | python $SERVER '' & 7 | ssh kenaniah <<'EOF' 8 | cd ~/apress 9 | source v/bin/activate 10 | cd fopnp/source/07 11 | LAUNCELOT_SERVER=192.168.5.130 fl-run-bench launcelot_tests.py TestLauncelot.test_dialog > OUT 2>&1 12 | EOF 13 | kill %1 14 | wait %1 2>/dev/null 15 | kill $(lsof | grep 'TCP.*1060' | awk '{print$2}') 16 | scp kenaniah:apress/fopnp/source/07/bench.xml ~/apress/bench 17 | (cd ~/apress/bench; fl-build-report --html bench.xml; rm -rf $SERVER; mv test_* $SERVER) 18 | done 19 | -------------------------------------------------------------------------------- /python3/07/Test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for SERVER in server_*.py 4 | do 5 | echo '===========' $SERVER '===========' 6 | python $SERVER localhost & 7 | sleep 1 8 | python client.py localhost 1060 9 | kill %1 10 | wait %1 2>/dev/null || true 11 | kill $(lsof | grep 'TCP.*1060' | awk '{print$2}') 12 | done 13 | -------------------------------------------------------------------------------- /python3/07/TestLancelot.conf: -------------------------------------------------------------------------------- 1 | # TestLauncelot.conf 2 | [main] 3 | title=Load Test For Chapter 7 4 | description=From the Foundations of Python Network Programming 5 | url=http://localhost:1060/ 6 | 7 | [ftest] 8 | log_path = ftest.log 9 | result_path = ftest.xml 10 | sleep_time_min = 0 11 | sleep_time_max = 0 12 | 13 | [bench] 14 | log_to = file 15 | log_path = bench.log 16 | result_path = bench.xml 17 | cycles = 1:2:3:5:7:10:13:16:20 18 | duration = 8 19 | startup_delay = 0.1 20 | sleep_time = 0.01 21 | cycle_time = 10 22 | sleep_time_min = 0 23 | sleep_time_max = 0 24 | -------------------------------------------------------------------------------- /python3/07/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - client.py 3 | # Simple Lancelot client that asks three questions then disconnects. 4 | 5 | import socket, sys, lancelot 6 | 7 | def client(hostname, port): 8 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | s.connect((hostname, port)) 10 | s.sendall(lancelot.qa[0][0]) 11 | answer1 = lancelot.recv_until(s, b'.') # answers end with '.' 12 | s.sendall(lancelot.qa[1][0]) 13 | answer2 = lancelot.recv_until(s, b'.') 14 | s.sendall(lancelot.qa[2][0]) 15 | answer3 = lancelot.recv_until(s, b'.') 16 | s.close() 17 | print(answer1) 18 | print(answer2) 19 | print(answer3) 20 | 21 | if __name__ == '__main__': 22 | if not 2 <= len(sys.argv) <= 3: 23 | print('usage: client.py hostname [port]', file=sys.stderr) 24 | sys.exit(2) 25 | port = int(sys.argv[2]) if len(sys.argv) > 2 else lancelot.PORT 26 | client(sys.argv[1], port) 27 | -------------------------------------------------------------------------------- /python3/07/lancelot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - lancelot.py 3 | # Constants and routines for supporting a certain network conversation. 4 | 5 | import socket, sys 6 | 7 | PORT = 1060 8 | qa = ((b'What is your name?', b'My name is Sir Lancelot of Camelot.'), 9 | (b'What is your quest?', b'To seek the Holy Grail.'), 10 | (b'What is your favorite color?', b'Blue.')) 11 | qadict = dict(qa) 12 | 13 | def recv_until(sock, suffix): 14 | message = b'' 15 | while not message.endswith(suffix): 16 | data = sock.recv(4096) 17 | if not data: 18 | raise EOFError('socket closed before we saw %r' % suffix) 19 | message += data 20 | return message 21 | 22 | def setup(): 23 | if len(sys.argv) != 2: 24 | print('usage: %s interface' % sys.argv[0], file=sys.stderr) 25 | exit(2) 26 | interface = sys.argv[1] 27 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 28 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 29 | sock.bind((interface, PORT)) 30 | sock.listen(128) 31 | print('Ready and listening at %r port %d' % (interface, PORT)) 32 | return sock 33 | -------------------------------------------------------------------------------- /python3/07/lancelot_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - lancelot_tests.py 3 | # Test suite that can be run against the Lancelot servers. 4 | 5 | from funkload.FunkLoadTestCase import FunkLoadTestCase 6 | import socket, os, unittest, lancelot 7 | 8 | SERVER_HOST = os.environ.get('LAUNCELOT_SERVER', 'localhost') 9 | 10 | class TestLancelot(FunkLoadTestCase): 11 | def test_dialog(self): 12 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 | sock.connect((SERVER_HOST, lancelot.PORT)) 14 | for i in range(10): 15 | question, answer = lancelot.qa[i % len(launcelot.qa)] 16 | sock.sendall(question) 17 | reply = lancelot.recv_until(sock, '.') 18 | self.assertEqual(reply, answer) 19 | sock.close() 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /python3/07/my_trace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - my_trace.py 3 | # Command-line tool for tracing a single function in a program. 4 | 5 | import linecache, sys, time 6 | 7 | def make_tracer(funcname): 8 | def mytrace(frame, event, arg): 9 | if frame.f_code.co_name == funcname: 10 | if event == 'line': 11 | _events.append((time.time(), frame.f_code.co_filename, 12 | frame.f_lineno)) 13 | return mytrace 14 | return mytrace 15 | 16 | if __name__ == '__main__': 17 | _events = [] 18 | if len(sys.argv) < 3: 19 | print('usage: my_trace.py funcname other_script.py ...', file=sys.stderr) 20 | sys.exit(2) 21 | sys.settrace(make_tracer(sys.argv[1])) 22 | del sys.argv[0:2] # show the script only its own name and arguments 23 | try: 24 | exec(compile(open(sys.argv[0]).read(), sys.argv[0], 'exec')) 25 | finally: 26 | for t, filename, lineno in _events: 27 | s = linecache.getline(filename, lineno) 28 | sys.stdout.write('%9.6f %s' % (t % 60.0, s)) 29 | -------------------------------------------------------------------------------- /python3/07/server_SocketServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_SocketServer.py 3 | # Answering Lancelot requests with a SocketServer. 4 | 5 | from socketserver import ThreadingMixIn, TCPServer, BaseRequestHandler 6 | import lancelot, server_simple, socket 7 | 8 | class MyHandler(BaseRequestHandler): 9 | def handle(self): 10 | server_simple.handle_client(self.request) 11 | 12 | class MyServer(ThreadingMixIn, TCPServer): 13 | allow_reuse_address = 1 14 | # address_family = socket.AF_INET6 # if you need IPv6 15 | 16 | server = MyServer(('', lancelot.PORT), MyHandler) 17 | server.serve_forever() 18 | -------------------------------------------------------------------------------- /python3/07/server_async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_async.py 3 | # Using the ancient "asyncore" framework to write a server. 4 | 5 | import asyncore, asynchat, lancelot 6 | 7 | class LancelotRequestHandler(asynchat.async_chat): 8 | 9 | def __init__(self, sock): 10 | asynchat.async_chat.__init__(self, sock) 11 | self.set_terminator(b'?') 12 | self.data = b'' 13 | 14 | def collect_incoming_data(self, more_data): 15 | self.data += more_data 16 | 17 | def found_terminator(self): 18 | answer = dict(lancelot.qa)[self.data + b'?'] 19 | self.push(answer) 20 | self.initiate_send() 21 | self.data = b'' 22 | 23 | class LancelotServer(asyncore.dispatcher): 24 | def handle_accept(self): 25 | sock, address = self.accept() 26 | LancelotRequestHandler(sock) 27 | 28 | sock = lancelot.setup() 29 | ls = LancelotServer(sock) 30 | ls.accepting = True # since we already called listen() 31 | asyncore.loop() 32 | -------------------------------------------------------------------------------- /python3/07/server_multi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_multi.py 3 | # Using multiple threads or processes to serve several clients in parallel. 4 | 5 | import sys, time, lancelot 6 | from multiprocessing import Process 7 | from server_simple import server_loop 8 | from threading import Thread 9 | 10 | WORKER_CLASSES = {'thread': Thread, 'process': Process} 11 | WORKER_MAX = 10 12 | 13 | def start_worker(Worker, listen_sock): 14 | worker = Worker(target=server_loop, args=(listen_sock,)) 15 | worker.daemon = True # exit when the main process does 16 | worker.start() 17 | return worker 18 | 19 | if __name__ == '__main__': 20 | if len(sys.argv) != 3 or sys.argv[2] not in WORKER_CLASSES: 21 | print('usage: server_multi.py interface thread|process', file=sys.stderr) 22 | sys.exit(2) 23 | Worker = WORKER_CLASSES[sys.argv.pop()] # setup() wants len(argv)==2 24 | 25 | # Every worker will accept() forever on the same listening socket. 26 | 27 | listen_sock = lancelot.setup() 28 | workers = [] 29 | for i in range(WORKER_MAX): 30 | workers.append(start_worker(Worker, listen_sock)) 31 | 32 | # Check every two seconds for dead workers, and replace them. 33 | 34 | while True: 35 | time.sleep(2) 36 | for worker in workers: 37 | if not worker.is_alive(): 38 | print(worker.name, "died; starting replacement worker") 39 | workers.remove(worker) 40 | workers.append(start_worker(Worker, listen_sock)) 41 | -------------------------------------------------------------------------------- /python3/07/server_poll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_poll.py 3 | # An event-driven approach to serving several clients with poll(). 4 | 5 | import lancelot 6 | import select 7 | 8 | listen_sock = lancelot.setup() 9 | sockets = { listen_sock.fileno(): listen_sock } 10 | requests = {} 11 | responses = {} 12 | 13 | poll = select.poll() 14 | poll.register(listen_sock, select.POLLIN) 15 | 16 | while True: 17 | for fd, event in poll.poll(): 18 | sock = sockets[fd] 19 | 20 | # Removed closed sockets from our list. 21 | if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL): 22 | poll.unregister(fd) 23 | del sockets[fd] 24 | requests.pop(sock, None) 25 | responses.pop(sock, None) 26 | 27 | # Accept connections from new sockets. 28 | elif sock is listen_sock: 29 | newsock, sockname = sock.accept() 30 | newsock.setblocking(False) 31 | fd = newsock.fileno() 32 | sockets[fd] = newsock 33 | poll.register(fd, select.POLLIN) 34 | requests[newsock] = b'' 35 | 36 | # Collect incoming data until it forms a question. 37 | elif event & select.POLLIN: 38 | data = sock.recv(4096) 39 | if not data: # end-of-file 40 | sock.close() # makes POLLNVAL happen next time 41 | continue 42 | requests[sock] += data 43 | if b'?' in requests[sock]: 44 | question = requests.pop(sock) 45 | answer = dict(lancelot.qa)[question] 46 | poll.modify(sock, select.POLLOUT) 47 | responses[sock] = answer 48 | 49 | # Send out pieces of each reply until they are all sent. 50 | elif event & select.POLLOUT: 51 | response = responses.pop(sock) 52 | n = sock.send(response) 53 | if n < len(response): 54 | responses[sock] = response[n:] 55 | else: 56 | poll.modify(sock, select.POLLIN) 57 | requests[sock] = b'' 58 | -------------------------------------------------------------------------------- /python3/07/server_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_simple.py 3 | # Simple server that only serves one client at a time; others have to wait. 4 | 5 | import lancelot 6 | 7 | def handle_client(client_sock): 8 | try: 9 | while True: 10 | question = lancelot.recv_until(client_sock, b'?') 11 | answer = lancelot.qadict[question] 12 | client_sock.sendall(answer) 13 | except EOFError: 14 | client_sock.close() 15 | 16 | def server_loop(listen_sock): 17 | while True: 18 | client_sock, sockname = listen_sock.accept() 19 | handle_client(client_sock) 20 | 21 | if __name__ == '__main__': 22 | listen_sock = lancelot.setup() 23 | server_loop(listen_sock) 24 | -------------------------------------------------------------------------------- /python3/07/server_twisted.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 7 - server_twisted.py 3 | # Using Twisted to serve Lancelot users. 4 | 5 | from twisted.internet.protocol import Protocol, ServerFactory 6 | from twisted.internet import reactor 7 | import lancelot 8 | 9 | class Lancelot(Protocol): 10 | def connectionMade(self): 11 | self.question = '' 12 | 13 | def dataReceived(self, data): 14 | self.question += data 15 | if self.question.endswith('?'): 16 | self.transport.write(dict(lancelot.qa)[self.question]) 17 | self.question = '' 18 | 19 | factory = ServerFactory() 20 | factory.protocol = Lancelot 21 | reactor.listenTCP(1060, factory) 22 | reactor.run() 23 | -------------------------------------------------------------------------------- /python3/08/hashing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 8 - hashing.py 3 | # Hashes are a great way to divide work. 4 | 5 | import hashlib 6 | 7 | def alpha_shard(word): 8 | """Do a poor job of assigning data to servers by using first letters.""" 9 | if word[0] in 'abcdef': 10 | return 'server0' 11 | elif word[0] in 'ghijklm': 12 | return 'server1' 13 | elif word[0] in 'nopqrs': 14 | return 'server2' 15 | else: 16 | return 'server3' 17 | 18 | def hash_shard(word): 19 | """Do a great job of assigning data to servers using a hash value.""" 20 | return 'server%d' % (hash(word) % 4) 21 | 22 | def md5_shard(word): 23 | """Do a great job of assigning data to servers using a hash value.""" 24 | data = word.encode('utf-8') 25 | return 'server%d' % (hashlib.md5(data).digest()[-1] % 4) 26 | 27 | words = open('/usr/share/dict/words').read().split() 28 | 29 | for function in alpha_shard, hash_shard, md5_shard: 30 | d = {'server0': 0, 'server1': 0, 'server2': 0, 'server3': 0} 31 | for word in words: 32 | d[function(word.lower())] += 1 33 | print(function.__name__[:-6], d) 34 | -------------------------------------------------------------------------------- /python3/08/queuecrazy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 8 - queuecrazy.py 3 | # Small application that uses several different message queues 4 | 5 | import random, threading, time, zmq 6 | zcontext = zmq.Context() 7 | 8 | def fountain(url): 9 | """Produces a steady stream of words.""" 10 | zsock = zcontext.socket(zmq.PUSH) 11 | zsock.bind(url) 12 | words = [ w for w in dir(__builtins__) if w.islower() ] 13 | while True: 14 | zsock.send(random.choice(words)) 15 | time.sleep(0.4) 16 | 17 | def responder(url, function): 18 | """Performs a string operation on each word received.""" 19 | zsock = zcontext.socket(zmq.REP) 20 | zsock.bind(url) 21 | while True: 22 | word = zsock.recv() 23 | zsock.send(function(word)) # send the modified word back 24 | 25 | def processor(n, fountain_url, responder_urls): 26 | """Read words as they are produced; get them processed; print them.""" 27 | zpullsock = zcontext.socket(zmq.PULL) 28 | zpullsock.connect(fountain_url) 29 | 30 | zreqsock = zcontext.socket(zmq.REQ) 31 | for url in responder_urls: 32 | zreqsock.connect(url) 33 | 34 | while True: 35 | word = zpullsock.recv() 36 | zreqsock.send(word) 37 | print(n, zreqsock.recv()) 38 | 39 | def start_thread(function, *args): 40 | thread = threading.Thread(target=function, args=args) 41 | thread.daemon = True # so you can easily Control-C the whole program 42 | thread.start() 43 | 44 | start_thread(fountain, 'tcp://127.0.0.1:6700') 45 | start_thread(responder, 'tcp://127.0.0.1:6701', str.upper) 46 | start_thread(responder, 'tcp://127.0.0.1:6702', str.lower) 47 | for n in range(3): 48 | start_thread(processor, n + 1, 'tcp://127.0.0.1:6700', 49 | ['tcp://127.0.0.1:6701', 'tcp://127.0.0.1:6702']) 50 | time.sleep(30) 51 | -------------------------------------------------------------------------------- /python3/08/squares.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 8 - squares.py 3 | # Using memcached to cache expensive results. 4 | 5 | import memcache, random, time, timeit 6 | mc = memcache.Client(['127.0.0.1:11211']) 7 | 8 | def compute_square(n): 9 | value = mc.get('sq:%d' % n) 10 | if value is None: 11 | time.sleep(0.001) # pretend that computing a square is expensive 12 | value = n * n 13 | mc.set('sq:%d' % n, value) 14 | return value 15 | 16 | def make_request(): 17 | compute_square(random.randint(0, 5000)) 18 | 19 | print('Ten successive runs:', end=' ') 20 | for i in range(1, 11): 21 | print('%.2fs' % timeit.timeit(make_request, number=2000), end=' ') 22 | print() 23 | -------------------------------------------------------------------------------- /python3/09/get_rfc2616.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 9 - verbose_handler.py 3 | # Example use of the verbose HTTP request handler. 4 | 5 | import urllib, urllib.request, urllib.error, urllib.parse 6 | from verbose_http import VerboseHTTPHandler 7 | opener = urllib.request.build_opener(VerboseHTTPHandler) 8 | opener.open('http://www.ietf.org/rfc/rfc2616.txt') 9 | -------------------------------------------------------------------------------- /python3/09/verbose_http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 9 - verbose_handler.py 3 | # HTTP request handler for urllib2 that prints requests and responses. 4 | 5 | import io, http.client, urllib.request, urllib.error, urllib.parse 6 | 7 | class VerboseHTTPResponse(http.client.HTTPResponse): 8 | def _read_status(self): 9 | s = self.fp.read() 10 | print('-' * 20, 'Response', '-' * 20) 11 | print(s.split(b'\r\n\r\n')[0].decode('ascii')) 12 | self.fp = io.BytesIO(s) 13 | return http.client.HTTPResponse._read_status(self) 14 | 15 | class VerboseHTTPConnection(http.client.HTTPConnection): 16 | response_class = VerboseHTTPResponse 17 | def send(self, s): 18 | print('-' * 50) 19 | print(s.strip().decode('ascii')) 20 | http.client.HTTPConnection.send(self, s) 21 | 22 | class VerboseHTTPHandler(urllib.request.HTTPHandler): 23 | def http_open(self, req): 24 | return self.do_open(VerboseHTTPConnection, req) 25 | -------------------------------------------------------------------------------- /python3/10/excerpt.html: -------------------------------------------------------------------------------- 1 | 2 | 7-Day Forecast for Latitude 33.45°N and Longitude 112.07°W (Elev. 1132 ft) 3 | ... 4 |
5 | 6 | 10 | 11 | 12 |
7 | Phoenix, Phoenix Sky Harbor International Airport
8 | Last Update on 29 Oct 7:51 MST

9 |
13 | 14 | 15 | 19 |
16 | 17 | A Few Clouds
18 |
71°F
(22°C)
20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
Humidity:30 %
Wind Speed:SE 5 MPH
26 |
Barometer:30.05 in (1015.90 mb)
Dewpoint:38°F (3°C)
Visibility:10.00 Miles
More Local Wx: 3 Day History:
40 | ... 41 | -------------------------------------------------------------------------------- /python3/10/fetch_mechanize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 10 - fetch_mechanize.py 3 | # Submitting a form and retrieving a page with mechanize 4 | 5 | import mechanize 6 | br = mechanize.Browser() 7 | br.open('http://www.weather.gov/') 8 | br.select_form(predicate=lambda form: 'zipcity' in form.action) 9 | br['inputstring'] = 'Phoenix, AZ' 10 | response = br.submit() 11 | content = response.read() 12 | open('phoenix.html', 'w').write(content) 13 | -------------------------------------------------------------------------------- /python3/10/fetch_urllib2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 10 - fetch_urllib2.py 3 | # Submitting a form and retrieving a page with urllib2 4 | 5 | import urllib, urllib.request, urllib.error, urllib.parse 6 | data = urllib.parse.urlencode({'inputstring': 'Phoenix, AZ'}).encode('ascii') 7 | info = urllib.request.urlopen('http://forecast.weather.gov/zipcity.php', data) 8 | content = info.read() 9 | open('phoenix.html', 'wb').write(content) 10 | -------------------------------------------------------------------------------- /python3/10/weather.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 10 - weather.py 3 | # Fetch the weather forecast from the National Weather Service. 4 | 5 | import sys, urllib, urllib.request, urllib.error, urllib.parse 6 | import lxml.etree 7 | from lxml.cssselect import CSSSelector 8 | # from BeautifulSoup import BeautifulSoup 9 | 10 | if len(sys.argv) < 2: 11 | print('usage: weather.py CITY, STATE', file=sys.stderr) 12 | exit(2) 13 | 14 | data = urllib.parse.urlencode({'inputstring': ' '.join(sys.argv[1:])}) 15 | data = data.encode('ascii') 16 | info = urllib.request.urlopen('http://forecast.weather.gov/zipcity.php', data) 17 | content = info.read() 18 | 19 | # Solution #1 20 | parser = lxml.etree.HTMLParser(encoding='utf-8') 21 | tree = lxml.etree.fromstring(content, parser) 22 | big = CSSSelector('td.big')(tree)[0] 23 | if big.find('font') is not None: 24 | big = big.find('font') 25 | print('Condition:', big.text.strip()) 26 | print('Temperature:', big.findall('br')[1].tail) 27 | tr = tree.xpath('.//td[b="Humidity"]')[0].getparent() 28 | print('Humidity:', tr.findall('td')[1].text) 29 | print() 30 | 31 | # Solution #2 32 | # soup = BeautifulSoup(content) # doctest: +SKIP 33 | # big = soup.find('td', 'big') 34 | # if big.font is not None: 35 | # big = big.font 36 | # print('Condition:', big.contents[0].string.strip()) 37 | # temp = big.contents[3].string or big.contents[4].string # can be either 38 | # print('Temperature:', temp.replace('°', ' ')) 39 | # tr = soup.find('b', text='Humidity').parent.parent.parent 40 | # print('Humidity:', tr('td')[1].string) 41 | # print() 42 | -------------------------------------------------------------------------------- /python3/11/bottle_app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 11 - bottle_app.py 3 | # A simple web application built using the Bottle micro-framework. 4 | 5 | import base64, bottle 6 | bottle.debug(True) 7 | app = bottle.Bottle() 8 | 9 | @app.route('/encode') 10 | @bottle.view('bottle_template.html') 11 | def encode(): 12 | mystring = bottle.request.GET.get('mystring').encode('utf-8') 13 | if mystring is None: 14 | bottle.abort(400, 'This form requires a "mystring" parameter') 15 | return dict(mystring=mystring, myb=base64.b64encode(mystring)) 16 | 17 | @app.route('/') 18 | @bottle.view('bottle_template.html') 19 | def index(): 20 | return dict(mystring=None) 21 | 22 | bottle.run(app=app, host='localhost', port=8080) 23 | -------------------------------------------------------------------------------- /python3/11/bottle_template.html: -------------------------------------------------------------------------------- 1 | %#!/usr/bin/env python 2 | %# Foundations of Python Network Programming - Chapter 11 - bottle_template.py 3 | %# The page template that goes with bottle_app.py. 4 | %# 5 | bottle_app.py 6 | 7 | %if mystring is None: 8 | Welcome! Enter a string: 9 |
10 | %else: 11 | {{mystring}} base64 encoded is: {{myb}}
12 | Return to the home page 13 | %end 14 | 15 | -------------------------------------------------------------------------------- /python3/11/wsgi_app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 11 - wsgi_app.py 3 | # A simple web application built directly against the low-level WSGI spec. 4 | 5 | import cgi, base64 6 | from wsgiref.simple_server import make_server 7 | 8 | def page(content, *args): 9 | yield b'wsgi_app.py' 10 | yield (content % args).encode('utf-8') 11 | yield b'' 12 | 13 | def simple_app(environ, start_response): 14 | html_headers = [('Content-Type', 'text/html; charset=UTF-8')] 15 | gohome = '
Return to the home page' 16 | q = cgi.parse_qs(environ['QUERY_STRING']) 17 | 18 | if environ['PATH_INFO'] == '/': 19 | 20 | if environ['REQUEST_METHOD'] != 'GET' or environ['QUERY_STRING']: 21 | start_response('400 Bad Request', [('Content-Type', 'text/plain')]) 22 | return [b'Error: the front page is not a form'] 23 | 24 | start_response('200 OK', html_headers) 25 | return page('Welcome! Enter a string:
' 26 | '
') 27 | 28 | elif environ['PATH_INFO'] == '/encode': 29 | 30 | if environ['REQUEST_METHOD'] != 'GET': 31 | start_response('400 Bad Request', [('Content-Type', 'text/plain')]) 32 | return [b'Error: this form does not support POST parameters'] 33 | 34 | if 'mystring' not in q or not q['mystring'][0]: 35 | start_response('400 Bad Request', [('Content-Type', 'text/plain')]) 36 | return [b'Error: this form requires a "mystring" parameter'] 37 | 38 | my = q['mystring'][0] 39 | my64 = base64.b64encode(my.encode('utf-8')).decode('ascii') 40 | start_response('200 OK', html_headers) 41 | return page('%s base64 encoded is: %s' + gohome, 42 | cgi.escape(repr(my)), cgi.escape(my64)) 43 | 44 | else: 45 | start_response('404 Not Found', [('Content-Type', 'text/plain')]) 46 | return [b'That URL is not valid'] 47 | 48 | print('Listening on localhost:8000') 49 | make_server('localhost', 8000, simple_app).serve_forever() 50 | -------------------------------------------------------------------------------- /python3/12/message.txt: -------------------------------------------------------------------------------- 1 | To: recipient@example.com 2 | From: Test Sender 3 | Subject: Test Message, Chapter 12 4 | Date: Mon, 02 Aug 2010 10:05:55 -0400 5 | Message-ID: <20100802140555.11734.89229@guinness.ten22> 6 | 7 | Hello, 8 | 9 | This is a test message from Chapter 12. I hope you enjoy it! 10 | 11 | -- Anonymous 12 | -------------------------------------------------------------------------------- /python3/12/mime_decode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_decode.py 3 | # This program requires Python 2.2.2 or above 4 | 5 | import sys, email 6 | counter = 0 7 | parts = [] 8 | 9 | def printmsg(msg, level = 0): 10 | global counter 11 | l = "| " * level 12 | if msg.is_multipart(): 13 | print(l + "Found multipart:") 14 | for item in msg.get_payload(): 15 | printmsg(item, level + 1) 16 | else: 17 | disp = ['%d. Decodable part' % (counter + 1)] 18 | if 'content-type' in msg: 19 | disp.append(msg['content-type']) 20 | if 'content-disposition' in msg: 21 | disp.append(msg['content-disposition']) 22 | print(l + ", ".join(disp)) 23 | counter += 1 24 | parts.append(msg) 25 | 26 | inputfd = open(sys.argv[1]) 27 | msg = email.message_from_file(inputfd) 28 | printmsg(msg) 29 | 30 | while 1: 31 | print("Select part number to decode or q to quit: ") 32 | part = sys.stdin.readline().strip() 33 | if part == 'q': 34 | sys.exit(0) 35 | try: 36 | part = int(part) 37 | msg = parts[part - 1] 38 | except: 39 | print("Invalid selection.") 40 | continue 41 | 42 | print("Select file to write to:") 43 | filename = sys.stdin.readline().strip() 44 | try: 45 | fd = open(filename, 'wb') 46 | except: 47 | print("Invalid filename.") 48 | continue 49 | 50 | fd.write(msg.get_payload(decode = 1)) 51 | -------------------------------------------------------------------------------- /python3/12/mime_gen_alt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_gen_alt.py 3 | 4 | from email.mime.base import MIMEBase 5 | from email.mime.multipart import MIMEMultipart 6 | from email.mime.text import MIMEText 7 | from email import utils, encoders 8 | 9 | def alternative(data, contenttype): 10 | maintype, subtype = contenttype.split('/') 11 | if maintype == 'text': 12 | retval = MIMEText(data, _subtype=subtype) 13 | else: 14 | retval = MIMEBase(maintype, subtype) 15 | retval.set_payload(data) 16 | encoders.encode_base64(retval) 17 | return retval 18 | 19 | messagetext = """Hello, 20 | 21 | This is a *great* test message from Chapter 12. I hope you enjoy it! 22 | 23 | -- Anonymous""" 24 | messagehtml = """Hello,

25 | This is a great test message from Chapter 12. I hope you enjoy 26 | it!

27 | -- Anonymous""" 28 | 29 | 30 | msg = MIMEMultipart('alternative') 31 | msg['To'] = 'recipient@example.com' 32 | msg['From'] = 'Test Sender ' 33 | msg['Subject'] = 'Test Message, Chapter 12' 34 | msg['Date'] = utils.formatdate(localtime = 1) 35 | msg['Message-ID'] = utils.make_msgid() 36 | 37 | msg.attach(alternative(messagetext, 'text/plain')) 38 | msg.attach(alternative(messagehtml, 'text/html')) 39 | print(msg.as_string()) 40 | -------------------------------------------------------------------------------- /python3/12/mime_gen_basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_gen_basic.py 3 | 4 | from email.mime.base import MIMEBase 5 | from email.mime.multipart import MIMEMultipart 6 | from email.mime.text import MIMEText 7 | from email import utils, encoders 8 | import mimetypes, sys 9 | 10 | def attachment(filename): 11 | fd = open(filename, 'rb') 12 | mimetype, mimeencoding = mimetypes.guess_type(filename) 13 | if mimeencoding or (mimetype is None): 14 | mimetype = 'application/octet-stream' 15 | maintype, subtype = mimetype.split('/') 16 | if maintype == 'text': 17 | retval = MIMEText(fd.read(), _subtype=subtype) 18 | else: 19 | retval = MIMEBase(maintype, subtype) 20 | retval.set_payload(fd.read()) 21 | encoders.encode_base64(retval) 22 | retval.add_header('Content-Disposition', 'attachment', 23 | filename = filename) 24 | fd.close() 25 | return retval 26 | 27 | message = """Hello, 28 | 29 | This is a test message from Chapter 12. I hope you enjoy it! 30 | 31 | -- Anonymous""" 32 | 33 | msg = MIMEMultipart() 34 | msg['To'] = 'recipient@example.com' 35 | msg['From'] = 'Test Sender ' 36 | msg['Subject'] = 'Test Message, Chapter 12' 37 | msg['Date'] = utils.formatdate(localtime = 1) 38 | msg['Message-ID'] = utils.make_msgid() 39 | 40 | body = MIMEText(message, _subtype='plain') 41 | msg.attach(body) 42 | for filename in sys.argv[1:]: 43 | msg.attach(attachment(filename)) 44 | print(msg.as_string()) 45 | -------------------------------------------------------------------------------- /python3/12/mime_gen_both.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_gen_both.py 3 | 4 | from email.mime.text import MIMEText 5 | from email.mime.multipart import MIMEMultipart 6 | from email.mime.base import MIMEBase 7 | from email import utils, encoders 8 | import mimetypes, sys 9 | 10 | def genpart(data, contenttype): 11 | maintype, subtype = contenttype.split('/') 12 | if maintype == 'text': 13 | retval = MIMEText(data, _subtype=subtype) 14 | else: 15 | retval = MIMEBase(maintype, subtype) 16 | retval.set_payload(data) 17 | encoders.encode_base64(retval) 18 | return retval 19 | 20 | 21 | def attachment(filename): 22 | fd = open(filename, 'rb') 23 | mimetype, mimeencoding = mimetypes.guess_type(filename) 24 | if mimeencoding or (mimetype is None): 25 | mimetype = 'application/octet-stream' 26 | retval = genpart(fd.read(), mimetype) 27 | retval.add_header('Content-Disposition', 'attachment', 28 | filename = filename) 29 | fd.close() 30 | return retval 31 | 32 | messagetext = """Hello, 33 | 34 | This is a *great* test message from Chapter 12. I hope you enjoy it! 35 | 36 | -- Anonymous""" 37 | messagehtml = """Hello,

38 | This is a great test message from Chapter 12. I hope you enjoy 39 | it!

40 | -- Anonymous""" 41 | 42 | msg = MIMEMultipart() 43 | msg['To'] = 'recipient@example.com' 44 | msg['From'] = 'Test Sender ' 45 | msg['Subject'] = 'Test Message, Chapter 12' 46 | msg['Date'] = utils.formatdate(localtime = 1) 47 | msg['Message-ID'] = utils.make_msgid() 48 | 49 | body = MIMEMultipart('alternative') 50 | body.attach(genpart(messagetext, 'text/plain')) 51 | body.attach(genpart(messagehtml, 'text/html')) 52 | msg.attach(body) 53 | 54 | for filename in sys.argv[1:]: 55 | msg.attach(attachment(filename)) 56 | print(msg.as_string()) 57 | -------------------------------------------------------------------------------- /python3/12/mime_headers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_headers.py 3 | 4 | from email.mime.text import MIMEText 5 | from email.header import Header 6 | 7 | message = """Hello, 8 | 9 | This is a test message from Chapter 12. I hope you enjoy it! 10 | 11 | -- Anonymous""" 12 | 13 | msg = MIMEText(message) 14 | msg['To'] = 'recipient@example.com' 15 | fromhdr = Header() 16 | fromhdr.append('Michael Müller', 'iso-8859-1') # 'utf-8' is even more general 17 | fromhdr.append('') 18 | msg['From'] = fromhdr 19 | msg['Subject'] = 'Test Message, Chapter 12' 20 | 21 | print(msg.as_string()) 22 | -------------------------------------------------------------------------------- /python3/12/mime_parse_headers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_parse_headers.py 3 | 4 | import sys, email 5 | from email.header import decode_header 6 | 7 | msg = email.message_from_file(sys.stdin) 8 | for header, raw in list(msg.items()): 9 | parts = decode_header(raw) 10 | value = '' 11 | for data, charset in parts: 12 | if isinstance(data, str): 13 | value += data 14 | else: 15 | value += data.decode(charset or 'ascii') 16 | print('{0}: {1}'.format(header, value)) 17 | -------------------------------------------------------------------------------- /python3/12/mime_structure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - mime_structure.py 3 | # This program requires Python 2.2.2 or above 4 | 5 | import sys, email 6 | 7 | def printmsg(msg, level = 0): 8 | prefix = "| " * level 9 | prefix2 = prefix + "|" 10 | print(prefix + "+ Message Headers:") 11 | for header, value in list(msg.items()): 12 | print(prefix2, header + ":", value) 13 | if msg.is_multipart(): 14 | for item in msg.get_payload(): 15 | printmsg(item, level + 1) 16 | 17 | msg = email.message_from_file(sys.stdin) 18 | printmsg(msg) 19 | -------------------------------------------------------------------------------- /python3/12/test.txt: -------------------------------------------------------------------------------- 1 | This is a test 2 | -------------------------------------------------------------------------------- /python3/12/test.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/misheska/foundations-of-python-network-programming/63c0eaadc902f93f51f18e54bd5abf5f046238a5/python3/12/test.txt.gz -------------------------------------------------------------------------------- /python3/12/trad_gen_newhdrs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - trad_gen_newhdrs.py 3 | # Traditional Message Generation with Date and Message-ID 4 | # This program requires Python 2.5 or above 5 | 6 | import email.utils 7 | from email.message import Message 8 | 9 | message = """Hello, 10 | 11 | This is a test message from Chapter 12. I hope you enjoy it! 12 | 13 | -- Anonymous""" 14 | 15 | msg = Message() 16 | msg['To'] = 'recipient@example.com' 17 | msg['From'] = 'Test Sender ' 18 | msg['Subject'] = 'Test Message, Chapter 12' 19 | msg['Date'] = email.utils.formatdate(localtime = 1) 20 | msg['Message-ID'] = email.utils.make_msgid() 21 | msg.set_payload(message) 22 | 23 | print(msg.as_string()) 24 | -------------------------------------------------------------------------------- /python3/12/trad_gen_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - trad_gen_simple.py 3 | # Traditional Message Generation, Simple 4 | # This program requires Python 2.5 or above 5 | 6 | from email.message import Message 7 | text = """Hello, 8 | 9 | This is a test message from Chapter 12. I hope you enjoy it! 10 | 11 | -- Anonymous""" 12 | 13 | msg = Message() 14 | msg['To'] = 'recipient@example.com' 15 | msg['From'] = 'Test Sender ' 16 | msg['Subject'] = 'Test Message, Chapter 12' 17 | msg.set_payload(text) 18 | 19 | print(msg.as_string()) 20 | -------------------------------------------------------------------------------- /python3/12/trad_parse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 12 - trad_parse.py 3 | # Traditional Message Parsing 4 | # This program requires Python 2.5 or above 5 | 6 | import email 7 | 8 | banner = '-' * 48 9 | popular_headers = ('From', 'To', 'Subject', 'Date') 10 | msg = email.message_from_file(open('message.txt')) 11 | headers = sorted(msg.keys()) 12 | 13 | print(banner) 14 | for header in headers: 15 | if header not in popular_headers: 16 | print(header + ':', msg[header]) 17 | print(banner) 18 | for header in headers: 19 | if header in popular_headers: 20 | print(header + ':', msg[header]) 21 | 22 | print(banner) 23 | if msg.is_multipart(): 24 | print("This program cannot handle MIME multipart messages.") 25 | else: 26 | print(msg.get_payload()) 27 | -------------------------------------------------------------------------------- /python3/13/debug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with debugging - Chapter 13 - debug.py 3 | 4 | import sys, smtplib, socket 5 | 6 | if len(sys.argv) < 4: 7 | print("usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0]) 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the debug.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | try: 23 | s = smtplib.SMTP(server) 24 | s.set_debuglevel(1) 25 | s.sendmail(fromaddr, toaddrs, message) 26 | except (socket.gaierror, socket.error, socket.herror, 27 | smtplib.SMTPException) as e: 28 | print(" *** Your message may not have been sent!") 29 | print(e) 30 | sys.exit(1) 31 | else: 32 | print("Message successfully sent to %d recipient(s)" % len(toaddrs)) 33 | -------------------------------------------------------------------------------- /python3/13/ehlo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with manual EHLO - Chapter 13 - ehlo.py 3 | 4 | import sys, smtplib, socket 5 | 6 | if len(sys.argv) < 4: 7 | print("usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0]) 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the ehlo.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | try: 23 | s = smtplib.SMTP(server) 24 | code = s.ehlo()[0] 25 | uses_esmtp = (200 <= code <= 299) 26 | if not uses_esmtp: 27 | code = s.helo()[0] 28 | if not (200 <= code <= 299): 29 | print("Remote server refused HELO; code:", code) 30 | sys.exit(1) 31 | 32 | if uses_esmtp and s.has_extn('size'): 33 | print("Maximum message size is", s.esmtp_features['size']) 34 | if len(message) > int(s.esmtp_features['size']): 35 | print("Message too large; aborting.") 36 | sys.exit(1) 37 | 38 | s.sendmail(fromaddr, toaddrs, message) 39 | 40 | except (socket.gaierror, socket.error, socket.herror, 41 | smtplib.SMTPException) as e: 42 | print(" *** Your message may not have been sent!") 43 | print(e) 44 | sys.exit(1) 45 | else: 46 | print("Message successfully sent to %d recipient(s)" % len(toaddrs)) 47 | -------------------------------------------------------------------------------- /python3/13/login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with authentication - Chapter 13 - login.py 3 | 4 | import sys, smtplib, socket 5 | from getpass import getpass 6 | 7 | if len(sys.argv) < 4: 8 | print("Syntax: %s server fromaddr toaddr [toaddr...]" % sys.argv[0]) 9 | sys.exit(2) 10 | 11 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 12 | 13 | message = """To: %s 14 | From: %s 15 | Subject: Test Message from simple.py 16 | 17 | Hello, 18 | 19 | This is a test message sent to you from the login.py program 20 | in Foundations of Python Network Programming. 21 | """ % (', '.join(toaddrs), fromaddr) 22 | 23 | print("Enter username: ") 24 | username = sys.stdin.readline().strip() 25 | password = getpass("Enter password: ") 26 | 27 | try: 28 | s = smtplib.SMTP(server) 29 | try: 30 | s.login(username, password) 31 | except smtplib.SMTPException as e: 32 | print("Authentication failed:", e) 33 | sys.exit(1) 34 | s.sendmail(fromaddr, toaddrs, message) 35 | except (socket.gaierror, socket.error, socket.herror, 36 | smtplib.SMTPException) as e: 37 | print(" *** Your message may not have been sent!") 38 | print(e) 39 | sys.exit(1) 40 | else: 41 | print("Message successfully sent to %d recipient(s)" % len(toaddrs)) 42 | -------------------------------------------------------------------------------- /python3/13/simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Basic SMTP transmission - Chapter 13 - simple.py 3 | 4 | import sys, smtplib 5 | 6 | if len(sys.argv) < 4: 7 | print("usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0]) 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the simple.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | s = smtplib.SMTP(server) 23 | s.sendmail(fromaddr, toaddrs, message) 24 | 25 | print("Message successfully sent to %d recipient(s)" % len(toaddrs)) 26 | -------------------------------------------------------------------------------- /python3/13/tls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # SMTP transmission with TLS - Chapter 13 - tls.py 3 | 4 | import sys, smtplib, socket 5 | 6 | if len(sys.argv) < 4: 7 | print("Syntax: %s server fromaddr toaddr [toaddr...]" % sys.argv[0]) 8 | sys.exit(2) 9 | 10 | server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:] 11 | 12 | message = """To: %s 13 | From: %s 14 | Subject: Test Message from simple.py 15 | 16 | Hello, 17 | 18 | This is a test message sent to you from the tls.py program 19 | in Foundations of Python Network Programming. 20 | """ % (', '.join(toaddrs), fromaddr) 21 | 22 | try: 23 | s = smtplib.SMTP(server) 24 | code = s.ehlo()[0] 25 | uses_esmtp = (200 <= code <= 299) 26 | if not uses_esmtp: 27 | code = s.helo()[0] 28 | if not (200 <= code <= 299): 29 | print("Remove server refused HELO; code:", code) 30 | sys.exit(1) 31 | 32 | if uses_esmtp and s.has_extn('starttls'): 33 | print("Negotiating TLS....") 34 | s.starttls() 35 | code = s.ehlo()[0] 36 | if not (200 <= code <= 299): 37 | print("Couldn't EHLO after STARTTLS") 38 | sys.exit(5) 39 | print("Using TLS connection.") 40 | else: 41 | print("Server does not support TLS; using normal connection.") 42 | s.sendmail(fromaddr, toaddrs, message) 43 | 44 | except (socket.gaierror, socket.error, socket.herror, 45 | smtplib.SMTPException) as e: 46 | print(" *** Your message may not have been sent!") 47 | print(e) 48 | sys.exit(1) 49 | else: 50 | print("Message successfully sent to %d recipient(s)" % len(toaddrs)) 51 | -------------------------------------------------------------------------------- /python3/14/download-and-delete.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # POP mailbox downloader with deletion - Chapter 14 3 | # download-and-delete.py 4 | 5 | import email, getpass, poplib, sys 6 | 7 | if len(sys.argv) != 3: 8 | print('usage: %s hostname user' % sys.argv[0]) 9 | exit(2) 10 | 11 | hostname, user = sys.argv[1:] 12 | passwd = getpass.getpass() 13 | 14 | p = poplib.POP3_SSL(hostname) 15 | try: 16 | p.user(user) 17 | p.pass_(passwd) 18 | except poplib.error_proto as e: 19 | print("Login failed:", e) 20 | else: 21 | response, listings, octets = p.list() 22 | for listing in listings: 23 | number, size = listing.decode('ascii').split() 24 | print('Message', number, '(size is', size, 'bytes):') 25 | print() 26 | response, lines, octets = p.top(number, 0) 27 | document = '\n'.join( line.decode('ascii') for line in lines ) 28 | message = email.message_from_string(document) 29 | for header in 'From', 'To', 'Subject', 'Date': 30 | if header in message: 31 | print(header + ':', message[header]) 32 | print() 33 | print('Read this message [ny]?') 34 | answer = input() 35 | if answer.lower().startswith('y'): 36 | response, lines, octets = p.retr(number) 37 | document = '\n'.join( line.decode('ascii') for line in lines ) 38 | message = email.message_from_string(document) 39 | print('-' * 72) 40 | for part in message.walk(): 41 | if part.get_content_type() == 'text/plain': 42 | print(part.get_payload()) 43 | print('-' * 72) 44 | print() 45 | print('Delete this message [ny]?') 46 | answer = input() 47 | if answer.lower().startswith('y'): 48 | p.dele(number) 49 | print('Deleted.') 50 | finally: 51 | p.quit() 52 | -------------------------------------------------------------------------------- /python3/14/mailbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # POP mailbox scanning - Chapter 14 - mailbox.py 3 | 4 | import getpass, poplib, sys 5 | 6 | if len(sys.argv) != 3: 7 | print('usage: %s hostname user' % sys.argv[0]) 8 | exit(2) 9 | 10 | hostname, user = sys.argv[1:] 11 | passwd = getpass.getpass() 12 | 13 | p = poplib.POP3_SSL(hostname) 14 | try: 15 | p.user(user) 16 | p.pass_(passwd) 17 | except poplib.error_proto as e: 18 | print("Login failed:", e) 19 | else: 20 | response, listings, octet_count = p.list() 21 | for listing in listings: 22 | number, size = listing.decode('ascii').split() 23 | print("Message %s has %s bytes" % (number, size)) 24 | finally: 25 | p.quit() 26 | -------------------------------------------------------------------------------- /python3/14/popconn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # POP connection and authentication - Chapter 14 - popconn.py 3 | 4 | import getpass, poplib, sys 5 | 6 | if len(sys.argv) != 3: 7 | print('usage: %s hostname user' % sys.argv[0]) 8 | exit(2) 9 | 10 | hostname, user = sys.argv[1:] 11 | passwd = getpass.getpass() 12 | 13 | p = poplib.POP3_SSL(hostname) # or "POP3" if SSL is not supported 14 | try: 15 | p.user(user) 16 | p.pass_(passwd) 17 | except poplib.error_proto as e: 18 | print("Login failed:", e) 19 | else: 20 | status = p.stat() 21 | print("You have %d messages totaling %d bytes" % status) 22 | finally: 23 | p.quit() 24 | -------------------------------------------------------------------------------- /python3/15/folder_info.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - folder_info.py 3 | # Opening an IMAP connection with IMAPClient and listing folder information. 4 | 5 | import getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username = sys.argv[1:] 10 | except ValueError: 11 | print('usage: %s hostname username' % sys.argv[0]) 12 | sys.exit(2) 13 | 14 | c = IMAPClient(hostname, ssl=True) 15 | try: 16 | c.login(username, getpass.getpass()) 17 | except c.Error as e: 18 | print('Could not log in:', e) 19 | sys.exit(1) 20 | else: 21 | select_dict = c.select_folder('INBOX', readonly=True) 22 | for k, v in list(select_dict.items()): 23 | print('%s: %r' % (k, v)) 24 | c.logout() 25 | -------------------------------------------------------------------------------- /python3/15/mailbox_summary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - mailbox_summary.py 3 | # Opening an IMAP connection with IMAPClient and retrieving mailbox messages. 4 | 5 | import email, getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username, foldername = sys.argv[1:] 10 | except ValueError: 11 | print('usage: %s hostname username folder' % sys.argv[0]) 12 | sys.exit(2) 13 | 14 | c = IMAPClient(hostname, ssl=True) 15 | try: 16 | c.login(username, getpass.getpass()) 17 | except c.Error as e: 18 | print('Could not log in:', e) 19 | sys.exit(1) 20 | 21 | c.select_folder(foldername, readonly=True) 22 | msgdict = c.fetch('1:*', ['BODY.PEEK[]']) 23 | for message_id, message in list(msgdict.items()): 24 | e = email.message_from_string(message['BODY[]']) 25 | print(message_id, e['From']) 26 | payload = e.get_payload() 27 | if isinstance(payload, list): 28 | part_content_types = [ part.get_content_type() for part in payload ] 29 | print(' Parts:', ' '.join(part_content_types)) 30 | else: 31 | print(' ', ' '.join(payload[:60].split()), '...') 32 | 33 | c.logout() 34 | -------------------------------------------------------------------------------- /python3/15/open_imap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - open_imap.py 3 | # Opening an IMAP connection with the powerful IMAPClient 4 | 5 | import getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username = sys.argv[1:] 10 | except ValueError: 11 | print('usage: %s hostname username' % sys.argv[0]) 12 | sys.exit(2) 13 | 14 | c = IMAPClient(hostname, ssl=True) 15 | try: 16 | c.login(username, getpass.getpass()) 17 | except c.Error as e: 18 | print('Could not log in:', e) 19 | sys.exit(1) 20 | 21 | print('Capabilities:', c.capabilities()) 22 | print('Listing mailboxes:') 23 | data = c.list_folders() 24 | for flags, delimiter, folder_name in data: 25 | print(' %-30s%s %s' % (' '.join(flags), delimiter, folder_name)) 26 | c.logout() 27 | -------------------------------------------------------------------------------- /python3/15/open_imap.txt: -------------------------------------------------------------------------------- 1 | Capabilities: ('IMAP4REV1', 'UNSELECT', 'IDLE', 'NAMESPACE', 'QUOTA', 'XLIST', 'CHILDREN', 'XYZZY', 'SASL-IR', 'AUTH=XOAUTH') 2 | Listing mailboxes: 3 | \HasNoChildren / INBOX 4 | \HasNoChildren / Personal 5 | \HasNoChildren / Receipts 6 | \HasNoChildren / Travel 7 | \HasNoChildren / Work 8 | \Noselect \HasChildren / [Gmail] 9 | \HasChildren \HasNoChildren / [Gmail]/All Mail 10 | \HasNoChildren / [Gmail]/Drafts 11 | \HasChildren \HasNoChildren / [Gmail]/Sent Mail 12 | \HasNoChildren / [Gmail]/Spam 13 | \HasNoChildren / [Gmail]/Starred 14 | \HasChildren \HasNoChildren / [Gmail]/Trash 15 | -------------------------------------------------------------------------------- /python3/15/open_imaplib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - open_imaplib.py 3 | # Opening an IMAP connection with the pitiful Python Standard Library 4 | 5 | import getpass, imaplib, sys 6 | 7 | try: 8 | hostname, username = sys.argv[1:] 9 | except ValueError: 10 | print('usage: %s hostname username' % sys.argv[0]) 11 | sys.exit(2) 12 | 13 | m = imaplib.IMAP4_SSL(hostname) 14 | m.login(username, getpass.getpass()) 15 | print('Capabilities:', m.capabilities) 16 | print('Listing mailboxes ') 17 | status, data = m.list() 18 | print('Status:', repr(status)) 19 | print('Data:') 20 | for datum in data: 21 | print(repr(datum)) 22 | m.logout() 23 | -------------------------------------------------------------------------------- /python3/15/open_imaplib.txt: -------------------------------------------------------------------------------- 1 | Capabilities: ('IMAP4REV1', 'UNSELECT', 'IDLE', 'NAMESPACE', 'QUOTA', 2 | 'XLIST', 'CHILDREN', 'XYZZY', 'SASL-IR', 'AUTH=XOAUTH') 3 | Listing mailboxes 4 | Status: 'OK' 5 | Data: 6 | '(\\HasNoChildren) "/" "INBOX"' 7 | '(\\HasNoChildren) "/" "Personal"' 8 | '(\\HasNoChildren) "/" "Receipts"' 9 | '(\\HasNoChildren) "/" "Travel"' 10 | '(\\HasNoChildren) "/" "Work"' 11 | '(\\Noselect \\HasChildren) "/" "[Gmail]"' 12 | '(\\HasChildren \\HasNoChildren) "/" "[Gmail]/All Mail"' 13 | '(\\HasNoChildren) "/" "[Gmail]/Drafts"' 14 | '(\\HasChildren \\HasNoChildren) "/" "[Gmail]/Sent Mail"' 15 | '(\\HasNoChildren) "/" "[Gmail]/Spam"' 16 | '(\\HasNoChildren) "/" "[Gmail]/Starred"' 17 | '(\\HasChildren \\HasNoChildren) "/" "[Gmail]/Trash"' 18 | -------------------------------------------------------------------------------- /python3/15/simple_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 15 - simple_client.py 3 | # Letting a user browse folders, messages, and message parts. 4 | 5 | import getpass, sys 6 | from imapclient import IMAPClient 7 | 8 | try: 9 | hostname, username = sys.argv[1:] 10 | except ValueError: 11 | print('usage: %s hostname username' % sys.argv[0]) 12 | sys.exit(2) 13 | 14 | banner = '-' * 72 15 | 16 | c = IMAPClient(hostname, ssl=True) 17 | try: 18 | c.login(username, getpass.getpass()) 19 | except c.Error as e: 20 | print('Could not log in:', e) 21 | sys.exit(1) 22 | 23 | def display_structure(structure, parentparts=[]): 24 | """Attractively display a given message structure.""" 25 | 26 | # The whole body of the message is named 'TEXT'. 27 | 28 | if parentparts: 29 | name = '.'.join(parentparts) 30 | else: 31 | print('HEADER') 32 | name = 'TEXT' 33 | 34 | # Print this part's designation and its MIME type. 35 | 36 | is_multipart = isinstance(structure[0], list) 37 | if is_multipart: 38 | parttype = 'multipart/%s' % structure[1].lower() 39 | else: 40 | parttype = ('%s/%s' % structure[:2]).lower() 41 | print('%-9s' % name, parttype, end=' ') 42 | 43 | # For a multipart part, print all of its subordinate parts; for 44 | # other parts, print their disposition (if available). 45 | 46 | if is_multipart: 47 | print() 48 | subparts = structure[0] 49 | for i in range(len(subparts)): 50 | display_structure(subparts[i], parentparts + [ str(i + 1) ]) 51 | else: 52 | if structure[6]: 53 | print('size=%s' % structure[6], end=' ') 54 | if structure[8]: 55 | disposition, namevalues = structure[8] 56 | print(disposition, end=' ') 57 | for i in range(0, len(namevalues), 2): 58 | print('%s=%r' % namevalues[i:i+2]) 59 | print() 60 | 61 | def explore_message(c, uid): 62 | """Let the user view various parts of a given message.""" 63 | 64 | msgdict = c.fetch(uid, ['BODYSTRUCTURE', 'FLAGS']) 65 | 66 | while True: 67 | print() 68 | print('Flags:', end=' ') 69 | flaglist = msgdict[uid]['FLAGS'] 70 | if flaglist: 71 | print(' '.join(flaglist)) 72 | else: 73 | print('none') 74 | display_structure(msgdict[uid]['BODYSTRUCTURE']) 75 | print() 76 | reply = input('Message %s - type a part name, or "q" to quit: ' 77 | % uid).strip() 78 | print() 79 | if reply.lower().startswith('q'): 80 | break 81 | key = 'BODY[%s]' % reply 82 | try: 83 | msgdict2 = c.fetch(uid, [key]) 84 | except c._imap.error: 85 | print('Error - cannot fetch section %r' % reply) 86 | else: 87 | content = msgdict2[uid][key] 88 | if content: 89 | print(banner) 90 | print(content.strip()) 91 | print(banner) 92 | else: 93 | print('(No such section)') 94 | 95 | def explore_folder(c, name): 96 | """List the messages in folder `name` and let the user choose one.""" 97 | 98 | while True: 99 | c.select_folder(name, readonly=True) 100 | msgdict = c.fetch('1:*', ['BODY.PEEK[HEADER.FIELDS (FROM SUBJECT)]', 101 | 'FLAGS', 'INTERNALDATE', 'RFC822.SIZE']) 102 | print() 103 | for uid in sorted(msgdict): 104 | items = msgdict[uid] 105 | print('%6d %20s %6d bytes %s' % ( 106 | uid, items['INTERNALDATE'], items['RFC822.SIZE'], 107 | ' '.join(items['FLAGS']))) 108 | for i in items['BODY[HEADER.FIELDS (FROM SUBJECT)]'].splitlines(): 109 | print(' ' * 6, i.strip()) 110 | 111 | reply = input('Folder %s - type a message UID, or "q" to quit: ' 112 | % name).strip() 113 | if reply.lower().startswith('q'): 114 | break 115 | try: 116 | reply = int(reply) 117 | except ValueError: 118 | print('Please type an integer or "q" to quit') 119 | else: 120 | if reply in msgdict: 121 | explore_message(c, reply) 122 | 123 | c.close_folder() 124 | 125 | def explore_account(c): 126 | """Display the folders in this IMAP account and let the user choose one.""" 127 | 128 | while True: 129 | 130 | print() 131 | folderflags = {} 132 | data = c.list_folders() 133 | for flags, delimiter, name in data: 134 | folderflags[name] = flags 135 | for name in sorted(folderflags.keys()): 136 | print('%-30s %s' % (name, ' '.join(folderflags[name]))) 137 | print() 138 | 139 | reply = input('Type a folder name, or "q" to quit: ').strip() 140 | if reply.lower().startswith('q'): 141 | break 142 | if reply in folderflags: 143 | explore_folder(c, reply) 144 | else: 145 | print('Error: no folder named', repr(reply)) 146 | 147 | if __name__ == '__main__': 148 | explore_account(c) 149 | -------------------------------------------------------------------------------- /python3/16/fabfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - fabfile.py 3 | # A sample Fabric script 4 | 5 | # Even though this chapter will not cover Fabric, you might want to try 6 | # using Fabric to automate your SSH commands instead of re-inventing the 7 | # wheel. Here is a script that checks for Python on remote machines. 8 | # Fabric finds this "fabfile.py" automatically if you are in the same 9 | # directory. Try running both verbosely, and with most messages off: 10 | # 11 | # $ fab versions:host=server.example.com 12 | # $ fab --hide=everything versions:host=server.example.com 13 | 14 | from fabric.api import * 15 | 16 | def versions(): 17 | with cd('/usr/bin'): 18 | with settings(hide('warnings'), warn_only=True): 19 | for version in '2.4', '2.5', '2.6', '2.7', '3.0', '3.1': 20 | result = run('python%s -c "None"' % version) 21 | if not result.failed: 22 | print("Host", env.host, "has Python", version) 23 | -------------------------------------------------------------------------------- /python3/16/sftp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - sftp.py 3 | # Fetching files with SFTP 4 | 5 | import functools 6 | import paramiko 7 | 8 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 9 | def missing_host_key(self, client, hostname, key): 10 | return 11 | 12 | client = paramiko.SSHClient() 13 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 14 | client.connect('127.0.0.1', username='test') # password='') 15 | 16 | def my_callback(filename, bytes_so_far, bytes_total): 17 | print('Transfer of %r is at %d/%d bytes (%.1f%%)' % ( 18 | filename, bytes_so_far, bytes_total, 100. * bytes_so_far / bytes_total)) 19 | 20 | sftp = client.open_sftp() 21 | sftp.chdir('/var/log') 22 | for filename in sorted(sftp.listdir()): 23 | if filename.startswith('messages.'): 24 | callback_for_filename = functools.partial(my_callback, filename) 25 | sftp.get(filename, filename, callback=callback_for_filename) 26 | 27 | client.close() 28 | -------------------------------------------------------------------------------- /python3/16/shell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - shell.py 3 | # A simple shell, so you can try running commands in the absence of 4 | # any special characters (except for whitespace, used for splitting). 5 | 6 | import subprocess 7 | 8 | while True: 9 | args = input('] ').split() 10 | if not args: 11 | pass 12 | elif args == ['exit']: 13 | break 14 | elif args[0] == 'show': 15 | print("Arguments:", args[1:]) 16 | else: 17 | subprocess.call(args) 18 | -------------------------------------------------------------------------------- /python3/16/ssh_commands.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - ssh_commands.py 3 | # Running separate commands instead of using a shell 4 | 5 | import paramiko 6 | 7 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 8 | def missing_host_key(self, client, hostname, key): 9 | return 10 | 11 | client = paramiko.SSHClient() 12 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 13 | client.connect('127.0.0.1', username='test') # password='') 14 | 15 | for command in 'echo "Hello, world!"', 'uname', 'uptime': 16 | stdin, stdout, stderr = client.exec_command(command) 17 | stdin.close() 18 | print(repr(stdout.read())) 19 | stdout.close() 20 | stderr.close() 21 | 22 | client.close() 23 | -------------------------------------------------------------------------------- /python3/16/ssh_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - ssh_simple.py 3 | # Using SSH like Telnet: connecting and running two commands 4 | 5 | import paramiko 6 | 7 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 8 | def missing_host_key(self, client, hostname, key): 9 | return 10 | 11 | client = paramiko.SSHClient() 12 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 13 | client.connect('127.0.0.1', username='test') # password='') 14 | 15 | channel = client.invoke_shell() 16 | stdin = channel.makefile('wb') 17 | stdout = channel.makefile('rb') 18 | 19 | stdin.write('echo Hello, world\rexit\r') 20 | print(stdout.read()) 21 | 22 | client.close() 23 | -------------------------------------------------------------------------------- /python3/16/ssh_simple.txt: -------------------------------------------------------------------------------- 1 | Linux guinness 2.6.32-24-generic #42-Ubuntu SMP Fri Aug 20 14:24:04 UTC 2 | 2010 i686 GNU/Linux 3 | Ubuntu 10.04.1 LTS 4 | 5 | Welcome to Ubuntu! 6 | * Documentation: https://help.ubuntu.com/ 7 | 8 | Last login: Mon Sep 6 01:02:46 2010 from localhost 9 | echo Hello, world 10 | exit 11 | test@guinness:~$ echo Hello, world 12 | Hello, world 13 | test@guinness:~$ exit 14 | logout 15 | -------------------------------------------------------------------------------- /python3/16/ssh_threads.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - ssh_threads.py 3 | # Running two remote commands simultaneously in different channels 4 | 5 | import threading 6 | import paramiko 7 | 8 | class AllowAnythingPolicy(paramiko.MissingHostKeyPolicy): 9 | def missing_host_key(self, client, hostname, key): 10 | return 11 | 12 | client = paramiko.SSHClient() 13 | client.set_missing_host_key_policy(AllowAnythingPolicy()) 14 | client.connect('127.0.0.1', username='test') # password='') 15 | 16 | def read_until_EOF(fileobj): 17 | s = fileobj.readline() 18 | while s: 19 | print(s.strip()) 20 | s = fileobj.readline() 21 | 22 | out1 = client.exec_command('echo One;sleep 2;echo Two;sleep 1;echo Three')[1] 23 | out2 = client.exec_command('echo A;sleep 1;echo B;sleep 2;echo C')[1] 24 | thread1 = threading.Thread(target=read_until_EOF, args=(out1,)) 25 | thread2 = threading.Thread(target=read_until_EOF, args=(out2,)) 26 | thread1.start() 27 | thread2.start() 28 | thread1.join() 29 | thread2.join() 30 | 31 | client.close() 32 | -------------------------------------------------------------------------------- /python3/16/telnet_codes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - telnet_codes.py 3 | # How your code might look if you intercept Telnet options yourself 4 | 5 | from telnetlib import Telnet, IAC, DO, DONT, WILL, WONT, SB, SE, TTYPE 6 | 7 | def process_option(tsocket, command, option): 8 | if command == DO and option == TTYPE: 9 | tsocket.sendall(IAC + WILL + TTYPE) 10 | print('Sending terminal type "mypython"') 11 | tsocket.sendall(IAC + SB + TTYPE + b'\0' + b'mypython' + IAC + SE) 12 | elif command in (DO, DONT): 13 | print('Will not', ord(option)) 14 | tsocket.sendall(IAC + WONT + option) 15 | elif command in (WILL, WONT): 16 | print('Do not', ord(option)) 17 | tsocket.sendall(IAC + DONT + option) 18 | 19 | t = Telnet('localhost') 20 | # t.set_debuglevel(1) # uncomment this for debugging messages 21 | 22 | t.set_option_negotiation_callback(process_option) 23 | t.read_until(b'login:', 5) 24 | t.write(b'brandon\n') 25 | t.read_until(b'assword:', 5) # so P can be capitalized or not 26 | t.write(b'mypass\n') 27 | n, match, previous_text = t.expect([br'Login incorrect', br'\$'], 10) 28 | if n == 0: 29 | print("Username and password failed - giving up") 30 | else: 31 | t.write(b'exec echo My terminal type is $TERM\n') 32 | print(t.read_all().decode('ascii')) 33 | -------------------------------------------------------------------------------- /python3/16/telnet_login.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 16 - telnet_login.py 3 | # Connect to localhost, watch for a login prompt, and try logging in 4 | 5 | import telnetlib 6 | 7 | t = telnetlib.Telnet('localhost') 8 | # t.set_debuglevel(1) # uncomment this for debugging messages 9 | 10 | t.read_until(b'login:') 11 | t.write(b'brandon\n') 12 | t.read_until(b'assword:') # let "P" be capitalized or not 13 | t.write(b'mypass\n') 14 | n, match, previous_text = t.expect([br'Login incorrect', br'\$'], 10) 15 | if n == 0: 16 | print(b'Username and password failed - giving up') 17 | else: 18 | t.write(b'exec uptime\n') 19 | print(t.read_all().decode('ascii')) # read until connection closes 20 | -------------------------------------------------------------------------------- /python3/17/advbinarydl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Advanced binary download - Chapter 17 - advbinarydl.py 3 | 4 | import os, sys 5 | from ftplib import FTP 6 | 7 | if os.path.exists('linux-1.0.tar.gz'): 8 | raise IOError('refusing to overwrite your linux-1.0.tar.gz file') 9 | 10 | f = FTP('ftp.kernel.org') 11 | f.login() 12 | 13 | f.cwd('/pub/linux/kernel/v1.0') 14 | f.voidcmd("TYPE I") 15 | 16 | datasock, size = f.ntransfercmd("RETR linux-1.0.tar.gz") 17 | bytes_so_far = 0 18 | fd = open('linux-1.0.tar.gz', 'wb') 19 | 20 | while 1: 21 | buf = datasock.recv(2048) 22 | if not buf: 23 | break 24 | fd.write(buf) 25 | bytes_so_far += len(buf) 26 | print("\rReceived", bytes_so_far, end=' ') 27 | if size: 28 | print("of %d total bytes (%.1f%%)" % ( 29 | size, 100 * bytes_so_far / float(size)), end=' ') 30 | else: 31 | print("bytes", end=' ') 32 | sys.stdout.flush() 33 | 34 | print() 35 | fd.close() 36 | datasock.close() 37 | f.voidresp() 38 | f.quit() 39 | -------------------------------------------------------------------------------- /python3/17/advbinaryul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Advanced binary upload - Chapter 17 - advbinaryul.py 3 | 4 | from ftplib import FTP 5 | import sys, getpass, os.path 6 | 7 | BLOCKSIZE = 8192 # chunk size to read and transmit: 8 kB 8 | 9 | if len(sys.argv) != 5: 10 | print("usage: %s " % ( 11 | sys.argv[0])) 12 | exit(2) 13 | 14 | host, username, localfile, remotedir = sys.argv[1:] 15 | password = getpass.getpass("Enter password for %s on %s: " % \ 16 | (username, host)) 17 | f = FTP(host) 18 | f.login(username, password) 19 | 20 | f.cwd(remotedir) 21 | f.voidcmd("TYPE I") 22 | 23 | fd = open(localfile, 'rb') 24 | datasock, esize = f.ntransfercmd('STOR %s' % os.path.basename(localfile)) 25 | size = os.stat(localfile)[6] 26 | bytes_so_far = 0 27 | 28 | while 1: 29 | buf = fd.read(BLOCKSIZE) 30 | if not buf: 31 | break 32 | datasock.sendall(buf) 33 | bytes_so_far += len(buf) 34 | print("\rSent", bytes_so_far, "of", size, "bytes", \ 35 | "(%.1f%%)\r" % (100 * bytes_so_far / float(size))) 36 | sys.stdout.flush() 37 | 38 | print() 39 | datasock.close() 40 | fd.close() 41 | f.voidresp() 42 | f.quit() 43 | -------------------------------------------------------------------------------- /python3/17/asciidl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # ASCII download - Chapter 17 - asciidl.py 3 | # Downloads README from remote and writes it to disk. 4 | 5 | import os 6 | from ftplib import FTP 7 | 8 | if os.path.exists('README'): 9 | raise IOError('refusing to overwrite your README file') 10 | 11 | def writeline(data): 12 | fd.write(data) 13 | fd.write(os.linesep) 14 | 15 | f = FTP('ftp.kernel.org') 16 | f.login() 17 | f.cwd('/pub/linux/kernel') 18 | 19 | fd = open('README', 'w') 20 | f.retrlines('RETR README', writeline) 21 | fd.close() 22 | 23 | f.quit() 24 | -------------------------------------------------------------------------------- /python3/17/binarydl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Binary upload - Chapter 17 - binarydl.py 3 | 4 | import os 5 | from ftplib import FTP 6 | 7 | if os.path.exists('patch8.gz'): 8 | raise IOError('refusing to overwrite your patch8.gz file') 9 | 10 | f = FTP('ftp.kernel.org') 11 | f.login() 12 | f.cwd('/pub/linux/kernel/v1.0') 13 | 14 | fd = open('patch8.gz', 'wb') 15 | f.retrbinary('RETR patch8.gz', fd.write) 16 | fd.close() 17 | 18 | f.quit() 19 | -------------------------------------------------------------------------------- /python3/17/binaryul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Binary download - Chapter 17 - binaryul.py 3 | 4 | from ftplib import FTP 5 | import sys, getpass, os.path 6 | 7 | if len(sys.argv) != 5: 8 | print("usage: %s " % ( 9 | sys.argv[0])) 10 | exit(2) 11 | 12 | host, username, localfile, remotedir = sys.argv[1:] 13 | password = getpass.getpass( 14 | "Enter password for %s on %s: " % (username, host)) 15 | 16 | f = FTP(host) 17 | f.login(username, password) 18 | f.cwd(remotedir) 19 | 20 | fd = open(localfile, 'rb') 21 | f.storbinary('STOR %s' % os.path.basename(localfile), fd) 22 | fd.close() 23 | 24 | f.quit() 25 | -------------------------------------------------------------------------------- /python3/17/connect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Basic connection - Chapter 17 - connect.py 3 | 4 | from ftplib import FTP 5 | 6 | f = FTP('ftp.ibiblio.org') 7 | print("Welcome:", f.getwelcome()) 8 | f.login() 9 | 10 | print("Current working directory:", f.pwd()) 11 | f.quit() 12 | -------------------------------------------------------------------------------- /python3/17/dir.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # dir() example - Chapter 17 - dir.py 3 | 4 | from ftplib import FTP 5 | 6 | f = FTP('ftp.ibiblio.org') 7 | f.login() 8 | f.cwd('/pub/academic/astronomy/') 9 | entries = [] 10 | f.dir(entries.append) 11 | print("%d entries:" % len(entries)) 12 | for entry in entries: 13 | print(entry) 14 | f.quit() 15 | -------------------------------------------------------------------------------- /python3/17/nlst.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # NLST example - Chapter 17 - nlst.py 3 | 4 | from ftplib import FTP 5 | 6 | f = FTP('ftp.ibiblio.org') 7 | f.login() 8 | f.cwd('/pub/academic/astronomy/') 9 | entries = f.nlst() 10 | entries.sort() 11 | print(len(entries), "entries:") 12 | for entry in entries: 13 | print(entry) 14 | f.quit() 15 | -------------------------------------------------------------------------------- /python3/17/recursedl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Recursive downloader - Chapter 17 - recursedl.py 3 | 4 | import os, sys 5 | from ftplib import FTP, error_perm 6 | 7 | def walk_dir(f, dirpath): 8 | original_dir = f.pwd() 9 | try: 10 | f.cwd(dirpath) 11 | except error_perm: 12 | return # ignore non-directores and ones we cannot enter 13 | print(dirpath) 14 | names = f.nlst() 15 | for name in names: 16 | walk_dir(f, dirpath + '/' + name) 17 | f.cwd(original_dir) # return to cwd of our caller 18 | 19 | f = FTP('ftp.kernel.org') 20 | f.login() 21 | walk_dir(f, '/pub/linux/kernel/Historic/old-versions') 22 | f.quit() 23 | -------------------------------------------------------------------------------- /python3/18/jsonrpc_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - jsonrpc_client.py 3 | # JSON-RPC client 4 | 5 | from lovely.jsonrpc import proxy 6 | proxy = proxy.ServerProxy('http://localhost:7002') 7 | print(proxy.lengths((1,2,3), 27, {'Sirius': -1.46, 'Rigel': 0.12})) 8 | -------------------------------------------------------------------------------- /python3/18/jsonrpc_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - jsonrpc_server.py 3 | # JSON-RPC server 4 | 5 | from wsgiref.simple_server import make_server 6 | import lovely.jsonrpc.dispatcher, lovely.jsonrpc.wsgi 7 | 8 | def lengths(*args): 9 | results = [] 10 | for arg in args: 11 | try: 12 | arglen = len(arg) 13 | except TypeError: 14 | arglen = None 15 | results.append((arglen, arg)) 16 | return results 17 | 18 | dispatcher = lovely.jsonrpc.dispatcher.JSONRPCDispatcher() 19 | dispatcher.register_method(lengths) 20 | app = lovely.jsonrpc.wsgi.WSGIJSONRPCApplication({'': dispatcher}) 21 | server = make_server('localhost', 7002, app) 22 | print("Starting server") 23 | while True: 24 | server.handle_request() 25 | -------------------------------------------------------------------------------- /python3/18/rpyc_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - rpyc_client.py 3 | # RPyC client 4 | 5 | import rpyc 6 | 7 | def noisy(string): 8 | print('Noisy:', repr(string)) 9 | 10 | proxy = rpyc.connect('localhost', 18861, config={'allow_public_attrs': True}) 11 | fileobj = open('testfile.txt') 12 | linecount = proxy.root.line_counter(fileobj, noisy) 13 | print('The number of lines in the file was', linecount) 14 | -------------------------------------------------------------------------------- /python3/18/rpyc_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - rpyc_server.py 3 | # RPyC server 4 | 5 | import rpyc 6 | 7 | class MyService(rpyc.Service): 8 | def exposed_line_counter(self, fileobj, function): 9 | for linenum, line in enumerate(fileobj.readlines()): 10 | function(line) 11 | return linenum + 1 12 | 13 | from rpyc.utils.server import ThreadedServer 14 | t = ThreadedServer(MyService, port = 18861) 15 | t.start() 16 | -------------------------------------------------------------------------------- /python3/18/testfile.txt: -------------------------------------------------------------------------------- 1 | Simple 2 | is 3 | better 4 | than 5 | complex. 6 | -------------------------------------------------------------------------------- /python3/18/xmlrpc_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_client.py 4 | # XML-RPC client 5 | 6 | import xmlrpc.client 7 | proxy = xmlrpc.client.ServerProxy('http://127.0.0.1:7001') 8 | print(proxy.addtogether('x', 'ÿ', 'z')) 9 | print(proxy.addtogether(20, 30, 4, 1)) 10 | print(proxy.quadratic(2, -4, 0)) 11 | print(proxy.quadratic(1, 2, 1)) 12 | print(proxy.remote_repr((1, 2.0, 'three'))) 13 | print(proxy.remote_repr([1, 2.0, 'three'])) 14 | print(proxy.remote_repr({'name': 'Arthur', 'data': {'age': 42, 'sex': 'M'}})) 15 | print(proxy.quadratic(1, 0, 1)) 16 | -------------------------------------------------------------------------------- /python3/18/xmlrpc_introspect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_introspect.py 3 | # XML-RPC client 4 | 5 | import xmlrpc.client 6 | proxy = xmlrpc.client.ServerProxy('http://127.0.0.1:7001') 7 | 8 | print('Here are the functions supported by this server:') 9 | for method_name in proxy.system.listMethods(): 10 | 11 | if method_name.startswith('system.'): 12 | continue 13 | 14 | signatures = proxy.system.methodSignature(method_name) 15 | if isinstance(signatures, list) and signatures: 16 | for signature in signatures: 17 | print('%s(%s)' % (method_name, signature)) 18 | else: 19 | print('%s(...)' % (method_name,)) 20 | 21 | method_help = proxy.system.methodHelp(method_name) 22 | if method_help: 23 | print(' ', method_help) 24 | -------------------------------------------------------------------------------- /python3/18/xmlrpc_multicall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_multicall.py 3 | # XML-RPC client performing a multicall 4 | 5 | import xmlrpc.client 6 | proxy = xmlrpc.client.ServerProxy('http://127.0.0.1:7001') 7 | multicall = xmlrpc.client.MultiCall(proxy) 8 | multicall.addtogether('a', 'b', 'c') 9 | multicall.quadratic(2, -4, 0) 10 | multicall.remote_repr([1, 2.0, 'three']) 11 | for answer in multicall(): 12 | print(answer) 13 | -------------------------------------------------------------------------------- /python3/18/xmlrpc_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Foundations of Python Network Programming - Chapter 18 - xmlrpc_server.py 3 | # XML-RPC server 4 | 5 | import operator, math 6 | from xmlrpc.server import SimpleXMLRPCServer 7 | from functools import reduce 8 | 9 | def addtogether(*things): 10 | """Add together everything in the list `things`.""" 11 | return reduce(operator.add, things) 12 | 13 | def quadratic(a, b, c): 14 | """Determine `x` values satisfying: `a` * x*x + `b` * x + c == 0""" 15 | b24ac = math.sqrt(b*b - 4.0*a*c) 16 | return list(set([ (-b-b24ac) / 2.0*a, 17 | (-b+b24ac) / 2.0*a ])) 18 | 19 | def remote_repr(arg): 20 | """Return the `repr()` rendering of the supplied `arg`.""" 21 | return arg 22 | 23 | server = SimpleXMLRPCServer(('127.0.0.1', 7001)) 24 | server.register_introspection_functions() 25 | server.register_multicall_functions() 26 | server.register_function(addtogether) 27 | server.register_function(quadratic) 28 | server.register_function(remote_repr) 29 | print("Server ready") 30 | server.serve_forever() 31 | --------------------------------------------------------------------------------