diff options
Diffstat (limited to 'day4/task4')
| -rw-r--r-- | day4/task4/client.py | 194 | ||||
| -rw-r--r-- | day4/task4/client_class.py | 134 | ||||
| -rw-r--r-- | day4/task4/server.py | 57 |
3 files changed, 123 insertions, 262 deletions
diff --git a/day4/task4/client.py b/day4/task4/client.py index bc4a40f..b6f0ab8 100644 --- a/day4/task4/client.py +++ b/day4/task4/client.py @@ -12,138 +12,124 @@ except ImportError: TQDM = False -def pack_data(data): - encoded = data.encode() - return struct.pack('I', len(encoded)) + encoded - - -def handle_input(data): - cmd, args = data.split(' ', maxsplit=1) - - if cmd == 'get': - make_get_request(args) - - elif cmd == 'cp': - paths = args.split() - if len(paths) != 2: - raise ValueError('Неверное количество путей в параметрах.') - - src, dest = paths - - # Если файл не присутствует в БД, то предварительно его загружаем - status = 0 - if src not in db: - status = make_get_request(src) - - if status == 0: - with open(dest, 'wb') as f: - f.write(db[src]) - - else: - raise ValueError('Команда не распознана') +DATATYPE_SIZE = 4 # int +CHUNK_SIZE = 4096000 +HOST, PORT = ADDR = 'localhost', 6000 -def make_get_request(path): - packet = pack_data(json.dumps({'method': 'get', 'path': path})) - sock.sendall(packet) - response = get_response() - return handle_response(response) +class Client: + def __init__(self, server_host, server_port): + self.server = socket.socket() + self.db = shelve.open('backdoor.db') + address = server_host, server_port + cnt = 0 + while cnt < 10: + try: + cnt += 1 + self.server.connect(address) -def parse_response(data): - return json.loads(data.decode()) + except ConnectionRefusedError: + print('Не удалось подключиться к серверу. Следующая попытка через 3 секунды...') + sleep(3) + else: + break -def get_response(): - buffer = b'' - while len(buffer) < DATATYPE_SIZE: - data = sock.recv(DATATYPE_SIZE - len(buffer)) - if not data: - raise ConnectionError('Connection was closed') + else: + print('Не удалось подключиться к серверу через 10 попыток.\nОстанавливаемся...') + self.server.close() - buffer += data + def start(self): + while True: + try: + data = input('Введите команду:\n') + self.handle_input(data) - size_packed, buffer = buffer[:DATATYPE_SIZE], buffer[DATATYPE_SIZE:] - if not size_packed: - raise ConnectionError('Connection was closed') + except ValueError as err: + print(err) - (size,) = struct.unpack('I', size_packed) - data = sock.recv(size - len(buffer)) - return parse_response(buffer + data) + except KeyboardInterrupt: + break + self.server.close() -def download_file(filesize): - data = b'' + def handle_input(self, data): + cmd, args = data.split(' ', maxsplit=1) - if TQDM: - for count in tqdm(range(0, filesize, CHUNK_SIZE)): - (size,) = struct.unpack('I', sock.recv(DATATYPE_SIZE)) - data += sock.recv(size) - else: - count = 0 - while count < filesize: - (size,) = struct.unpack('I', sock.recv(DATATYPE_SIZE)) - data += sock.recv(size) - count += size + if cmd == 'get': + self.download_file(args) - return data + elif cmd == 'cp': + paths = args.split() + if len(paths) != 2: + raise ValueError('Неверное количество путей в параметрах.') + src, dest = paths -def handle_response(data): - if data['status'] == 0: - print(f'Загружаем файл размером {data["size"]} байт...') - file_data = download_file(data['size']) - db[data['path']] = file_data - print('Загрузка завершена') + # Если файл не присутствует в БД, то предварительно его загружаем + if src not in self.db: + self.download_file(src) - elif data['status'] == 1: - print(data['reason']) + # При любых ошибках при загрузке файла download_file выкинет исключение и исполнение + # не дойдет до этого блока, поэтому можно не проверять наличие src в БД + with open(dest, 'wb') as f: + f.write(self.db[src]) - elif data['status'] == 2: - print('Неизвестная ошибка:') - print(data['reason']) + else: + raise ValueError('Команда не распознана') - return data['status'] + def download_file(self, path): + response = self.make_get_request(path) + if response['status'] == 0: + print(f'Загружаем файл размером {response["size"]} байт...') + file_data = self.receive_data(int(response['size']), use_tqdm=True) + self.db[path] = file_data -def try_connect(): - cnt = 0 - sock = socket.socket() - while cnt < 10: - try: - cnt += 1 - sock.connect(ADDR) + print('Загрузка завершена') - except ConnectionRefusedError: - print('Не удалось подключиться к серверу. Следующая попытка через 3 секунды...') - sleep(3) + elif response['status'] == 1: + raise ValueError(response['reason']) - else: - return sock + elif response['status'] == 2: + raise ValueError(f'Неизвестная ошибка: {response["reason"]}') - else: - print('Не удалось подключиться к серверу через 10 попыток.\nОстанавливаемся...') - sock.close() - return + def make_get_request(self, path): + packet = Client.pack_str(json.dumps({'method': 'get', 'path': path})) + self.server.sendall(packet) + return Client.parse_response(self.receive_data(DATATYPE_SIZE)) + def receive_data(self, data_size, use_tqdm=False): + data = b'' -HOST, PORT = ADDR = 'localhost', 6000 -DATATYPE_SIZE = 4 # int -CHUNK_SIZE = 4096000 + # С копипастой надо бы что-то сделать, но я не знаю что + if not use_tqdm or not TQDM: + while len(data) < data_size: + (packet_size,) = struct.unpack('I', self.server.recv(DATATYPE_SIZE)) + data += self.server.recv(packet_size) + if not data: + raise ConnectionError('Connection was closed') -sock = try_connect() -if sock is None: - quit() + elif TQDM: + for count in tqdm(range(0, data_size, CHUNK_SIZE)): + (packet_size,) = struct.unpack('I', self.server.recv(DATATYPE_SIZE)) + data += self.server.recv(packet_size) + if not data: + raise ConnectionError('Connection was closed') + return data -db = shelve.open('backdoor.db') + @staticmethod + def pack_str(data): + encoded = data.encode() + return struct.pack('I', len(encoded)) + encoded -while True: - try: - data = input('Введите команду:\n') - handle_input(data) + @staticmethod + def parse_response(data): + return json.loads(data.decode()) - except KeyboardInterrupt: - break -sock.close() +if __name__ == '__main__': + client = Client(HOST, PORT) + client.start() diff --git a/day4/task4/client_class.py b/day4/task4/client_class.py deleted file mode 100644 index 854e5e2..0000000 --- a/day4/task4/client_class.py +++ /dev/null @@ -1,134 +0,0 @@ -import socket -from time import sleep -import struct -import json -import shelve - -try: - from tqdm import tqdm - TQDM = True -except ImportError: - print('Для вывода прогресса загрузки файлов установите библиотеку tqdm') - TQDM = False - - -DATATYPE_SIZE = 4 # int -CHUNK_SIZE = 4096000 -HOST, PORT = ADDR = 'localhost', 6000 - - -class Client: - def __init__(self, server_host, server_port): - self.server = socket.socket() - self.db = shelve.open('backdoor.db') - - address = server_host, server_port - cnt = 0 - while cnt < 10: - try: - cnt += 1 - self.server.connect(address) - - except ConnectionRefusedError: - print('Не удалось подключиться к серверу. Следующая попытка через 3 секунды...') - sleep(3) - - else: - break - - else: - print('Не удалось подключиться к серверу через 10 попыток.\nОстанавливаемся...') - self.server.close() - - def start(self): - while True: - try: - data = input('Введите команду:\n') - self.handle_input(data) - - except ValueError as err: - print(err) - - except KeyboardInterrupt: - break - - self.server.close() - - def handle_input(self, data): - cmd, args = data.split(' ', maxsplit=1) - - if cmd == 'get': - self.download_file(args) - - elif cmd == 'cp': - paths = args.split() - if len(paths) != 2: - raise ValueError('Неверное количество путей в параметрах.') - - src, dest = paths - - # Если файл не присутствует в БД, то предварительно его загружаем - if src not in self.db: - self.download_file(src) - - # При любых ошибках при загрузке файла download_file выкинет исключение и исполнение - # не дойдет до этого блока, поэтому можно не проверять наличие src в БД - with open(dest, 'wb') as f: - f.write(self.db[src]) - - else: - raise ValueError('Команда не распознана') - - def download_file(self, path): - response = self.make_get_request(path) - if response['status'] == 0: - print(f'Загружаем файл размером {response["size"]} байт...') - - file_data = self.receive_data(int(response['size']), use_tqdm=True) - self.db[path] = file_data - - print('Загрузка завершена') - - elif response['status'] == 1: - raise ValueError(response['reason']) - - elif response['status'] == 2: - raise ValueError(f'Неизвестная ошибка: {response["reason"]}') - - def make_get_request(self, path): - packet = Client.pack_str(json.dumps({'method': 'get', 'path': path})) - self.server.sendall(packet) - return Client.parse_response(self.receive_data(DATATYPE_SIZE)) - - def receive_data(self, data_size, use_tqdm=False): - data = b'' - - # С копипастой надо бы что-то сделать, но я не знаю что - if not use_tqdm or not TQDM: - while len(data) < data_size: - (packet_size,) = struct.unpack('I', self.server.recv(DATATYPE_SIZE)) - data += self.server.recv(packet_size) - if not data: - raise ConnectionError('Connection was closed') - - elif TQDM: - for count in tqdm(range(0, data_size, CHUNK_SIZE)): - (packet_size,) = struct.unpack('I', self.server.recv(DATATYPE_SIZE)) - data += self.server.recv(packet_size) - if not data: - raise ConnectionError('Connection was closed') - - return data - - @staticmethod - def pack_str(data): - encoded = data.encode() - return struct.pack('I', len(encoded)) + encoded - - @staticmethod - def parse_response(data): - return json.loads(data.decode()) - - -client = Client(HOST, PORT) -client.start() diff --git a/day4/task4/server.py b/day4/task4/server.py index fb88629..d013b35 100644 --- a/day4/task4/server.py +++ b/day4/task4/server.py @@ -3,6 +3,11 @@ import struct import json +HOST, PORT = ADDR = '0.0.0.0', 6000 +CHUNK_SIZE = 4096000 +DATATYPE_SIZE = 4 # int + + def pack_str(data: str): encoded = data.encode() return struct.pack('I', len(encoded)) + encoded @@ -54,14 +59,15 @@ def handle_request(data, connection): def get_data(connection): buffer = b'' - while len(buffer) < 4: - data = connection.recv(4 - len(buffer)) + # Считываем размер пакета + 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[:4], buffer[4:] + size_packed, buffer = buffer[:DATATYPE_SIZE], buffer[DATATYPE_SIZE:] if not size_packed: raise ConnectionError('Connection was closed') @@ -93,24 +99,27 @@ def handle_connection(connection, address): handle_request(data.decode(), connection) -HOST, PORT = ADDR = '0.0.0.0', 6000 -CHUNK_SIZE = 4096000 -sock = socket.socket() -sock.bind(ADDR) -sock.listen(5) - -while True: - print('Listening for new connections...') - try: - connection, address = sock.accept() - print(f'Got a connection from {address[0]}') - handle_connection(connection, address) - - except ConnectionResetError: - print(f'Connection with {address[0]} was unexpectedly closed') - - except KeyboardInterrupt: - print('Stopping server...') - sock.close() - print('Server stopped') - break +def main(): + sock = socket.socket() + sock.bind(ADDR) + sock.listen(5) + + while True: + print('Listening for new connections...') + try: + connection, address = sock.accept() + print(f'Got a connection from {address[0]}') + handle_connection(connection, address) + + except ConnectionResetError: + print(f'Connection with {address[0]} was unexpectedly closed') + + except KeyboardInterrupt: + print('Stopping server...') + sock.close() + print('Server stopped') + break + + +if __name__ == '__main__': + main() |