LECTURE 14 Introduction to Networking NETWORKING IN PYTHON Networking applications are a major use of the Python language. Python supports low-level socket programming as provides high-level networking libraries. Today, we will start with the basics of sockets in Python. We will then create a blackjack game server using the socket module. SOCKETS • A socket is one end-point of a two-way communication link between two programs running on a network. • Allows connections to be made and data to be transmitted in either direction. Python’s socket module provides access to the BSD socket interface. SOCKET BASICS • Creating a socket • socket.socket() returns a socket object. • First argument is the address family. • Second argument is the socket type. • Creating an IPv4 TCP connection: From socket import * s = socket(AF_INET, SOCK_STREAM) SOCKET BASICS Address and Protocol families • socket.AF_UNIX: Unix Domain Sockets (UDS) (Posix systems). • socket.AF_INET: IPv4 Internet addressing (e.g. 10.1.1.5 and 127.0.0.1). • socket.AF_INET6: IPv6 Internet addressing (128 bits). Socket Types • socket.SOCK_STREAM: Connection based stream (TCP). • socket.SOCK_DGRAM: Datagrams (UDP). • Other much less common options. TCP CLIENT s.connect(addr) makes a connection. • address is a tuple (host, port). s.send(string[, flags]) • Send string to remote socket. • Returns number of bytes sent. • Flags are available on man page for recv(2). from socket import * s = socket(AF_INET, SOCK_STREAM) s.connect(("www.python.org",80)) # Connect s.send("GET /index.html HTTP/1.0\n\n") # Send request data = s.recv(10000) # Get response s.close() TCP CLIENT s.recv(bufsize[, flags]) • bufsize is maximum number of bytes. • Returns data received. s.close() closes connection. from socket import * s = socket(AF_INET, SOCK_STREAM) s.connect(("www.python.org",80)) # Connect s.send("GET /index.html HTTP/1.0\n\n") # Send request data = s.recv(10000) # Get response s.close() TCP SERVER TCP Clients are easy – just create a connection and send and receive data as needed. TCP Servers must be listening and able to accept multiple connections at any time. TCP SERVER s.bind(address) • address is a tuple (host, port). • Binding to localhost makes the server available only to the machine itself. • Binding to socket.gethostname() makes socket visible to outside. • Bind to “” so the socket is reachable by any address the machine has. from socket import * s = socket(AF_INET, SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() print "Received connection from", a c.send("Hello %s\n" % a[0]) c.close() Note: low number ports usually reserved – use a 4 digit port number when testing. TCP SERVER s.listen(num) • Listen for connections made to the socket. • Queue up as many as num connections before connections are refused. s.accept() • Accept a connection. • Returns (conn, address) where conn is a new socket object and address is the address bound to the other end of the connection. • Blocks until connection received. from socket import * s = socket(AF_INET, SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() print "Received connection from", a c.send("Hello %s\n" % a[0]) c.close() TCP SERVER s.listen(num) • Listen for connections made to the socket. • Queue up as many as num connections before connections are refused. s.accept() • Accept a connection. • Returns (conn, address) where conn is a new socket object and address is the address bound to the other end of the connection. • Blocks until connection received. from socket import * s = socket(AF_INET, SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() print "Received connection from", a c.send("Hello %s\n" % a[0]) c.close() New socket object is created for the specific client. TCP CLIENTS AND SERVERS Clients • Issue connect() and then short sequences of send/receive data. Servers • bind(), listen(), loop: accept() create client socket. Useful utility functions: socket.gethostbyname("www.python.org") returns IP socket.gethostbyaddr("82.94.237.218") returns name SEND AND RECV Sending and receiving data is often done in stages – they are bound to the capacity of the network buffers. • s.send() returns number of bytes sent. • s.recv() may receive fewer bytes than the specified max. Returns empty string when connection is closed. • s.sendall(string[, flags]) blocks until all data transmitted. SOCKET OPTIONS s.settimeout(value) • Sets a timeout on blocking socket operations of value seconds. s.setblocking(Flag) • Sets whether socket operations should be blocking or non-blocking. f = s.makefile() • Can read and write socket as a file object f. UDP SOCKETS UDP does not require transmission handshaking or other setup, but offers lower reliability of delivery. UDP messages may be delivered out of order, multiple times, or not at all. UDP Datagrams deliver higher performance. Key new methods: • s.sendto(string, address): sends string to address, returning number of bytes sent. • s.recvfrom(buf): receive at most buf bytes of data from the socket. Returns (string, address). UDP CLIENT from socket import * s = socket(AF_INET, SOCK_DGRAM) msg = "Hello World” s.sendto(msg,("server.com",10000)) data, addr = s.recvfrom(maxsize) UDP SERVER from socket import * s = socket(AF_INET, SOCK_DGRAM) s.bind(("",10000)) while True: data, addr = s.recvfrom(maxsize) resp = "Get off my lawn!” s.sendto(resp,addr) No connection! – just receiving and sending packets. BACK TO TCP Let’s go back to TCP sockets for a while since they’re more common. What’s the problem with this model? from socket import * s = socket(AF_INET, SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() print "Received connection from", a c.send("Hello %s\n" % a[0]) c.close() BACK TO TCP Let’s go back to TCP sockets for a while since they’re more common. What’s the problem with this model? Every client will have to wait for the previously connection to close before its own connection is made. from socket import * s = socket(AF_INET, SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() print "Received connection from", a c.send("Hello %s\n" % a[0]) c.close() THREADING The threading module in the Python Standard Library allows us to implement threading – running multiple operations concurrently within the same program space. Simple usage: t = threading.Thread(target=worker_function, args=(arg1, arg2)) Creates a thread t which will call worker_function with the arguments arg1 and arg2 when the thread is started. THREADED TCP SERVER import threading from socket import * def handle_client(c): ... whatever ... c.close() return s = socket(AF_INET,SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() t = threading.Thread(target=handle_client, args=(c,)) t.start() FORKING TCP SERVER import os from socket import * s = socket(AF_INET, SOCK_STREAM) s.bind(("",9000)) s.listen(5) while True: c,a = s.accept() if os.fork() == 0: # Child process. Manage client ... c.close() os._exit(0) else: c.close() EXAMPLE BLACKJACK SERVER Check out threaded our threaded TCP server for playing Blackjack: blackjack_server.py and card.py.