52
Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Embed Size (px)

Citation preview

Page 1: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Advanced Networking in Python

Modified from Steve Holden and Kenneth A. Lambert

CPE 401 / 601 Computer Network Systems

Mehmet Hadi Gunes

Page 2: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes
Page 3: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Writing a handle() Method

• self.request gives client access– (string, socket) for UDP servers– Connected socket for TCP servers

• self.client_address is remote address• self.server is server instance

• TCP servers should handle a complete client session

Page 4: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Skeleton Handler Examples

• No error checking• Unsophisticated session handling (TCP)• Simple tailored clients

– Try telnet with TCP server!

• Demonstrate the power of the Python network libraries

Page 5: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

UDP Upper-Case SocketServer

import SocketServerclass UCHandler(SocketServer.BaseRequestHandler): def handle(self): remote = self.client_address data, skt = self.request print data skt.sendto(data.upper(), remote)

myaddr = ('127.0.0.1', 2345)myserver = SocketServer.UDPServer(myaddr, UCHandler)myserver.serve_forever()

Note: this server never terminates!

Change this function to alter server's functionality

Page 6: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

UDP Upper-Case Client

from socket import socket, AF_INET, SOCK_DGRAMsrvaddr = ('127.0.0.1', 2345)data = raw_input("Send: ")s = socket(AF_INET, SOCK_DGRAM)s.bind(('', 0))s.sendto(data, srvaddr)data, addr = s.recvfrom(1024)print "Recv:", data

• Client interacts once then terminates

• hangs if no response

Page 7: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

TCP Upper-Case SocketServer

import SocketServerclass UCHandler(SocketServer.BaseRequestHandler): def handle(self): print "Connected:", self.client_address while True: data = self.request.recv(1024) if data == "\r\n": break print data[:-2] self.request.send(data.upper())

myaddr = ('127.0.0.1', 2345)myserver = SocketServer.TCPServer(myaddr, UCHandler)myserver.serve_forever()

Change this function to alter server's functionality

Page 8: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

TCP Upper-Case Client

from socket import socket, AF_INET, SOCK_STREAMsrvaddr = ('127.0.0.1', 2345)s = socket(AF_INET, SOCK_STREAM)s.connect(srvaddr)while True: data = raw_input("Send: ") s.send(data + "\r\n") if data == "": break data = s.recv(1024) print data[:-2] # Avoids doubling-up the newlines.close()

Page 9: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Example: Python Client (TCP)

from socket import *

serverName = ’servername’

serverPort = 12000

clientSocket = socket(AF_INET, SOCK_STREAM)

clientSocket.connect((serverName,serverPort))

sentence = raw_input(‘Input lowercase sentence:’)

clientSocket.send(sentence)

modifiedSentence = clientSocket.recv(1024)

print ‘From Server:’, modifiedSentence

clientSocket.close()

create TCP socket for server, remote port 12000

No need to attach server name, port

Page 10: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Example: Python Server (TCP)

from socket import *serverPort = 12000serverSocket = socket(AF_INET,SOCK_STREAM)serverSocket.bind((‘’,serverPort))serverSocket.listen(1)print ‘The server is ready to receive’while True: connectionSocket, addr = serverSocket.accept() sentence = connectionSocket.recv(1024) capitalizedSentence = sentence.upper() connectionSocket.send(capitalizedSentence) connectionSocket.close()

create TCP welcomingsocket

server begins listening for incoming TCP requests

loop forever

server waits on accept()for incoming requests, new socket created on return

read bytes from socket (but not address as in UDP)

close connection to this client (but not welcoming socket)

Page 11: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Example: Python Client (UDP)

from socket import *

serverName = ‘hostname’

serverPort = 12000

clientSocket = socket(socket.AF_INET,

socket.SOCK_DGRAM)

message = raw_input(’Input lowercase sentence:’)

clientSocket.sendto(message,(serverName, serverPort))

modifiedMessage, serverAddress =

clientSocket.recvfrom(2048)

print modifiedMessage

clientSocket.close()

include Python’s socket library

create UDP socket for server

get user keyboardinput

Attach server name, port to message; send into socket

print out received string and close socket

read reply characters fromsocket into string

Page 12: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Example: Python Server (UDP)

from socket import *

serverPort = 12000

serverSocket = socket(AF_INET, SOCK_DGRAM)

serverSocket.bind(('', serverPort))

print “The server is ready to receive”

while True: message, clientAddress = serverSocket.recvfrom(2048) modifiedMessage = message.upper() serverSocket.sendto(modifiedMessage, clientAddress)

create UDP socket

bind socket to local port number 12000

loop forever

Read from UDP socket into message, getting client’s address (client IP and port)

send upper case string back to this client

Page 13: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Sample Python Module

• Problem: remote debugging– Need to report errors, print values, etc.– Log files not always desirable

• Permissions issues• Remote viewing often difficult• Maintenance (rotation, etc.) issues

• Solution: messages as UDP datagrams

Page 14: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Output Module

def spew(msg, host='localhost', port=PORT): s = socket.socket((socket.AF_INET,socket.SOCK_DGRAM)) s.bind(('', 0)) while msg: s.sendto(msg[:BUFSIZE], (host, port))

