import socket import struct import json def pack_str(data: str): encoded = data.encode() return struct.pack('I', len(encoded)) + encoded def pack_bytes(data: bytes): return struct.pack('I', len(data)) + data def handle_request(data, connection): request = json.loads(data) # Хотя метод только один, но все равно лучше # сразу написать расширяемое приложение if request['method'] == 'get': path = request['path'] try: with open(path, 'rb') as f: file_data = f.read() except FileNotFoundError: header = json.dumps({'status': 1, 'reason': 'Файл не найден'}) connection.sendall(pack_str(header)) except PermissionError: header = json.dumps({'status': 1, 'reason': 'Файл не доступен для чтения'}) connection.sendall(pack_str(header)) # Я знаю, что это плохо, но сервер не должен падать, # а других ошибок я не смог вспомнить except Exception as e: header = json.dumps({'status': 2, 'reason': str(e)}) connection.sendall(pack_str(header)) else: length = len(file_data) header = json.dumps({'status': 0, 'size': length, 'path': request['path']}) connection.sendall(pack_str(header)) i = 0 while i < length: packet = pack_bytes(file_data[i: i + CHUNK_SIZE]) connection.sendall(packet) i += CHUNK_SIZE def get_data(connection): buffer = b'' while len(buffer) < 4: data = connection.recv(4 - len(buffer)) if not data: raise ConnectionError('Connection was closed') buffer += data size_packed, buffer = buffer[:4], buffer[4:] if not size_packed: raise ConnectionError('Connection was closed') (size,) = struct.unpack('I', size_packed) data = connection.recv(size - len(buffer)) return buffer + data def handle_connection(connection, address): while True: try: data = get_data(connection) except ConnectionResetError: print(f'Connection with {address[0]} was unexpectedly closed') break except ConnectionError: print(f'Connection with {address[0]} was ended') break except KeyboardInterrupt: raise KeyboardInterrupt() else: if not data: print(f'Connection with {address[0]} was ended') break handle_request(data.decode(), connection) HOST, PORT = ADDR = '0.0.0.0', 6000 CHUNK_SIZE = 4096 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 KeyboardInterrupt: print('Stopping server...') sock.close() print('Server stopped') break