summaryrefslogtreecommitdiff
path: root/day4/task4/client.py
diff options
context:
space:
mode:
Diffstat (limited to 'day4/task4/client.py')
-rw-r--r--day4/task4/client.py131
1 files changed, 131 insertions, 0 deletions
diff --git a/day4/task4/client.py b/day4/task4/client.py
new file mode 100644
index 0000000..33ea084
--- /dev/null
+++ b/day4/task4/client.py
@@ -0,0 +1,131 @@
+import socket
+from time import sleep
+import struct
+import json
+import shelve
+
+
+def pack_data(data):
+ encoded = data.encode()
+ return struct.pack('I', len(encoded)) + encoded
+
+
+def prepare_data(data):
+ cmd, args = data.split(' ', maxsplit=1)
+
+ if cmd == 'get':
+ return json.dumps({'method': 'get', 'path': args})
+
+ elif cmd == 'cp':
+ paths = args.split()
+ if len(paths) != 2:
+ raise ValueError('Неверное количество путей в параметрах.')
+ src, dest = args.split()
+ if src not in db:
+ return json.dumps({'method': 'get_cp', 'path': src})
+ with open(dest, 'wb') as f:
+ f.write(db[src])
+
+ else:
+ raise ValueError('Команда не распознана')
+
+
+def parse_response(data):
+ return json.loads(data.decode())
+
+
+def get_response(connection):
+ buffer = b''
+ while len(buffer) < DATATYPE_SIZE:
+ data = connection.recv(DATATYPE_SIZE - len(buffer))
+ if not data:
+ raise ConnectionError('Connection was closed')
+
+ buffer += data
+
+ size_packed, buffer = buffer[:DATATYPE_SIZE], buffer[DATATYPE_SIZE:]
+ if not size_packed:
+ raise ConnectionError('Connection was closed')
+
+ (size,) = struct.unpack('I', size_packed)
+ data = connection.recv(size - len(buffer))
+ return parse_response(buffer + data)
+
+
+def download_file(filesize, connection):
+ data = b''
+ count = 0
+ while count < filesize:
+ (size,) = struct.unpack('I', connection.recv(DATATYPE_SIZE))
+ data += connection.recv(size)
+ count += size
+
+ return data
+
+
+def handle_response(data, connection):
+ if data['status'] == 0:
+ print(f'Загружаем файл размером {data["size"]} байт...')
+ file_data = download_file(data['size'], connection)
+ db[data['path']] = file_data
+ print('Загрузка завершена')
+
+ elif data['status'] == 1:
+ print(data['reason'])
+
+ elif data['status'] == 2:
+ print('Неизвестная ошибка:')
+ print(data['reason'])
+
+
+def try_connect():
+ cnt = 0
+ sock = socket.socket()
+ while cnt < 10:
+ try:
+ cnt += 1
+ sock.connect(ADDR)
+
+ except ConnectionRefusedError:
+ print('Не удалось подключиться к серверу. Следующая попытка через 3 секунды...')
+ sleep(3)
+
+ else:
+ return sock
+
+ else:
+ print('Не удалось подключиться к серверу через 10 попыток.\nОстанавливаемся...')
+ sock.close()
+ return
+
+
+HOST, PORT = ADDR = 'localhost', 6000
+DATATYPE_SIZE = 4 # int
+
+sock = try_connect()
+if sock is None:
+ quit()
+
+
+db = shelve.open('backdoor.db')
+
+while True:
+ try:
+ data = input('Введите команду:\n')
+ data = prepare_data(data)
+ if data is None:
+ continue
+
+ except KeyboardInterrupt:
+ break
+
+ except ValueError as err:
+ print(err)
+
+ else:
+ packet = pack_data(data)
+ sock.sendall(packet)
+ response = get_response(sock)
+ handle_response(response, sock)
+
+sock.close()