Develop two Python scripts: one a server; the other a client that will use the s
ID: 3604148 • Letter: D
Question
Develop two Python scripts: one a server; the other a client that will use the server. Use the polynomial function module “polynomials.py”. Do not include those functions directly into your server code, but import them into the server (see Additional Notes below).
polynomials.py:
https://pastebin.com/iCNhsEiT
Server
The server will listen on a specific port number (ex. 12345). It will carry out polynomial computations using the functions in the provided module. Requests are in one of two formats:
Evaluate Request
Request starts with ‘E’
Followed by an argument value
Followed by a single space
Followed by the coefficients of a polynomial, separated by single spaces
Bisection Request
Requests starts with ‘S’
Followed by ‘a’, ‘b’, polynomial, tolerance separated by single spaces
For example, here is a sample evaluate request:
E1.0 -945 1689 -950 230 -25 1
This is a request to evaluate the polynomial
-945 + 1689x - 950x2 + 230x3 - 25x4 + x5
at the value x = 1.0
Here is a sample bisection request:
S0 2 -945 1689 -950 230 -25 1 1e-15
This requests the use of the bisection function with a = 0, b = 2, tolerance = 1e-15 and using the same polynomial as in the evaluate example.
The server will create a response to the client for each request. The first character of the response will indicate the type of response:
‘X’ indicates an error response. The remainder of the response is an error message
‘E’ indicates a successful response to an evaluate request. This is immediately followed by the value returned by the evaluate function
‘S’ indicates a successful response to a bisection request. This is immediately followed by the value returned by the bisection function
The response to the example evaluate request would be2
E2.2737367544323206e-13
The response to the example bisection request would be
S1.0000000000000004
The server should operate in a continuing manner: the server should repeatedly accept a connection, get a request, send a response and close the connection to the client. In particular, only one request is handled for each connection.
Server Error Checking
The server should respond properly in the case of an erroneous request. Not only should the server not ‘crash’ but the server should send back an appropriate error response to the client.
For example, the request string
E1.0 -945xx 1689 -950 230 -25 1
should result in a response something like this:
Xinvalid format numeric data
Note the ‘X’ that flags this as an error message.
Include error checking in the server. Also document the error checking by including a string at the end of the server code that describes the errors caught. That string might look something like this (to start with):
'''
Invalid numeric format
Wrong number of fields in request
'''
Client
You are strongly urged to write small clients that will test aspects of your server as you work on that. Once you are satisfied that you can send an evaluation request and get a good result and also send a bisection request and get a good result then work on the client described here.
The client should define four variables at the beginning: the first, named poly with a list of numbers representing the coefficients of a polynomial;3 another, named ‘a’, representing a value a to use in bisection; another, named b representing a value b to use in bisection; another, named tol representing a tolerance value to use in bisection.
Note: in testing your client, the values assigned to these variables will be changed so make sure they are evident.
The client should first make a request to the server for a bisection. Provide the data defined in the variables just described. Display the value returned.
The result from the first request should be used as the x value in another request to the server to evaluate the polynomial (defined in the variable described above).
The result of the evaluation should be displayed. This value should be very close to 0.
Additional notes:
The client will do not numeric computations at all, it is just sending and receiving data. The most it does is get substrings and concatenate strings.
The result is in scientific notation. The value of the result is very near 0.
This value should not be string, it should be a list of numeric values.
Explanation / Answer
poly_server.py
import socket
import logging
import polynomials
"""
# DESCRIPTION ##########################################################################################################
The server will listen on port 12321.
It will carry out polynomial computations using the functions in the provided module.
Requests are in one of two formats:
* Evaluate Request
* Request starts with ‘E’
* Followed by an argument value
* Followed by a single space
* Followed by he coefficients of a polynomial, separated by single spaces
* Ex.) E1.0 -945 1689 -950 230 -25 1
* Bisection Request
* Requests starts with ‘S’
* Followed by ‘a’, ‘b’, polynomial, tolerance separated by single spaces
########################################################################################################################
"""
logging.basicConfig(filename='poly_server.log', level=logging.INFO)
host = "localhost"
port = 12321
listener = socket.socket() # listener is used just to start a connection
listener.bind((host, port))
listener.listen()
startMessage = "Server Started on {}:{}. ".format(host, port)
print(startMessage)
while 1:
conn = listener.accept() # conn is used to communicate through a connection
sock = conn[0] # get the socket from the connection
# get the request from the client
request = ""
encoded_message = sock.recv(2048)
while len(encoded_message) > 0:
request += encoded_message.decode()
encoded_message = sock.recv(2048) # possibility that decode error from
# split encoding
logging.info(" request received |" + request + "|")
print("request received |" + request + "|")
if len(request) == 0:
message = "XEmpty request"
logging.error(" response " + message)
sock.sendall(message.encode())
sock.shutdown(1)
else:
request_code = request[0] # assuming the message has at least one character
if request_code == "E":
try:
parameters = request[1:].split(' ')
args = [float(x) for x in parameters]
x = args[0]
poly = args[1:]
value = polynomials.evaluate(x, poly)
message = "E" + str(value)
logging.info("response " + message)
sock.sendall(message.encode())
sock.shutdown(1)
except Exception as ex:
logging.error("Input value conversion error " + request[1:])
logging.error(str(ex))
message = "X Invalid format numeric data: " + request[1:]
logging.error("response " + message)
sock.sendall(message.encode())
sock.shutdown(1)
elif request_code == "S":
try:
parameters = request[1:].split(' ')
args = [float(x) for x in parameters]
a = args[0]
b = args[1]
poly = args[2:8]
tol = args[8]
value = polynomials.bisection(a, b, poly, tol)
message = "S" + str(value)
logging.info("response " + message)
sock.sendall(message.encode())
sock.shutdown(1)
except Exception as ex:
logging.error("Input value conversion error " + request[1:])
logging.error(str(ex))
message = "X Invalid format numeric data: " + request[1:]
logging.error("response " + message)
sock.sendall(message.encode())
sock.shutdown(1)
else:
message = "XInvalid request code: " + request_code
logging.error("response " + message)
sock.sendall(message.encode())
sock.shutdown(1)
sock.close()
poly_client.py
import socket
'''
# DESCRIPTION ##########################################################################################################
# This Client connects to a Polynomial Server at "localhost:12321",
# Evaluates a Bisection,
# And then Evaluates a polynomial based on the result.
# Bisection : S0 2 -945 1689 -950 230 -25 1 1e-15
# Evaluate : E1.0 -945 1689 -950 230 -25 1
########################################################################################################################
'''
host = "localhost"
port = 12321
# Evaluate which mode we are based on code and construct the proper message string.
def eval_mode(_c, _a, _b, _p, _t):
if _c == "E":
msg = _c + str(_a) + " "
msg += ' '.join(str(x) for x in _p)
elif code == "S":
msg = _c + str(_a) + " " + str(_b) + " "
msg += ' '.join(str(x) for x in _p)
msg += " " + str(_t)
else: # Default, just add all parameters and keep going. Server should catch any errors.
msg = _c + str(_a) + " " + str(_b) + " "
msg += ' '.join(str(x) for x in _p)
msg += " " + str(_t)
return msg
# Send a message to the server with the given variables.
def send(_c, _a, _b, _p, _t):
sck = socket.socket()
sck.connect((host, port))
message = eval_mode(_c, _a, _b, _p, _t)
print("Sending: " + message)
encoded_message = message.encode()
sck.sendall(encoded_message)
sck.shutdown(1)
res = ""
encoded_message = sck.recv(2048)
while len(encoded_message) > 0:
res += encoded_message.decode()
encoded_message = sck.recv(2048)
print("Received: " + res)
print()
sck.close()
return res
# __main __ ############################################################################################################
# VARIABLES
code = "S"
a = 0
b = 2
poly = [-945, 1689, -950, 230, -25, 1]
tol = 1e-15
print()
response = send(code, a, b, poly, tol)
resCode = response[0]
if resCode == "E":
# do nothing
pass
elif resCode == "S":
a = float(response[1:])
code = "E"
send(code, a, b, poly, tol)
polynomials.py
"""
Polynomial manipulations.
Polynomials are represented as lists of coefficients, 0 order first.
"""
def evaluate(x, poly):
"""
Evaluate the polynomial at the value x.
poly is a list of coefficients from lowest to highest.
:param x: Argument at which to evaluate
:param poly: The polynomial coefficients, lowest order to highest
:return: The result of evaluating the polynomial at x
"""
if len(poly) == 0:
return 0
else:
return x*evaluate(x,poly[1:]) + poly[0]
def bisection(a, b, poly, tolerance):
"""
Assume that poly(a) <= 0 and poly(b) >= 0.
Modify a and b so that abs(b-a) < tolerance and poly(b) >= 0 and poly(a) <= 0.
Return (a+b)/2
:param a: poly(a) <= 0
:param b: poly(b) >= 0
:param poly: polynomial coefficients, low order first
:param tolerance: greater than 0
:return: an approximate root of the polynomial
"""
if evaluate(a, poly) > 0:
raise Exception("poly(a) must be <= 0")
if evaluate(b,poly) < 0:
raise Exception("poly(b) must be >= 0")
mid = (a+b) / 2
if abs(b-a) <= tolerance:
return mid
else:
val = evaluate(mid,poly)
if val <= 0:
return bisection(mid, b, poly, tolerance)
else:
return bisection(a, mid, poly, tolerance)
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.