Skip to content
Permalink
Browse files

Implement key value store with socket server

  • Loading branch information
chelseatroy committed Dec 15, 2019
1 parent 4d2c807 commit fd8a427c8d301174f0c01972c0866845d37e098f
Showing with 78 additions and 45 deletions.
  1. +16 −16 echo_client.py
  2. +62 −29 echo_server.py
@@ -9,22 +9,22 @@
print(f"connecting to {server_address[0]} port {server_address[1]}")
sock.connect(server_address)

try:
while True:

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

This whole file looks like it was changed, and it wasn't. I added a run loop to the client file because previously, after every command I sent with the client, the client stopped running and I needed to restart it. This allows me to have the client run continuously and send multiple commands to the server. The addition of this while True: has nothing to do with the key value store. Naughty Chelsea polluted a commit. Shame!

try:
# Send data
message = input("Type your message:\n")
print(f"sending {message}")

# Send data
message = input("Type your message:\n")
print(f"sending {message}")
sock.sendall(message.encode('utf-8'))
sock.sendall(message.encode('utf-8'))

# Look for the response
amount_received = 0
amount_expected = len(message)
# Look for the response
amount_received = 0
amount_expected = len(message)

while amount_received < amount_expected:
data = sock.recv(16)
amount_received += len(data)
print(f"received {data}")

finally:
print(f"closing socket")
sock.close()
while amount_received < amount_expected:
data = sock.recv(16)
amount_received += len(data)
print(f"received {data}")
except:
print(f"closing socket")
sock.close()
@@ -1,32 +1,65 @@
import socket
import sys

server_address = ('localhost', 10000)
print(f"starting up on {server_address[0]} port {server_address[1]}")

sock = socket.socket()
sock.bind(server_address)

sock.listen(1)

while True:
print('waiting for a connection')
connection, client_address = sock.accept()

try:
print(f"connection from {client_address}")

# Receive the data in small chunks and retransmit it
while True:
data = connection.recv(16)
print(f"received {data}")
if data:
print(f"sending data back to the client")
connection.sendall(data)
else:
print(f"no more data from {client_address}")
break

finally:
# Clean up the connection
connection.close()
data = {}

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

This is our ersatz data store for now. These curly braces tell Python that this is going to be a dictionary.



def get(key):
return data[key]

def set(key, value):
data[key] = value

def delete(key):
del data[key]

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

Here are our three methods on our server, which shell out directly to methods in the Python dictionary API.


def run_server():
server_address = ('localhost', 10000)
print(f"starting up on {server_address[0]} port {server_address[1]}")

sock = socket.socket()
sock.bind(server_address)
sock.listen(1)
while True:
print('waiting for a connection')
connection, client_address = sock.accept()

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

So, we accept the connection from our client...


try:
print(f"connection from {client_address}")

# Receive the data in small chunks and retransmit it
while True:
operation = connection.recv(16)
string_operation = operation.decode("utf-8")

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

decode it from a string to bytes...


print(f"received {string_operation} of type {type(string_operation)}")
if operation:

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

and now, instead of spitting the comment directly back to the client, we are going to do something fancier with it. We will parse it to determine what the client wants!

command, key, value = 0,1,2
operands = string_operation.split(" ")

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

Our client will send commands in the following fashion:

set key value
get key
delete key

For now, we will assume that clients know this, and we won't put in a bunch of code attempting to parse an invalid command. Instead, we'll send back "Sorry, I don't understand that command" if the command does not fit one of these formats.

response = "Sorry, I don't understand that command."

if operands[command] == "get":
response = get(operands[key])
elif operands[command] == "set":
set(operands[key], operands[value])
response = f"key {operands[key]} set to {operands[value]}"
elif operands[command] == "delete":
delete(operands[key])
response = f"key {key} deleted"
elif operands[command] == "show":
response = str(data)

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

For debugging purposes, let's add one more command for now: show, which will send back a string representation of the whole data store that the server has right now.

else:
pass

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

Chelsea, I hate long chains of elifs like that. Why didn't you do that in a more object-oriented way?

Because this is a practice project and all this code is gonna get a lot more complicated later, I promise.

But more broadly, because I don't have enough information about the problem space yet to trust my judgment about where the seams go to separate responsibilities in my app. Moving responsibilities between separate objects, or consolidating them into one object, takes more time and energy than splitting them out. So I will wait until I understand the problem better and feel more confident in my understanding of who should have what responsibilities before I start splitting them apart.

connection.sendall(response.encode('utf-8'))

This comment has been minimized.

Copy link
@chelseatroy

chelseatroy Dec 22, 2019

Author Owner

Gotta encode back into bytes to send a response!


else:
print(f"no more data from {client_address}")
break

finally:
# Clean up the connection
connection.close()

run_server()

0 comments on commit fd8a427

Please sign in to comment.
You can’t perform that action at this time.