Reputation: 11
i have 2 problems that need help below. Transfer File socket python and MultiThreading
# server.py
import os
import socket
import threading
RESOURCES_SERVER = 'resources'
TEXT_FILE = 'text.txt'
BUFFER_SIZE = 4096
init_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
init_server.bind((socket.gethostname(), 9876))
init_server.listen(5)
file_lock = threading.Lock()
print(f"Server started at {init_server.getsockname()}")
def handle_client(server, addr):
try:
text_file = os.path.join(os.path.dirname(__file__), TEXT_FILE)
resources_dir = os.path.join(os.path.dirname(__file__), RESOURCES_SERVER)
with open(text_file, 'r') as f:
file_list = f.read()
server.send(file_list.encode())
while True:
request = server.recv(BUFFER_SIZE).decode().strip()
if not request:
break
if '|' not in request:
file_path = os.path.join(resources_dir, request)
if os.path.isfile(file_path):
file_size = os.path.getsize(file_path)
server.send(str(file_size).encode())
else:
server.send(f"File {request} not found.".encode())
continue
parts = request.split('|')
if len(parts) != 2:
server.send("Invalid request.".encode())
continue
file_name, range_str = parts
start, end = map(int, range_str.split('-'))
file_path = os.path.join(resources_dir, file_name)
if not os.path.isfile(file_path):
server.send(f"File {file_name} not found.".encode())
continue
with file_lock:
with open(file_path, 'rb') as f:
f.seek(start)
remaining = end - start
while remaining > 0:
chunk_size = min(BUFFER_SIZE, remaining)
chunk = f.read(chunk_size)
if not chunk:
break
server.sendall(chunk)
remaining -= len(chunk)
except ConnectionResetError:
print(f"Connection reset by peer {addr}")
except Exception as e:
print(f"Error handling client {addr}: {e}")
finally:
server.close()
def run_server():
write_text()
try:
while True:
server, addr = init_server.accept()
print(f"Connected by {addr}")
thread = threading.Thread(target=handle_client, args=(server, addr))
thread.daemon = True
thread.start()
except KeyboardInterrupt:
print("\nServer is shutting down...")
finally:
server.close()
if __name__ == "__main__":
run_server()
# client.py
import os
import socket
import threading
import sys
import time
REQUEST_DOWNLOAD_FILE = "input.txt"
DOWNLOAD_FOLDER = "data"
BUFFER_SIZE = 4096
PORT = 9876
lock = threading.Lock()
last_used_line_in_terminal = 0
...
def display_progress_download(base_line, part_num, percent):
with lock:
target_line = base_line + part_num
sys.stdout.write(f'\033[{target_line}H')
sys.stdout.write('\033[2K')
sys.stdout.write(f"Part {part_num} - Progress: {percent:.2f}% / 100%\r")
sys.stdout.flush()
time.sleep(0.01)
def download_part(HOST, PORT, file_name, part_num, start, end, base_line, part_size):
client = None
try:
client = create_connection_to_server(HOST, PORT)
if not client:
return False
client.recv(BUFFER_SIZE)
request = f"{file_name}|{start}-{end}".encode()
client.sendall(request)
part_path = f"./{DOWNLOAD_FOLDER}/{file_name}.part{part_num}"
with open(part_path, "wb") as f:
received = 0
while received < part_size:
chunk_size = min(BUFFER_SIZE, part_size - received)
data = client.recv(chunk_size)
if not data:
raise ConnectionError(f"Connection lost at {received} bytes")
f.write(data)
received += len(data)
percent = min(received / part_size * 100, 100)
display_progress_download(base_line, part_num, percent)
return True
except Exception as e:
print(f"Error downloading part {part_num}: {e}")
return False
finally:
if client:
client.close()
def merge_parts(file_name, parts):
output_path = f"./{DOWNLOAD_FOLDER}/{file_name}"
try:
with open(output_path, "wb") as output_file:
for part_path in parts:
with open(part_path, "rb") as part_file:
while chunk := part_file.read(BUFFER_SIZE):
output_file.write(chunk)
os.remove(part_path)
return True
except Exception as e:
return False
def download_file(HOST, PORT, file_name, file_size):
global last_used_line_in_terminal
os.makedirs(DOWNLOAD_FOLDER, exist_ok=True)
threads = []
parts = []
base_line = last_used_line_in_terminal + 1
last_used_line_in_terminal = base_line + 6
print(f"\033[{base_line}HDownloading {file_name}...\n")
for i in range(4):
start = i * (file_size // 4)
end = file_size if i == 3 else (i + 1) * (file_size // 4)
part_size = end - start
thread = threading.Thread(target=download_part, args=(HOST, PORT, file_name, i + 1, start, end, base_line, part_size))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
for i in range(4):
part_path = f"./{DOWNLOAD_FOLDER}/{file_name}.part{i + 1}"
if not os.path.exists(part_path):
return False
parts.append(part_path)
success = merge_parts(file_name, parts)
try:
merged_file_size = os.path.getsize(f"./{DOWNLOAD_FOLDER}/{file_name}")
if success and merged_file_size == file_size:
print(f"\033[{base_line + 5}HDownload {file_name} completed successfully!\n")
print(f"\033[{base_line + 6}H" + "-" * 40)
else:
print(f"\033[{base_line + 5}HDownload {file_name} errors! Expected:{file_size}, Got:{merged_file_size}\n")
except FileNotFoundError:
print(f"\033[{base_line + 5}HDownload of {file_name} failed! Merged file not found.")
return success
Here is my client and server code. It will download files from the server to the client. The client will create 4 parallel connections to the server, each connection will be responsible for downloading a portion of the original file size (with the original file size divided into 4) and I need to display their progress on the screen. .
Now the questions I want to ask.
example display process
Host Name: 127.0.0.1
Available files:
genshin.png|5980541
arya.gif|3707944
jinx.png|2445272
alime.jpeg|23765
avt.jpeg|51573
Downloading arya.gif...
Part 1 - Progress: 100.00% / 100%
Part 2 - Progress: 100.00% / 100%
Part 3 - Progress: 100.00% / 100%
Part 4 - Progress: 100.00% / 100%
Download completed successfully for arya.gif!
----------------------------------------
Downloading jinx.png...
Part 1 - Progress: 100.00% / 100%
Part 2 - Progress: 100.00% / 100%
Part 3 - Progress: 100.00% / 100%
Part 4 - Progress: 100.00% / 100%
Download completed successfully for jinx.png!
2024-12-15 00:33:37,379 - INFO - Received: 2260992 bytes in part 1 of vangoh.jpg
2024-12-15 00:33:37,387 - INFO - Received: 2342912 bytes in part 1 of vangoh.jpg
2024-12-15 00:33:37,395 - INFO - Received: 2424832 bytes in part 1 of vangoh.jpg
2024-12-15 00:33:37,396 - INFO - Received: 81816 bytes in part 2 of vangoh.jpg
2024-12-15 00:33:37,404 - INFO - Received: 2506752 bytes in part 1 of vangoh.jpg
2024-12-15 00:33:37,412 - INFO - Received: 163736 bytes in part 2 of vangoh.jpg
2024-12-15 00:33:37,420 - INFO - Received: 2588672 bytes in part 1 of vangoh.jpg
This is part of the process of transmitting bytes, and when part 1 has transmitted about 80%, part 2 will start transmitting, while I want all 4 parts to transmit in parallel at the same time (there may be a difference but it is small), this causes my progress to sometimes display part 1 at about 80/100% before part 2 begins to load. I want to see how to fix this error
Maybe the article is a bit long but I hope everyone can support me, remember to keep my functions intact. Thank you very much everyone.
i tried printing the progress but if ter minal is not enough length it will be overwritten at the end. I also tried downloading the file by dividing it into 4 parallel parts, but the 4 threads do not run at the same time, but sometimes part2 appears before part1, I want all 4 to run at the same time.
Upvotes: 1
Views: 39