Outline

1
Chapter 20 – Networking
Outline
20.1
20.2
20.3
20.4
20.5
20.6
20.7
Introduction
Accessing URLs over HTTP
Establishing a Simple Server (Using Stream Sockets)
Establishing a Simple Client (Using Stream Sockets)
Client/Server Interaction with Stream Socket Connections
Connectionless Client/Server Interaction with Datagrams
Client/Server Tic-Tac-Toe Using a Multithreaded Server
 2002 Prentice Hall. All rights reserved.
2
20.1 Introduction
• Client/server relationship
• stream sockets provide connection-oriented using
Transmission Control Protocol (TCP)
• User Datagram Protocol (UDP) enables
connectionless network communication with
datagram sockets
• Module socket contains the functions and class
definitions that enable programs to communicate
over a network
 2002 Prentice Hall. All rights reserved.
3
20.2 Accessing URLs over HTTP
• HyperText Transfer Protocol (HTTP), which is
crucial to data transmission on the Web, uses
Uniform (or Universal) Resource Locators (URLs)
to locate content on the Internet
• URLs represent files, directories or complex tasks,
such as database lookups and Internet searches
 2002 Prentice Hall. All rights reserved.
4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Outline
# Fig. 20.1: fig20_01.py
# Displays the contents of a file from a Web server in a browser.
Provides methods for accessing data referred to by URLs
URLs
from Tkinter import *
Provides functions to parse and manipulate
import Pmw
import urllib
Implements a simple Web browser
import urlparse
fig20_1.py
class WebBrowser( Frame ):
"""A simple Web browser"""
def __init__( self ):
"""Create the Web browser GUI"""
Frame.__init__( self )
Pmw.initialise()
self.pack( expand = YES, fill = BOTH )
self.master.title( "Simple
Browser"
EntryWeb
component
for) user-entered
self.master.geometry( "400x300" )
URL
self.address = Entry( self )
in =Pmw
self.address.pack( fill Web
= X, page
padxdisplayed
= 5, pady
5 )ScrolledText
self.address.bind( "<Return>", self.getPage )
component
self.contents = Pmw.ScrolledText( self,
text_state = DISABLED )
self.contents.pack( expand = YES, fill = BOTH, padx = 5,
and displays specified Web page
pady =Retrieves
5 )
def getPage( self, event ):
"""Parse URL, add addressing scheme and retrieve file"""
 2002 Prentice Hall.
All rights reserved.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Retrieve Takes
URL from
Entry
component
a string
as input
and returns a six-element tuple
# parse the URL
myURL = event.widget.get()
components = urlparse.urlparse( myURL )
self.contents.text_state = NORMAL
5
Outline
fig20_1.py
FirstAppend
elementhttp://
of tuple returned
by urlparse.urlparse
is addressing scheme
to user-entered
URL if necessary
# if addressing scheme not specified, use http
if components[ 0 ] == "":
myURL = "http://" + myURL
# connect and retrieve the file
Retrieve requested file
try:
Display requested file
tempFile = urllib.urlopen( myURL )
self.contents.settext( tempFile.read() ) # show results
Generated if file could not be found
tempFile.close()
except IOError:
self.contents.settext( "Error finding file" )
self.contents.text_state = DISABLED
def main():
WebBrowser().mainloop()
if __name__ == "__main__":
main()
 2002 Prentice Hall.
All rights reserved.
6
Outline
fig20_1.py
 2002 Prentice Hall.
All rights reserved.
7
20.3 Establishing a Simple Server (Using
Stream Sockets)
• Step 1: Create a socket object with a call to the
socket constructor: socket.socket( family,
type )
– family (AF_INET or AF_UNIX) specifies how to interpret
any addresses used by the socket
– type (SOCK_STREAM or SOCK_DGRAM) specifies stream
sockets or datagram sockets, respectively
• Step 2: Bind (assign) the socket object to a
specified address: socket.bind( address )
– For AF_INET family sockets, address specifies the
machine’s hostname or IP address and a port number for
connections
 2002 Prentice Hall. All rights reserved.
8
20.3 Establishing a Simple Server (Using
Stream Sockets)
• Step 3: Prepare socket to receive connection
requests: socket.listen( backlog )
– backlog specifies the maximum number of clients that can
request connections to the server
• Step 4: Wait for a client to request a connection:
connection, address = socket.accept()
– socket object blocks indefinitely
– Server communicates with client using connection, a
new socket object
– address corresponds to the client’s Internet address
 2002 Prentice Hall. All rights reserved.
