Session 9: Client server model (II) - myTeachingURJC/2018-19-PNE GitHub Wiki
Session 9. Week 5: Client-server model (II)
- Goals:
- Learn about the client-server model
- Write our first server using sockets
- Understand how the server works
- Learn how to install packages
- Duration: 2h
- Date: Week 5: Tuesday, Feb-19th-2019
- These session consist of the teacher's guidelines for driving the Lecture, following the learn by doing approach
Contents
- Server side
- Example 1: Configuring our first server
- Example 2: Waiting for connections
- Example 3: The echo server
- Client Blocking the server
- Installing libraries: termcolor
- Exercise 1
- Authors
- Credits
- License
The server side
- The servers initially create one socket, bound to the IP and the PORT where the clients should connect
- They wait, until a client connects
- In our examples: the server only can attend one client at a time
- Once the client is connected, a new socket is created: this sockets allows the server to communicate with the client
- The server reads the request message, process it and generates the response
- Then it waits for the next client
- The clients are queued
Example 1: Configuring our first server
This is the code for configuring our server's socket. first the socket should be created. Then bound to the IP and PORT and finally change to listen mode
import socket
# Configure the Server's IP and PORT
PORT = 8085
IP = "192.168.1.36"
MAX_OPEN_REQUESTS = 5
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the IP and PORT
serversocket.bind((IP, PORT))
# Configure the server sockets
# MAX_OPEN_REQUESTS connect requests before refusing outside connections
serversocket.listen(MAX_OPEN_REQUESTS)
print("Socket ready: {}".format(serversocket))
- Run and execute step by step
- Check that non of the configuration methods is blocking the server
Example 2: Waiting for connections
Once the server is configured, we use the socket's accept() method for waiting for a client to communicate. Once the client is connected, a new socket is created (clientsocket). This new socket is bound to another port. And it is only use for communicating exclusiverly with that client
import socket
# Configure the Server's IP and PORT
PORT = 8085
IP = "192.168.1.36"
MAX_OPEN_REQUESTS = 5
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the IP and PORT
serversocket.bind((IP, PORT))
# Configure the server sockets
# MAX_OPEN_REQUESTS connect requests before refusing outside connections
serversocket.listen(MAX_OPEN_REQUESTS)
print("Socket ready: {}".format(serversocket))
while True:
# accept connections from outside
# The server is waiting for connections
print("Waiting for connections at {}, {} ".format(IP, PORT))
(clientsocket, address) = serversocket.accept()
# Connection received. A new socket is returned for communicating with the client
print("Attending connections from client: {}".format(address))
# This server do nothing. The new socket is closed
clientsocket.close()
- Run the server. You need to have a client that simply connects to the server. Whenever the clients is connected, a message like this is shown in the console:
Attending connections from client: ('192.168.1.36', 51910)
-
Execute step by step
-
This is an example of a client (the same we use the previous week). Just for you to copy&paste:
import socket
# SERVER IP, PORT
IP = "192.168.1.36"
PORT = 8086
# Create the socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# establish the connection to the Server (IP, PORT)
s.connect((IP, PORT))
# Close the socket
s.close()
Example 3: The echo server
Once the server have the new socket for communicating with the client, the use is exactly the same than we did last week with the clients. We use the send() and recv() socket's method for communicating with the client.
Let's develop a server that just send back the request messages from the clients. This is called an echo server (Because it echoed back all the received messsages)
The new socket is passed as an argument to the processs_client() function, that is in charge of servicing the client
import socket
# Configure the Server's IP and PORT
PORT = 8086
IP = "192.168.1.36"
MAX_OPEN_REQUESTS = 5
def process_client(cs):
"""Process the client request.
Parameters: cs: socket for communicating with the client"""
# Read client message. Decode it as a string
msg = cs.recv(2048).decode("utf-8")
# Print the received message, for debugging
print("Request message: {}".format(msg))
# Send the msg back to the client (echo)
cs.send(str.encode(msg))
# Close the socket
cs.close()
# MAIN PROGRAM
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the IP and PORT
serversocket.bind((IP, PORT))
# Configure the server sockets
# MAX_OPEN_REQUESTS connect requests before refusing outside connections
serversocket.listen(MAX_OPEN_REQUESTS)
print("Socket ready: {}".format(serversocket))
while True:
# accept connections from outside
# The server is waiting for connections
print("Waiting for connections at {}, {} ".format(IP, PORT))
(clientsocket, address) = serversocket.accept()
# Connection received. A new socket is returned for communicating with the client
print("Attending connections from client: {}".format(address))
# Service the client
process_client(clientsocket)
This is the test program: a client that just connect to the server, send a message and print the echo from the server
import socket
# SERVER IP, PORT
IP = "192.168.1.36"
PORT = 8086
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# establish the connection to the Server (IP, PORT)
s.connect((IP, PORT))
msg = "Hello"
# Send the request message to the server
s.send(str.encode(msg))
# Receive the servers respoinse
response = s.recv(2048).decode()
# Print the server's response
print("Response: {}".format(response))
s.close()
Client blocking the server
Try the following client. It connects to the server, ask the user to enter a message, send the message to the server, read the server's response (the echo) and repeat it again
import socket
# SERVER IP, PORT
IP = "192.168.1.36"
PORT = 8087
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# establish the connection to the Server (IP, PORT)
s.connect((IP, PORT))
# The client is blocking the server.... NOT A GOOD DESIGN!!!
msg = input("> ")
# Send the request message to the server
s.send(str.encode(msg))
# Receive the servers respoinse
response = s.recv(2048).decode()
# Print the server's response
print("Response: {}".format(response))
s.close()
- Run the echo server and the cliet. Can you see any problem??
- YES! The client is not well design. It is blocking the server while the user is entering the message... that should be avoided. This is a better solution:
import socket
# SERVER IP, PORT
IP = "192.168.1.36"
PORT = 8087
while True:
# Before connecting to the server, ask the user for the string
msg = input("> ")
# Now we can create the socket and connect to the servewr
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# establish the connection to the Server (IP, PORT)
s.connect((IP, PORT))
# Send the request message to the server
s.send(str.encode(msg))
# Receive the servers respoinse
response = s.recv(2048).decode()
# Print the server's response
print("Response: {}".format(response))
s.close()
Installing libraries: termcolor
There are many python libraries available for you to use. You only have to install them. This installation depends on the type of python interpreter you have installed
- Go to the Settings/project-2018-19-PNE-practises/project interpreter
- on the top right, click on the gear icon to add a python interpreter
- Click on virtualenv environment if that is not your current python interpreter. Click on OK
- A new venv folder will appear in your project (make sure this folder is excluded from your project)
Now we can install and use other libraries. Let's install termcolor: a library for printing with color on the console
- Create a new python file with the following test code:
import termcolor
termcolor.cprint("Hey! this is printed in green!", 'green')
- The termcolor word will be mark as an unknown module. Click on the red bulb and click on "Install package termcolor". It will automatically be installed
- Run the example code. You will see the text printed in green color
Exercise 1
Modify the echo server:
- It should print the messages from the client in a different color in the console (using termcolor)
- If the received message from the client is the word "EXIT", the server should finish
Use a client that ask the user to enter a messsage, and then send the message to the echo server. The response is printed in a different color (using termcolor)
Authors
- Boni García
- Juan González-Gómez (Obijuan)
Credits
- Alvaro del Castillo. He designed and created the original content of this subject. Thanks a lot :-)