msg = msg[BUFSIZE:]

• Creates a datagram (UDP) socket• Sends the message

– In chunks if necessary

Page 15: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Input Module

def bucket(port=PORT, logfile=None):s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.bind(('', port))print 'waiting on port: %s' % portwhile True: try: data, addr = s.recvfrom(BUFSIZE) print data[1:-1] except socket.error, msg: print msg

• An infinite loop, printing out received messages

Page 16: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Sockets and a Day/Time Client Script

• We’ll write a script that is a client to a server• Socket: object that serves as a communication

link between a server process and a client process– Can create/open several sockets on the same port

Page 17: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

A Day/Time Client Script

Page 18: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

A Day/Time Server Script

Page 19: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

A Two-Way Chat Script• Server creates a socket and enters an infinite loop to

accept/handle clients; when one connects, it sends a greeting, and enters loop to chat with client

Page 20: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

A Two-Way Chat Script

• Client:– Sets up a socket – After connection, receives and displays greeting– Then, enters a loop to chat with server

Page 21: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Handling Multiple Clients Concurrently

• To solve the problem of giving many clients timely access to the server, – we assign task of handling the client’s request a

client-handler thread

Page 22: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Server code

Client code same as previous one

Page 23: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Multi-client Chat roomClient code

Page 24: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Multi-client Chat roomServer code

Page 25: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Multi-client Chat roomServer code

ChatRecord code

Page 26: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Simple Server Limitations

accept()

read()

write()

[blocked]

[blocked]

Client connection

Forked server process orthread runs independently

Remote Client

Process

Server creates a new thread or forks a new process to handle each request

Page 27: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Asynchronous Server Classes

• A threading UDP server class is created as follows:

class ThreadingUDPServer(

ThreadingMixIn, UDPServer): pass

• The mix-in class must come first, since it overrides a method defined in UDPServer

Page 28: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Network Client Libraries

• Python offers a rich variety of network client code– Email: smtplib, poplib, imaplib

• rfc822 and email modules handle content

– File transfer: ftplib– Web: httplib, urllib– Network news: nntplib– Telnet: telnetlib

Page 29: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

General Client Strategy

• Library usually defines an object class

• Create an instance of the object to interact with the server

• Call the instance's methods to request particular interactions

Page 30: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using smtplib

• s = smtplib.SMTP([host[, port]])

– Create SMTP object with given connection parameters

• r = s.sendmail(from, to, msg[, mopts[, ropts]])

– from : sender address– to : list of recipient addresses– msg : RFC822-formatted message

• including all necessary headers– mopts, ropts : ESMTP option lists

Page 31: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

SMTP Example (1)

import smtplib, socket

frad = "[email protected]"

toads = ["[email protected]",

"[email protected]",

"[email protected]"]

msg = """To: Various recipients

From: Steve Holden <[email protected]>

Hello. This is an RFC822 mail message.

"""

Page 32: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

SMTP Example (2)

try: server = smtplib.SMTP('10.0.0.1') result = server.sendmail(frad, toads, msg) server.quit() if result: for r in result.keys(): print "Error sending to", r rt = result[r] print "Code", rt[0], ":", rt[1] else: print "Sent without errors“

except smtplib.SMTPException, arg: print "Server could not send mail", arg

Page 33: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using poplib

• p = poplib.POP3(host[, port])

– Creates a POP object with given connection parameters

• p.user(username)

– Provide username to server• p.pass_(password)

– Provide password to server• p.stat()

