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()