9
20.3 Establishing a Simple Server (Using
Stream Sockets)
• Step 5: Processing phase in which server and
client communicates using socket methods
send and recv
• Step 6: Transmission completes and server closes
connection by invoking close method on the
socket object
 2002 Prentice Hall. All rights reserved.
10
20.4 Establishing a Simple Client (Using
Stream Sockets)
• Step 1: Create a socket object
• Step 2: Connect to the server using
socket.connect( ( host, port ) ) where host
represents server’s hostname or IP address and
port is the port number to which the server process
is bound
• Step 3: Processing phase in which client and
server communicate with methods send and
recv
• Step 4: Client closes connection by invoking
close method on the socket object
 2002 Prentice Hall. All rights reserved.
11
20.5 Client/Server Interaction with Stream
Socket Connections
• Implementation of a simple client/server chat
application using stream sockets
 2002 Prentice Hall. All rights reserved.
12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#
#
#
#
Fig. 20.2: fig20_02.py
Set up a server that will receive a connection
from a client, send a string to the client,
and close the connection.
import socket
Outline
fig20_02.py
String “127.0.0.1” always refers to the local machine
HOST = "127.0.0.1"
PORT = 5000
counter = 0
Creates socket object mySocket to wait for connection requests
# step 1: create socket
mySocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
mySocket
to port 5000
# step 2: bind theBind
socket
to address
Method bind failure generates
try:
mySocket.bind( ( HOST, PORT ) )
except socket.error:
print "Call to bind failed"
socket.error exception
while 1:
Specifies
that only
one client can request a connection
# step 3: wait for
connection
request
print "Waiting for connection"
Establishes connection for a request
mySocket.listen( 1 )
# step 4: establish connection for request
connection, address = mySocket.accept()
counter += 1
print "Connection", counter, "received from:", address[ 0 ]
Send data via connection
Specify that server can receive at most 1024 bytes
# step 5: send and receive data via connection
connection.send( "SERVER>>> Connection successful" )
clientMessage = connection.recv( 1024 )
 2002 Prentice Hall.
All rights reserved.
13
36
37
38
39
40
41
42
43
44
45
46
47
48
while clientMessage != "CLIENT>>> TERMINATE":
if not clientMessage:
break
Outline
fig20_02.py
print clientMessage
serverMessage = raw_input( "SERVER>>> " )
connection.send( "SERVER>>> " + serverMessage )
clientMessage = connection.recv( 1024 )
connection
# step 6: close Terminate
connection
print "Connection terminated"
connection.close()
 2002 Prentice Hall.
All rights reserved.
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Fig. 20.3: fig20_03.py
# Set up a client that will read information sent
# from a server and display that information.
Outline
fig20_03.py
import socket
HOST = "127.0.0.1"
PORT = 5000
# step 1: create socket Create a stream socket
print "Attempting connection"
mySocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
Make a connection
# step 2: make connection
request torequest
serverto
try:
mySocket.connect( ( HOST, PORT ) )
except socket.error:
print "Call to connect failed"
print "Connected to Server"
Accept
server
message from server
# step 3: transmit data via connection
serverMessage = mySocket.recv( 1024 )
while serverMessage != "SERVER>>> TERMINATE":
if not serverMessage:
break
Send message to server
print serverMessage
clientMessage = raw_input( "CLIENT>>> " )
mySocket.send( "CLIENT>>> " + clientMessage )
serverMessage = mySocket.recv( 1024 )
 2002 Prentice Hall.
All rights reserved.
35
36
37
Terminate connection
connection
# step 4: close
print "Connection terminated"
mySocket.close()
15
Outline
fig20_03.py
Waiting for connection
Connection 1 received from: 127.0.0.1
Attempting connection
Connected to Server
SERVER>>> Connection successful
CLIENT>>> Hi to person at server
Attempting
Waiting
forconnection
connection
Connectionto
Connected
1 Server
received from: 127.0.0.1
CLIENT>>> Connection
SERVER>>>
Hi to person
successful
at server
CLIENT>>>
person
at server
SERVER>>> Hi to
back
to you--client!
SERVER>>> Hi back to you--client!
CLIENT>>> TERMINATE
Waiting for connection
Connection 1 received from: 127.0.0.1
CLIENT>>> Hi to person at server
SERVER>>> Hi back to you--client!
Connection terminated
Waiting for connection
 2002 Prentice Hall.
