使用 python(创建专用服务器和客户端)发送 zip 文件,用于克隆流行平台,如使用 python 中的套接字的 s



enter code here我不知道为什么,但客户端服务器只是没有为自己在他们的消息中重置,后来我看到我的电脑破坏了连接,你知道怎么解决它。它向我显示了winerror,我什至在Windows后卫或防火墙等中寻找它。我希望这个问题有一个快速的解决方案。

客户端代码:

import socket
import tqdm
import os
import time
SERVER_HOST = socket.gethostname()
SERVER_PORT = 5000
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"
gamename = "gra" 
s = socket.socket()
s.connect((SERVER_HOST, SERVER_PORT))
print("Succesfully connected to the server")
s.send(gamename.encode("utf-8"))
print("data about downloaded game sended")
received = s.recv(BUFFER_SIZE).decode("utf-8")
print(received)
try:
filename, filesize = received.split(SEPARATOR)
except:
while True:
time.sleep(1)
filename = "effect.zip"
filename = os.path.basename(filename)
print(filename)
filesize = int(filesize)
progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", 
unit_scale=True, unit_divisor=1024)
with open(filename, "wb") as f:
while True:
bytes_read = s.recv(BUFFER_SIZE)
if not bytes_read:    
break
f.write(bytes_read)
progress.update(len(bytes_read))
f.close()

服务器代码在这里:

import socket
import tqdm
import os
import threading
import time
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096 
def send_file(host, port, buffer):
while True:
s = socket.socket()
print("Starting")
s.bind((host, port))
s.listen(5)
print("Started port "+str(port))
client_socket, address = s.accept()
time.sleep(0.5)
received = client_socket.recv(buffer).decode("utf-8")
filename = received + ".zip"
print("received info about installation")
filesize = os.path.getsize(filename)
print(f"{filename}{SEPARATOR}{filesize}")
client_socket.send(f"{filename}{SEPARATOR}{filesize}".encode("utf-8"))
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
while True:
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
break
client_socket.sendall(bytes_read)
progress.update(len(bytes_read))
s.close()
host = socket.gethostname()
send_file(host, 5000, BUFFER_SIZE)

我在这个代码中看到两个问题

第一:

您有错误的缩进,有些行在while True外部,但它们应该在内部。

client.py

with open(filename, "wb") as f:
while True:
bytes_read = s.recv(BUFFER_SIZE)
# the lines below should to be inside `while True`
if not bytes_read:    
break
f.write(bytes_read)
progress.update(len(bytes_read))  

server.py

with open(filename, "rb") as f:
while True:
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
break
# the lines below should to be inside `while True`
client_socket.sendall(bytes_read)
progress.update(len(bytes_read))

client.py中的错误缩进使其永远不会while循环结束。

第二:

Socket对象,可能不会在数据结束时通知客户端 - 并且代码if not bytes_read: break可能不起作用。或者可能是暂时的问题 具有连接并给出bytes_read = 0,可以在服务器发送所有数据之前关闭连接。

您应该使用filesize来检查是否获取所有数据。您可以倒计时 - 从filesize中减去接收字节的大小,直到您得到0

client.py

with open(filename, "wb") as f:
while filesize > 0:   # <--- use `filesize`
bytes_read = s.recv(BUFFER_SIZE)
# this may not work
if not bytes_read:   
break
filesize -= len(bytes_read)   # <--- use `filesize` 

f.write(bytes_read)
progress.update(len(bytes_read))
# --- after loop ---
if filesize == 0:
print('download completed')
else:                
print('download uncomplete, missing', filesize, 'bytes')

我看到其他可能的问题。

客户端将gamename发送到服务器,服务器将f"{filename}{SEPARATOR}{filesize}"发送到客户端。套接字可能会发送分成较小部分的数据并延迟发送,因此在这两种情况下,它都可能部分发送,然后服务器可能会gamename不完整并尝试使用错误的文件名。f"{filename}{SEPARATOR}{filesize}"也会发生同样的情况 - 客户端可能只得到其中的一部分,稍后它可以在获取文件数据并将其保存在文件中时得到休息 - 因此您创建了不正确的文件。

您应该发送一个字节,其中包含已发送数据的大小,另一端应首先读取此大小的一个字节,并使用它来从服务器读取正确的字节。