– Returns (# of msgs, # of bytes)

Page 34: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using poplib (continued)

• p.retr(msgnum)

– returns (response, linelist, bytecount)

• p.dele(msgnum)

– Marks the given message for deletion

• p.quit()

– Terminate the connection– Server actions pending deletes and unlocks

the mailbox

Page 35: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

poplib Example (1)

import poplib, rfc822, sys, StringIOSRVR = "mymailserver.com"USER = "user"PASS = "password"try: p = poplib.POP3(SRVR)except: print "Can't contact %s" % (SRVR, ) sys.exit(-1)try: print p.user(USER) print p.pass_(PASS)except: print "Authentication failure" sys.exit(-2)

Page 36: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

poplib Example (2)

msglst = p.list()[1]for m in msglst: mno, size = m.split() lines = p.retr(mno)[1] print "----- Message %s" % (mno, ) file = StringIO.StringIO("\r\n".join(lines)) msg = rfc822.Message(file) body = file.readlines() addrs = msg.getaddrlist("to") for rcpt, addr in addrs: print "%-15s %s" % (rcpt, addr) print len(body), "lines in message body"print "-----"p.quit()

Page 37: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using ftplib

• f = ftplib.FTP(host[,user[,passwd[,acct]]])

– Creates an FTP object• f.dir(directory)

– Send directory listing to standard output• f.cwd(directory)

– Change to given directory• f.mkd(directory)

– Create directory on server• f.pwd()

– Returns current directory on server

Page 38: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using ftplib (continued)

• retrbinary(command, callback[,maxblocksize[, rest]])

– Retrieve a file in binary mode– command - an FTP command

• E.g. "RETR myfile.dat"– callback - processes each block– maxblocksize – how much data per block– rest – restart position

Page 39: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using ftplib (continued)

• f.retrlines(command[, callback])

– Retrieves a file in text mode– command - an FTP command

• E.g. "RETR myfile.txt"– callback - processes each line as an argument

• Default callback prints line to standard output• f.storlines(command, file)

– Sends content of file line-by-line• f.storbinary(command, file, blocksize)

– Sends content of file block-by-block

Page 40: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Abbreviated ftplib Example

class Writer:

def __init__(self, file):

self.f = open(file, "w")

def __call__(self, data):

self.f.write(data)

self.f.write('\n')

print data

FILENAME = "AutoIndent.py"

writer = Writer(FILENAME)

import ftplib

ftp = ftplib.FTP('127.0.0.1', 'book', 'bookpw')

ftp.retrlines("RETR %s" % FILENAME, writer)

Page 41: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

HTTP and HTML Libraries

• Python applications are often web-based• htmllib, HTMLParser – HTML parsing• httplib – HTTP protocol client• urllib, urllib2 – multiprotocol client• SimpleHTTPServer, CGIHTTPServer – SocketServer-based servers

• cgi, cgitb – CGI scripting assistance• Various web samples also available

Page 42: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using urllib

• f = urllib.urlopen(URL)

– Create file-like object that allows you to read the identified resource

• urlretrieve(url[, filename[,reporthook[, data]]])

– Reads the identified resource and store it as a local file

• See documentation for further details

• This is very convenient for interactive use

Page 43: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Interactive urllib Session

>>> import urllib>>> f = urllib.urlopen("http://www.python.org/")>>> page = f.read() # treat as file to get body>>> len(page)14790>>> h = f.info()>>> h.getheader("Server")'Apache/1.3.26 (Unix)'>>> h.getheaders("Date")['Thu, 29 May 2003 15:07:27 GMT']>>> h.type'text/html'

• Useful for testing & quick interactions

Page 44: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Using urllib2

• urllib has limitations - difficult to– Include authentication– Handle new protocols/schemes

• Must subclass urllib.FancyURLOpener and bind an instance to urllib._urlopener

• urllib2 is intended to be more flexible• The price is added complexity

– Many applications don't need the complexity

Page 45: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

urllib2.Request Class

• Instance can be passed instead of a URL to the urllib2.urlopen() function

• r = Request(url, data=None, headers={})– r.add_header(key, value)

• Can only add one header with a given key– r.set_proxy(host, scheme )

• Sets the request to use a given proxy to access the given scheme

– r.add_data(data)

• Forces use of POST rather than GET• Requires http scheme

Page 46: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Serving HTTP

• Several related modules:– BaseHTTPServer defines

• HTTPServer class• BaseHTTPRequestHandler class

– SimpleHTTPServer defines• SimpleHTTPRequestHandler class

– CGIHTTPServer defines• CGIHTTPRequestHandler class

• All request handlers use the standard HTTPServer.BaseHTTPRequestHandler

Page 47: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

The Simplest Web Server …

import CGIHTTPServer, BaseHTTPServer

httpd = BaseHTTPServer.HTTPServer(('', 8888),

CGIHTTPServer.CGIHTTPRequestHandler)

httpd.serve_forever()

• Uses the basic HTTP server class• Request handler methods implement the

HTTP PUT/GET/HEAD requests• Yes, this really works!

Page 48: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Standard CGI Support

• cgi module provides input handling• Recent (2.2) changes make things easier

– cgitb module traps errors• Easier to diagnose problems

– Gives complete Python traceback

– Situation previously complicated by differences in multi-valued form inputs

• Had to check, and program different actions (string vs list)

• Python is excellent for producing HTML!

Page 49: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

The cgi.FieldStorage Class

• Makes web client's input accessible– Consumes input, so only instantiate once!– Handles method GET or POST– Optional argument retains blank values

• f.getfirst(name, default=None)

– Returns first (only) input value with given name

• f.getlist(name)

– Returns a list of all values with given name

Page 50: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Error Handling• Should use for all CGI scripts!

import cgitb; cgitb.enable()

• Traps any errors, producing legible trace

Page 51: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Sample CGI Script

#!/usr/bin/pythonimport cgi, cgitb; cgitb.enable()fields = ["subnum", "reviewer", "comments"]

form = cgi.FieldStorage()vlist = []for f in fields: vlist.append("%s=%s" % (f, form.getfirst(f)))

print pgtmpl = """Content-Type: text/html

<html><head><title>Hello!</title></head>%s</body></html>""" % "<br>".join(vlist)

Page 52: Advanced Networking in Python Modified from Steve Holden and Kenneth A. Lambert CPE 401 / 601 Computer Network Systems Mehmet Hadi Gunes

Summary

• Reviewed principles of networking• Contrasted TCP and UDP features• Shown how Python programs access

networking functionality• Given examples of client and server program

structures• Demonstrated some Python network libraries• Given pointers to other network functionality