-3

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

客户端代码:

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

1 回答 1

0

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

第一的:

你有错误的缩进,有些线在外面while True,但它们应该在里面。

客户端.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))  

服务器.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

客户端.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)

包含其他更改的完整代码

服务器.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)

客户端.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()
于 2021-05-07T13:22:21.533 回答