All rights reserved.
16
20.6 Connectionless Client/Server
Interaction with Datagrams
• Connectionless transmission uses datagrams
(packets)
• Connectionless transmission can result in lost,
duplicated and lost packets
 2002 Prentice Hall. All rights reserved.
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Outline
# Fig. 20.4: fig20_04.py
# Set up a server that will receive packets from a
# client and send packets to a client.
fig20_04.py
import socket
HOST = "127.0.0.1"
PORT = 5000
Create a datagram socket object
# step 1: create socket
mySocket = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM
)
Assign socket
to specified host
at port 5000
# step 2: bind socket
mySocket.bind( ( HOST, PORT ) )
while 1:
Method recvfrom blocks until message arrives
Returns received message and address of the socket sending the data
# step 3: receive packet
packet, address = mySocket.recvfrom( 1024 )
print
print
print
print
print
print
"Packet received:"
"From host:", address[ 0 ]
"Host port:", address[ 1 ]
"Length:", len( packet )
"Containing:"
"\t" + packet
Method sendto specifies data to be sent and the address to which it is sent
# step 4: echo packet back to client
print "\nEcho data to client...",
mySocket.sendto(
packet,
address )
Terminate
connection
print "Packet sent\n"
mySocket.close()
 2002 Prentice Hall.
All rights reserved.
18
Packet received:
From host: 127.0.0.1
Host port: 1645
Length: 20
Containing:
first message packet
Outline
fig20_04.py
Echo data to client... Packet sent
 2002 Prentice Hall.
All rights reserved.
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Fig. 20.5: fig20_05.py
# Set up a client that will send packets to a
# server and receive packets from a server.
Outline
fig20_05.py
import socket
HOST = "127.0.0.1"
PORT = 5000
Create datagram socket
# step 1: create socket
mySocket = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
while 1:
# step 2: send packet
Send packet to HOST at PORT
packet = raw_input( "Packet>>>" )
print "\nSending packet containing:", packet
mySocket.sendto( packet, ( HOST, PORT ) )
print "Packet sent\n"
Receive packet from server
# step 3: receive packet back from server
packet, address = mySocket.recvfrom( 1024 )
print
print
print
print
print
print
"Packet received:"
"From host:", address[ 0 ]
"Host port:", address[ 1 ]
"Length:", len( packet )
"Containing:"
Terminate connection
"\t" + packet + "\n"
mySocket.close()
 2002 Prentice Hall.
All rights reserved.
20
Packet>>>first message packet
Sending packet containing: first message packet
Packet sent
Outline
fig20_05.py
Packet received:
From host: 127.0.0.1
Host port: 5000
Length: 20
Containing:
first message packet
Packet>>>
 2002 Prentice Hall.
All rights reserved.
21
20.7 Client/Server Tic-Tac-Toe Using a
Multithreaded Server
• Tic-Tac-Toe game implemented with stream
sockets and using client/server techniques
• A TicTacToeServer class allows two
TicTacToeClients to connect to the server
and play the game
 2002 Prentice Hall. All rights reserved.
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Fig. 20.6: fig20_06.py
# Class TicTacToeServer maintains a game of Tic-Tac-Toe
# for two clients, each managed by a Player thread.
import socket
Thread
import threading
Outline
fig20_06.py
to manage each Tic-Tac-Toe client individually
class Player( threading.Thread ):
"""Thread to manage each Tic-Tac-Toe client individually"""
def __init__( self, connection, server, number ):
"""Initialize thread and setup variables"""
threading.Thread.__init__( self )
Specify each player’s mark
# specify player's mark
if number == 0:
self.mark = "X"
else:
self.mark = "O"
self.connection = connection
self.server = server
Send message to other
self.number = number
client that opponent moved
def otherPlayerMoved( self, location ):
"""Notify client of opponent’s last move"""
self.connection.send( "Opponent moved." )
self.connection.send( str( location ) )
def run( self ):
"""Play the game"""
 2002 Prentice Hall.
