Bladeren bron

add python server and client

master
erichhasl 8 jaren geleden
commit
aa793be1db
3 gewijzigde bestanden met toevoegingen van 326 en 0 verwijderingen
  1. +6
    -0
      .gitignore
  2. +133
    -0
      python/client.py
  3. +187
    -0
      python/server.py

+ 6
- 0
.gitignore Bestand weergeven

@@ -0,0 +1,6 @@
*.swp
*.swo
*.swn
*.swm
python/__pycache__/*
*.pyc

+ 133
- 0
python/client.py Bestand weergeven

@@ -0,0 +1,133 @@
import socket
import struct
import ssl
from threading import Thread
import select


class SocketClient:

NO_BUFFERING = 0
LENGTH_BUFFERING = 1
DELIMITER_BUFFERING = 2

def __init__(self, ssl_cert=None, buffering=LENGTH_BUFFERING,
delimiter='\n'):
self.terminated = False
self.connected = False
self.ssl_cert = ssl_cert
self.buffering = buffering
self.delimiter = delimiter
self.left = b''
print("Initialized socket client")

def connect(self, host, port):
try:
self.socket = socket.socket()
# if using a ssl certificate, wrap the socket using ssl
if self.ssl_cert:
self.socket = ssl.wrap_socket(self.socket,
ca_certs=self.ssl_cert,
cert_reqs=ssl.CERT_REQUIRED)
self.socket.connect((host, port))
self.connected = True
return True
except socket.error:
print("ERROR: Error while connecting!")
self.connected = False
return False

def start(self):
print("Client has started")
Thread(target=self.handle_server).start()

def disconnect(self):
print("disconnecting")
self.connected = False
self.send("quit")
self.terminated = True
self.socket.close()

def send(self, data):
try:
if self.buffering is SocketClient.DELIMITER_BUFFERING:
msg = (data + self.delimiter).encode()
elif self.buffering is SocketClient.LENGTH_BUFFERING:
msg = struct.pack('>I', len(data)) + data.encode()
else:
msg = data.encode()
self.socket.sendall(msg)
except Exception as e:
print("ERROR: Error while sending", e)

def handle_server(self):
while not self.terminated:
try:
read_sockets, write_sockets, in_error = \
select.select([self.socket, ], [self.socket, ], [], 5)
except select.error:
print("FATAL ERROR: Connection error")
self.socket.shutdown(2)
self.socket.close()
if len(read_sockets) > 0:
if self.buffering is SocketClient.DELIMITER_BUFFERING:
recv, self.left = recvuntil(self.socket, self.delimiter,
self.left)
elif self.buffering is SocketClient.LENGTH_BUFFERING:
raw_msglen = recvall(self.socket, 4)
if not raw_msglen:
print("Connection closed")
self.on_quit()
return None
msglen = struct.unpack('>I', raw_msglen)[0]
recv = recvall(self.socket, msglen)
elif self.buffering is SocketClient.NO_BUFFERING:
recv = self.socket.recv(2048)

if len(recv) > 0:
reply = self.on_receive(recv)
if len(write_sockets) > 0 and reply:
self.socket.send(reply)
print("finished handling server")

def on_receive(self, query):
pass

def on_quit(self):
pass


def recvall(sock, n):
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data


def recvuntil(sock, delimiter, left_over):
data = left_over
left = b''
while True:
packet = sock.recv(512)
if not packet:
return None
data += packet
idx = data.find(delimiter.encode())
if idx >= 0:
data = data[:idx]
left = data[idx+len(delimiter):]
break
return data, left

if __name__ == '__main__':
client = SocketClient(buffering=SocketClient.DELIMITER_BUFFERING,
delimiter='\r\n')
client.connect('localhost', 4242)
client.start()
client.on_receive = lambda x: print("-->", x)
while True:
x = input("> ")
client.send(x)

+ 187
- 0
python/server.py Bestand weergeven

@@ -0,0 +1,187 @@
import socket
import select
import ssl
import struct
import threading
from threading import Thread
import logging as log


class SocketServer:

NO_BUFFERING = 0
LENGTH_BUFFERING = 1
DELIMITER_BUFFERING = 2

def __init__(self, ssl_cert=None, ssl_key=None, buffering=LENGTH_BUFFERING,
delimiter='\n'):
self.terminated = False
self.connected = False
self.buffering = buffering
self.ssl_cert, self.ssl_key = ssl_cert, ssl_key
self.delimiter = delimiter
log.debug("Initialized socket server")

def connect(self, host, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

if self.ssl_cert and self.ssl_key:
self.socket = ssl.wrap_socket(self.socket,
certfile=self.ssl_cert,
keyfile=self.ssl_key,
server_side=True)
try:
self.socket.bind((host, port))
except socket.error as e:
log.critical("Error: %s", str(e))
self.socket.listen(5)

def start(self):
Thread(target=self.wait_for_connections).start()

def wait_for_connections(self):
while not self.terminated:
self.accept_connection()

def accept_connection(self):
if self.terminated:
return
try:
conn, addr = self.socket.accept()
except OSError as e:
log.error("OSError while accepting connection: %s", str(e))
return
Thread(target=self.pre_handle_client, args=(conn, addr)).start()

def clean_up(self):
self.terminated = True
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()

def pre_handle_client(self, conn, addr):
log.info("Established connection to %s", addr)
client = ClientConnection(conn, addr, self.buffering, self.delimiter)
connected = self.on_connect(client)

while not self.terminated and connected:
try:
read, write, error = select.select([client.conn, ],
[client.conn, ],
[], 5)
except (select.error, ValueError):
log.warn("FATAL ERROR: Connection error %s", addr)
self.on_disconnect(client)
break
if len(read) > 0:
text = client.recv()
if text is None:
log.critical("no text --> disconnecting")
self.on_disconnect(client)
break
log.debug("Received: %s %s", text, addr)
try:
reply = self.on_receive(client, text)
except TypeError:
pass
else:
if reply is not None:
client.send(reply)

log.critical("Terminating connection with %s", addr)
client.quit()

def on_receive(self, client, query):
return query

def on_connect(self, client):
return True

def on_disconnect(self, client):
pass


class ClientConnection:

def __init__(self, conn, addr, buffering, delimiter):
self.conn = conn
self.addr = addr
self.lock = threading.Lock()
self.buffering, self.delimiter = buffering, delimiter
self.left = b''

def ask(self, key, question):
self.send(key, question)
self.conn.settimeout(2)
return self.recv()

def recv(self):
try:
if self.buffering is SocketServer.DELIMITER_BUFFERING:
recv, self.left = recvuntil(self.conn, self.delimiter,
self.left)
elif self.buffering is SocketServer.LENGTH_BUFFERING:
raw_msglen = recvall(self.conn, 4)
if not raw_msglen:
log.debug("%s No msglen: EOF", self.addr)
return None
msglen = struct.unpack('>I', raw_msglen)[0]
recv = recvall(self.conn, msglen)
else:
recv = self.conn.recv(1024)
return recv.decode("utf-8")
except Exception as e:
log.critical("%s Error while receiving: %s", self.addr, str(e))
return None

def send(self, query):
if self.buffering is SocketServer.DELIMITER_BUFFERING:
msg = (query + self.delimiter).encode()
elif self.buffering is SocketServer.LENGTH_BUFFERING:
msg = struct.pack('>I', len(query)) + query.encode()
else:
msg = query.encode()
with self.lock:
try:
self.conn.sendall(msg)
except Exception as e:
log.debug("%s Failed to send %s: %s", self.addr, msg, e)

def on_recv(self):
pass

def quit(self):
self.conn.close()


def recvall(sock, n):
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data


def recvuntil(sock, delimiter, left_over):
data = left_over
left = b''
while True:
packet = sock.recv(512)
if not packet:
return None
data += packet
idx = data.find(delimiter.encode())
if idx >= 0:
data = data[:idx]
left = data[idx+len(delimiter):]
break
return data, left

if __name__ == '__main__':
log.basicConfig(level=log.DEBUG)
server = SocketServer(buffering=SocketServer.DELIMITER_BUFFERING,
delimiter='\r\n')
server.connect('localhost', 4242)
server.start()

Laden…
Annuleren
Opslaan