H2 Computing 1
C8 Socket Programming
C8 Socket Programming 2
How programs communicate?
C8 Socket Programming 3
What is a Socket?
A socket connection is like a bi-directional communication pipe
between two running programs.
The Internet Socket, which is most common, uses the TCP/IP *
protocol so that computers can access each other even over the
network.
* Transmission Control Protocol and Internet Protocol
Computer X Computer Y
Program A Program B
bytes
bytes
Internet
Socket
C8 Socket Programming 4
For simplicity, we illustrate an Internet Socket as a pipe
connecting the two computers.
In reality, data communication between two computers passes
through multiple devices before reaching its destination.
Computer X Computer Y
Program A Program B
device
bytes bytes bytes
bytes
device bytes bytes
C8 Socket Programming 5
Create a server listening for client
from socket import *
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
server.py
Computer X
Listening …
These 4 lines of code
Program A are essential to
initialise my_socket()
my_socket
Server
127.0.0.1:12345
C8 Socket Programming 6
Connecting a client to the server
from socket import *
my_socket = socket()
addr=input('Enter IPv4 address of server: ')
port=int(input('Enter port number of server: '))
client.py
my_socket.connect((addr, port)) Computer Y
Program B
Server Port Port
127.0.0.1 12345 5000
Socket
my_socket Client
192.0.0.1:5000
C8 Socket Programming 7
Server accepts the client
new_socket, addr = my_socket.accept()
Print('Connected to: ' + str(addr))
new_socket my_socket my_socket
Computer X Computer Y
server.py
Listening …
Program A Program B
Port Port
Accepted !
12345 5000
Socket
Server Client
127.0.0.1:12345 192.0.0.1:5000
The socket.accept() method will block the program until a new client
connects; then it will create a new_socket with the client's address.
C8 Socket Programming 8
Server sends a message
Computer X Computer Y
Listening …
Program A Program B
Msg bytes Msg
Socket
Server Client
127.0.0.1:12345 192.0.0.1:5000
server.py
Bufsize(byte): max amount
Msg = 'Hello from server' of data to be received at
once. Should be small
new_socket.sendall(Msg.encode()) power of 2, eg 210
client.py
Msg = my_socket.recv(1024)
Print(Msg.decode())
C8 Socket Programming 9
Closing all the sockets
new_socket my_socket my_socket
Computer X Computer Y
Listening …
Program A Program B
Socket
Server Client
127.0.0.1:12345 192.0.0.1:5000
server.py
new_socket.close()
my_socket.close()
client.py
my_socket.close()
C8 Socket Programming 10
Unicode and Encodings
C8 Socket Programming 11
Python's Bytes Type
Sockets work at a very basic level, they can only send and receive
data in the form of raw bytes.
ie. data is encoded into a sequence of 8-bit characters.
msg = 'string'.encode()
type(msg) → <class 'bytes'>
msg → b'string'
len(msg) → 6 which is same as len('string')
print(msg.decode()) → 'string'
Message need to be encoded before sending and
be decoded after receiving.
C8 Socket Programming 12
Python's Bytes Type
The Chinese character 中 can be written as the str literal
'\u4e2d' in Python. The use of the escape code '\u' to
produce the character by specifying its Unicode code point.
Encode
msg1 = '\u4e2d' before sending
type(msg1) → <class 'str'>
len(msg1) → 1 msg2 = msg1.encode()
print(msg1) → 中
type(msg2) → <class 'bytes'>
len(msg2) → 3 in UTF-8
print(msg2) → b'\xe4\xb8\xad'
msg3 = msg2.decode()
type(msg3) → <class 'str'>
Decode
len(msg3) → 1
print(msg3) → 中 after receiving
C8 Socket Programming 13
Project 1
Single direction Server-Client communication
C8 Socket Programming 14
from socket import *
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
server.py
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
Msg = 'Hello from server\n'
new_socket.sendall(Msg.encode())
new_socket.close()
my_socket.close()
C8 Socket Programming 15
from socket import *
my_socket = socket()
addr=input('Enter IPv4 address of server: ')
port=int(input('Enter port number of server: '))
client.py
my_socket.connect((addr, port))
Msg = my_socket.recv(1024)
print(Msg.decode())
my_socket.close()
16
Assignment 1
Single direction communication from 1 Server to 2 Clients
C8 Socket Programming 17
Modify the server.py in Project 1 so that the server can
communicate with two clients.
from socket import *
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
server.py
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
Msg = 'Hello from server\n'
new_socket.sendall(Msg.encode())
new_socket.close()
my_socket.close()
C8 Socket Programming 18
Same as client.py in Project 1:
from socket import *
my_socket = socket()
addr=input('Enter IPv4 address of server: ')
client1.py
port=int(input('Enter port number of server: '))
my_socket.connect((addr, port))
Msg = my_socket.recv(1024)
print(Msg.decode())
my_socket.close()
C8 Socket Programming 19
Same as client.py in Project 1:
from socket import *
my_socket = socket()
addr=input('Enter IPv4 address of server: ')
client2.py
port=int(input('Enter port number of server: '))
my_socket.connect((addr, port))
Msg = my_socket.recv(1024)
print(Msg.decode())
my_socket.close()
C8 Socket Programming 20
Project 2
Designing a Protocol
C8 Socket Programming 21
Why do we need a Protocol?
When a server send a long sequence of bytes, some of the data
packet may be delayed during transportation through the
network.
To understand this, we will break the data in to two sequences.
After sending out the first piece of data, we call the sleep()
method in the time module to simulate a delay in the busy
network, then call socket.sendall() again to send the
second piece of data.
C8 Socket Programming 22
from socket import *
from time import *
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
server.py
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
new_socket.sendall(b'Hello fr')
sleep(0.1)
new_socket.sendall(b'om server\n')
new_socket.close()
my_socket.close()
C8 Socket Programming 23
Run the client.py from Project 1 to receive the message
from the server.
from socket import *
client.py
my_socket = socket()
my_socket.connect(('127.0.0.1', 12345))
print(my_socket.recv(1024).decode())
[Project 1]
my_socket.close()
In this example, the client receives only the first part of the data
and closes the socket. This will produce an error when the server
tries to send the second piece of data.
In general, we should never assume that socket.recv()
has received all the bytes that were sent.
C8 Socket Programming 24
We can agree on a protocol beforehand that any data we
transmit will always end with a newline character \n and that
the data itself will never contain the \n character.
The following client.py search for the \n character to
detect the end of a transmission:
from socket import *
my_socket = socket()
my_socket.connect(('127.0.0.1', 12345))
client.py
data = b''
while b'\n' not in data:
data += my_socket.recv(1024)
print(data.decode())
We will use this method whenever
my_socket.close()
we need to receive any data.
C8 Socket Programming 25
Assignment 2
Bi-direction Server-Client communication
C8 Socket Programming 26
Assignment 2 :
Modify the server.py and client.py (with protocol),
given in the next two slides, so that it will be a bi-directional
communication between the server and the client.
C8 Socket Programming 27
from socket import *
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
server.py
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
new_socket.sendall(b'Hello from server\n')
new_socket.close()
my_socket.close()
C8 Socket Programming 28
from socket import *
my_socket = socket()
my_socket.connect(('127.0.0.1', 12345))
client.py (with protocol)
data = b''
while b'\n' not in data:
data += my_socket.recv(1024)
print(data.decode())
my_socket.close()
C8 Socket Programming 29
Project 3
Iterative Server
C8 Socket Programming 30
Why we need a iterative server?
Currently, the server program exits immediately after it finishes
working with a client. In reality, the server program should run
continuously and is always listening for the clients' connection
requests.
Must include the 4 essential lines
... of code to initialise my_socket()
while True:
print('Type Ctrl-F6 or close the shell
to terminate the server.')
server.py
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
new_socket.sendall(b'Hello from server\n')
new_socket.close()
my_socket.close()
Iterative servers are easy to write, but they are limited and can
only handle one client at a time.
C8 Socket Programming 31
Run the client.py from Project 2 to receive the message
from the server.
from socket import *
my_socket = socket()
client.py (with protocol)
my_socket.connect(('127.0.0.1', 12345))
data = b''
while b'\n' not in data:
data += my_socket.recv(1024)
print(data.decode())
my_socket.close()
Since the server is still running, you may execute the client
program again, a few more times, after it closes my_socket.
C8 Socket Programming 32
Project 4
A Chat Program
C8 Socket Programming 33
Must include the 4 essential lines
... of code to initialise my_socket()
print('Type Ctrl-F6 or close the shell to
terminate the server.')
chat_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr)) Sending
while True:
data = input('Input message: ').encode()
chat_socket.sendall(data + b'\n')
server.py
print('WAITING FOR CLIENT ...')
data = b''
while b'\n' not in data:
data += chat_socket.recv(1024)
print('Client wrote: ' + data.decode())
chat_socket.close()
my_socket.close() Receiving
C8 Socket Programming 34
The client program is similar, except the order of sending and
receiving is reversed.
from socket import *
chat_socket = socket()
chat_socket.connect(('127.0.0.1', 12345))
Receiving
while True:
client.py
print('WAITING FOR SERVER ...')
data = b''
while b'\n' not in data:
data += chat_socket.recv(1024)
print('Server wrote: ' + data.decode())
data = input('Input message: ').encode()
chat_socket.sendall(data + b'\n')
chat_socket.close() Sending
C8 Socket Programming 35
Assignment 3
A Chat Program with Quit
C8 Socket Programming 36
Assignment 3 : Chat program with Quit
Currently, there is no way to exit our chat programs other than
using the Ctrl-F6 or closing the IDLE shell.
Modify the chat_client.py and chat_server.py so that
both programs exit once the word 'BYE' * is mentioned by either
user. Remember to close all the sockets before exiting.
* The user may use both small or capital letters.
C8 Socket Programming 37
Project 5
A Turn-Based Game – "Guess Head or Tail"
C8 Socket Programming 38
Consider the following 'Guess Head or Tail' game:
from random import *
def game(guess):
if guess == 'H' or guess == 'T':
if guess == choice(['H', 'T']):
head_tail.py
return 'You are right!'
else:
return 'Sorry, you are wrong.'
elif guess == 'Q':
return 'Thanks for playing the game. Bye!'
else:
return 'Invalid entry. Try again.'
C8 Socket Programming 39
def main():
while True:
guess = input('\n\nI will toss a coin, \
head_tail.py
enter H or T for guessing a \
head or tail (T), and Q to \
quit: ').upper()
print(game(guess))
if guess == 'Q':
break
Copy the codes for game() and main() and save them in the
head_tail.py program. Run the program and play the game.
Observe how the game is being implemented.
C8 Socket Programming 40
from socket import * Must include the program
code for game(guess)
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
print('Type Ctrl-F6 or close the shell to \
server.py
terminate the server.')
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
while True: Convert the code for main()
and include it here
new_socket.close()
my_socket.close()
C8 Socket Programming 41
Observe how the following server
program communicate with the client.
while True:
new_socket.sendall(b'I will toss a coin, \
guess if it is a head (H) or tail (T) : ')
client_guess = b''
server.py
while b'\n' not in client_guess:
client_guess += new_socket.recv(1024)
client_guess = client_guess.decode().strip()
new_socket.sendall(game(client_guess)\
.encode() + b'\n')
if client_guess == 'Q':
break
C8 Socket Programming 42
from socket import *
my_socket = socket()
my_socket.connect(('127.0.0.1', 12345))
while True:
data = my_socket.recv(1024)
guess = input(data.decode()).upper()
my_socket.sendall(guess.encode() + b'\n')
client.py
data = b''
Send user's input to the server
while b'\n' not in data:
data += my_socket.recv(1024)
print(data.decode())
if guess == 'Q':
Display message from the server
break
my_socket.close()
C8 Socket Programming 43
Assignment 4
A Turn-Based Game – "Guess Head or Tail" with Counters
C8 Socket Programming 44
Assignment 4 : Add Counters to the
"Guess Head or Tail" game
N = Total number of guesses
C = Total number of correct guesses
Modify the server and client program to display the following when
the user ended the game:
' You have guessed correctly C out of N times.'
C8 Socket Programming 45
Assignment 5
A Turn-Based Game – "Guess High or Low"
C8 Socket Programming 46
Assignment 5 : Write the server program
1. Study the "Guess High or Low" game.
2. Use, but do not modify, the provided client program.
3. Using the template for the server program, write the necessary
code to communicate with the client program for the game.
C8 Socket Programming 47
Consider the following 'Guess High or Low' game:
from random import *
num = randint(1,100)
def game(guess):
if guess.isdigit():
high_low.py
if int(guess) == num:
return 'You win!'
elif int(guess) > num:
return 'HIGH'
else:
return 'LOW'
else:
return 'Please enter number 1 to 100'
C8 Socket Programming 48
def main():
counter = 5
while counter > 0:
guess = input('Guess a number 1 to 100: ')
if game(guess) == 'You win!':
high_low.py
print(game(guess))
break
else:
print(game(guess))
counter -= 1
if counter == 0:
print('You ran out of tries! Game over.')
Copy the codes for game() and main() and save them in
the high_low.py program. Run the program and play the
game. Observe how the game is being implemented.
C8 Socket Programming 49
from socket import *
s = socket()
s.connect(('127.0.0.1', 12345))
Do not modify the
client program.
while True:
data = b''
while b'\n' not in data:
data += s.recv(1024)
received = data.decode().strip()
if received == 'LOW':
client.py
print('Your guess is too low.')
elif received == 'HIGH':
print('Your guess is too high.')
elif received == 'GUESS':
guess = input('Enter guess (1-100): ')
s.sendall(guess.encode() + b'\n')
elif received == 'WIN':
print('You win!')
break
elif received == 'GAMEOVER':
print('You ran out of tries! Game over.')
break
s.close()
C8 Socket Programming 50
from socket import * Must include the program code for
game(guess) and the random value num
my_socket = socket()
my_socket.bind(('127.0.0.1', 12345))
my_socket.listen()
(template) server.py
print('Type Ctrl-F6 or close the shell to \
terminate the server.')
new_socket, addr = my_socket.accept()
print('Connected to: ' + str(addr))
while True: Write the code and
include it here
new_socket.close()
my_socket.close()
C8 Socket Programming 51
Assignment 6
Symmetrical Game – "Scissor, Paper, Stone"
C8 Socket Programming 52
Assignment 6 :
1. The provided “scissor-paper-stone" program code is for a player
to play against the computer "Robot".
2. Modify the program code so that it becomes a symmetrical
game where a human "Player1" plays against another human
"Player2".
3. Write the server (as "Player2") and client (as "Player1") program
codes for the symmetrical game.
C8 Socket Programming 53
Consider the following 'Scissor, Paper, Stone' game:
# player1 is a human # player2 is a robot
from random import *
scissor-paper-stone.py
def game(opponent):
player2 = choice(['Scissor', 'Paper', 'Stone'])
print('Player2: ', player2)
if player2 == opponent:
return 'Draw'
elif (player2 == 'Scissor' and opponent == \
'Paper') or (player2 == 'Paper' and opponent == \
'Stone') or (player2 == 'Stone' and opponent == \
'Scissor'):
return 'Player2 wins!'
else:
return 'Player1 wins!'
C8 Socket Programming 54
def main():
print('You are Player1 playing against Player2')
counter = 3
d = {'1':'Scissor', '2':'Paper', '3':'Stone'}
scissor-paper-stone.py
while counter > 0:
player1 = input('Player1: Enter (1)Scissor,\
(2)Paper or (3)Stone : ')
if player1 in d:
print('Player1: ', d[player1])
print(game(d[player1]))
counter -= 1
else:
print('Please enter only 1, 2 or 3.')
Copy the codes for game() and main() and save them in
the scissor-paper-stone.py program.
Run the program and play the game. Observe how the game is
being implemented.
55
The End
Socket Programming