All rights reserved.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Each client
receives
message
0)
indicating
its
mark (X
or O) indicating its mark (X or
Outline
# send client message
self.server.display( "Player %s connected." % self.mark )
self.connection.send( self.mark )
# wait for another player to arrive
Wait for second player to arrive
if self.mark == "X":
self.connection.send( "Waiting for another player..." )
self.server.gameBeginEvent.wait()
self.connection.send(
"Other player connected. Your move." )
else:
self.server.gameBeginEvent.wait()
# wait for server
self.connection.send( "Waiting for first move..." )
fig20_06.py
Continue game until game is over
# play game until over
while not self.server.gameOver():
Get selected location from client
# get more location from client
location = self.connection.recv( 1 )
if not location:
break
# check for valid move Send message informing player whether
if self.server.validMove( int( location ), self.number ):
self.server.display( "loc: " + location )
self.connection.send( "Valid move." )
else:
self.connection.send( "Invalid move, try again." )
selected move was valid
Terminate connection
# close connection to client
self.connection.close()
self.server.display( "Game over." )
self.server.display( "Connection closed." )
 2002 Prentice Hall.
All rights reserved.
23
24
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
Outline
class TicTacToeServer:
"""Server that maintains a game of Tic-Tac-Toe for two clients"""
Server that maintains Tic-Tac-Toe game for two clients
def __init__( self ):
"""Initialize variables and setup server"""
fig20_06.py
HOST = ""
PORT = 5000
self.board = [] Condition variable controls which player moves
Event object controls whether game has begun
self.currentPlayer = 0
self.turnCondition = threading.Condition()
self.gameBeginEvent = threading.Event()
for i in range( 9 ):
self.board.append( None )
Create server stream socket
# setup server socket
Bind server socket
self.server = socket.socket( socket.AF_INET,
socket.SOCK_STREAM )
self.server.bind( ( HOST, PORT ) )
self.display( "Server awaiting connections..." )
def execute( self ):
"""Play the game--create and start both Player threads"""
self.players = []
# wait for and accept Server
two client
socketconnections
prepares
for two
connection
requests
Socket
accepts
a connection
for i in range( 2 ):
self.server.listen( 2 )
connection, address = self.server.accept()
 2002 Prentice Hall.
All rights reserved.
25
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# assign each client to a Player thread
self.players.append( Player( connection, self, i ) )
self.players[ Terminate
-1 ].start()
connection
self.server.close()
Outline
Assign each client to a Player thread
fig20_06.py
# no more connections to wait for
# players are suspended until player O connects
Resume players
# resume players now
self.gameBeginEvent.set()
def display( self, message ):
"""Display a message on the server"""
print message
Make valid move
def validMove( self, location, player ):
"""Determine if a move is valid--if so, make move"""
Acquire lock to ensure that only one move can be made at a given time
# only one move can be made at a time
self.turnCondition.acquire()
Player waits for turn
# while not current player, must wait for turn
while player != self.currentPlayer:
self.turnCondition.wait()
Make move if location is not occupied
# make move if location is not occupied
if not self.isOccupied( location ):
# set move on board
if self.currentPlayer == 0:
self.board[ location ] = "X"
else:
self.board[ location ] = "O"
 2002 Prentice Hall.
All rights reserved.
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
Change current player
# change current player
self.currentPlayer = ( self.currentPlayer + 1 ) % 2
self.players[ self.currentPlayer ].otherPlayerMoved(
location )
Tell waiting player to continue
26
Outline
fig20_06.py
# tell waiting player to continue
self.turnCondition.notify()
self.turnCondition.release()
# valid move
return 1
# invalid move
else:
self.turnCondition.notify()
self.turnCondition.release()
return 0
def isOccupied( self, location ):
"""Determine if a space is occupied"""
return self.board[ location ]
# an empty space is None
def gameOver( self ):
"""Determine if the game is over"""
# place code here testing for a game winner
# left as an exercise for the reader
return 0
def main():
TicTacToeServer().execute()
if __name__ == "__main__":
main()
 2002 Prentice Hall.
All rights reserved.
27
Server awaiting connections...
Player X connected.
Player O connected.
loc: 0
loc: 4
loc: 3
loc: 1
loc: 7
loc: 5
loc: 2
loc: 8
loc: 6
Outline
fig20_06.py
 2002 Prentice Hall.
All rights reserved.
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Fig. 20.7: fig20_07.py
# Client for Tic-Tac-Toe program.
import socket
import threading
from Tkinter import *
import Pmw
Outline
fig20_07.py
Client that plays Tic-Tac-Toe
class TicTacToeClient( Frame, threading.Thread ):
"""Client that plays a game of Tic-Tac-Toe"""
Create GUI to play game
def __init__( self ):
"""Create GUI and play game"""
threading.Thread.__init__( self )
# initialize GUI
Frame.__init__( self )
Pmw.initialise()
self.pack( expand = YES, fill = BOTH )
self.master.title( "Tic-Tac-Toe Client" )
self.master.geometry( "250x325" )
self.id = Label( self, anchor = W )
self.id.grid( columnspan = 3, sticky = W+E+N+S )
self.board = []
Create and add all buttons to the board
# create and add all buttons to the board
for i in range( 9 ):
newButton = Button( self, font = "Courier 20 bold",
height = 1, width
= 1, relief
= GROOVE,
Associate
each button
with an event – left
name = str( i ) )
newButton.bind( "<Button-1>", self.sendClickedSquare )
self.board.append( newButton )
mouse button click
 2002 Prentice Hall.
All rights reserved.
29
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Outline
current = 0
# display buttons in 3x3 grid beginning with grid's row one
for i in range( 1, 4 ):
fig20_07.py
for j in range( 3 ):
self.board[ current ].grid( row = i, column = j,
sticky = W+E+N+S )
current += 1
# area for server messages
self.display = Pmw.ScrolledText( self, text_height = 10,
text_width = 35, vscrollmode = "static" )
self.display.grid( row = 4, columnspan = 3 )
self.start()
# run thread
def run( self ):
"""Control thread to allow continuous updated display"""
# setup connection to server
HOST = "127.0.0.1"
Create client socket
PORT = 5000
self.connection = socket.socket( socket.AF_INET,
socket.SOCK_STREAM )
self.connection.connect( ( HOST, PORT ) )
# first get player s mark ( X or O )
self.myMark = self.connection.recv( 1 )
self.id.config( text = 'You are player "%s"' % self.myMark )
self.myTurn = 0
 2002 Prentice Hall.
All rights reserved.
30
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# receive messages sent to client
while 1:
message = self.connection.recv( 34 )
Receive messages sent to client
Outline
fig20_07.py
if not message:
break
self.processMessage( message )
Terminate connection
self.connection.close()
self.display.insert( END, "Game over.\n" )
self.display.insert( END, "Connection closed.\n" )
Interpret
messages to perform necessary
self.display.yview(
ENDserver
)
actions
def processMessage( self, message ):
"""Interpret server message to perform necessary actions"""
# valid move occurred
if message == "Valid move.":
self.display.insert( END, "Valid move, please wait.\n" )
self.display.yview( END )
# set mark
self.board[ self.currentSquare ].config(
text = self.myMark, bg = "white" )
# invalid move occurred
elif message == "Invalid move, try again.":
self.display.insert( END, message + "\n" )
self.display.yview( END )
self.myTurn = 1
# opponent moved
elif message == "Opponent moved.":
 2002 Prentice Hall.
All rights reserved.
31
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# get move location
location = int( self.connection.recv( 1 ) )
# update board
if self.myMark == "X":
self.board[ location ].config( text = "O",
bg = "gray" )
else:
self.board[ location ].config( text = "X",
bg = "gray" )
Outline
fig20_07.py
self.display.insert( END, message + " Your turn.\n" )
self.display.yview( END )
self.myTurn = 1
# other player's turn
elif message == "Other player connected. Your move.":
self.display.insert( END, message + "\n" )
self.display.yview( END )
self.myTurn = 1
# simply display message
else:
self.display.insert( END, message + "\n" )
self.display.yview( END )
Send attempted move to server
def sendClickedSquare( self, event ):
"""Send attempted move to server"""
if self.myTurn:
name = event.widget.winfo_name()
self.currentSquare = int( name )
 2002 Prentice Hall.
All rights reserved.
32
138
139
140
141
142
143
144
145
146
# send location to server
self.connection.send( name )
self.myTurn = 0
Send location of move to server
def main():
TicTacToeClient().mainloop()
Outline
fig20_07.py
if __name__ == "__main__":
main()
 2002 Prentice Hall.
All rights reserved.
33
Outline
fig20_07.py
 2002 Prentice Hall.
All rights reserved.