f"{filename}{SEPARATOR}{filesize}"示例

server.py- 发送信息

# - send header -
# convert info to header
header = f"{filename}{SEPARATOR}{filesize}"
header_bytes = header.encode("utf-8")
header_size = len(header_bytes)
print('header:', header)
# first send 1-byte with header size
size = struct.pack("B", header_size)
client_socket.sendall(size)
# next send header
client_socket.sendall(header_bytes)

client.py- 接收信息

# - recv header -

# first recv 1-byte with header size
size = s.recv(1)
header_size = struct.unpack("B", size)[0]
# next recv header
header_bytes = s.recv(header_size)
header = header_bytes.decode('utf-8')
print('header:', header)
# convert header to info
filename, filesize = header.split(SEPARATOR)
filesize = int(filesize)

包含其他更改的完整代码

server.py

import socket
import tqdm
import os
import time
import struct
# --- constants ---
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096
# --- functions ---
def send_file(host, port, buffer_size):
print(f"Starting {host}:{port}")
s = None   # default value at start

try:
s = socket.socket()   # standard options TCP/IP
# solution for "[Error 89] Address already in use". Use before bind()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
# kolejka klientów oczekujących na połączenie (max 5 klientów)
s.listen(5)
# --- loop ---
while True:
print("nWaiting for client")
client_socket, client_address = s.accept()
print("Client:", client_address)
try:
time.sleep(0.5)
# --- recv request ---

received = client_socket.recv(buffer_size).decode("utf-8")
filename = received + ".zip"
print("received info about installation")
filesize = os.path.getsize(filename)
# --- send response ---

# - send header -
# convert info to header
header = f"{filename}{SEPARATOR}{filesize}"
header_bytes = header.encode("utf-8")
header_size = len(header_bytes)

print('header:', header)
# first send 1-byte with header size
size = struct.pack("B", header_size)
client_socket.sendall(size)
# next send header
client_socket.sendall(header_bytes)
# - send data -
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
# send file
with open(filename, "rb") as f:
while True:
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
break
client_socket.sendall(bytes_read)
progress.update(len(bytes_read))
# simulate slow connection (and see progress bar)
time.sleep(0.5)
progress.close()  # stop displaying forgotten updates of progress bar

print('[DEBUG] end of file')

except BrokenPipeError as ex:
print('[Exception]', ex)

# --- after loop ---

except KeyboardInterrupt:
print('Stopped by Ctrl+C')
finally:    
print('Closing')    
if s is not None:
s.close()
# --- main ---
if __name__ == '__main__':
host = socket.gethostname()
send_file(host, 5000, BUFFER_SIZE)

client.py

import socket
import tqdm
import os
import time
import struct
# --- constants ---
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096
# --- other ---
SERVER_HOST = socket.gethostname()
SERVER_PORT = 5000
gamename = "gra" 
# ---------------------------------------
s = socket.socket()
# --- connect ---
s.connect((SERVER_HOST, SERVER_PORT))
print("Succesfully connected to the server", (SERVER_HOST, SERVER_PORT))
# --- send request ---
request = gamename
request_bytes = request.encode("utf-8")
s.sendall(request_bytes)
print("request about downloaded game sended")
# --- recv response ---

# - recv header -

# first recv 1-byte with header size
size = s.recv(1)
header_size = struct.unpack("B", size)[0]
# next recv header
header_bytes = s.recv(header_size)
header = header_bytes.decode('utf-8')
print('header:', header)
# convert header to info
filename, filesize = header.split(SEPARATOR)
filesize = int(filesize)
# - recv data -
progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", unit_scale=True, unit_divisor=1024)
# change name only for tests
filename = 'output.zip'
with open(filename, "wb") as f:
while filesize > 0:
bytes_read = s.recv(BUFFER_SIZE)
if not bytes_read:   
break
filesize -= len(bytes_read)

f.write(bytes_read)
progress.update(len(bytes_read))

# simulate slow connection (and see progress bar)
time.sleep(0.5)
progress.close()  # stop displaying forgotten updates of progress bar

if filesize == 0:
print('download completed')
else:                
print('download uncomplete, missing', filesize, 'bytes')
# --- close ---

f.close()

最新更新