首页 > 解决方案 > 为什么我在通过 python 中的套接字传输文件时丢失字节?

问题描述

我正在尝试通过套接字将文件(在本例中为 jpg 文件)从客户端发送到服务器,但我在此过程中丢失了一些字节。

我能够发送图像,它看起来与原始图像相同并且具有相同的分辨率,但它的字节数更小。原文:145018 字节。已接收:139264。首先我发送一个包含文件名和文件大小的标头,当服务器收到标头时,它会向客户端发送一条消息:“标头已收到”,然后客户端将文件发送到服务器并服务器将文件保存到f'received/{fileName}'

服务器

import socket
import argparse
import os
import sys

parser = argparse.ArgumentParser()
parser.add_argument("address", help='IP address of the host')
parser.add_argument("port", type=int, help='Portnumber of the host')

HEADERSIZE = 10

def main():

    args = parser.parse_args()
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((args.address, args.port))
    sock.listen(5)
    (client, addr) = sock.accept()
    fileSizeAndName = client.recv(128)
    if(fileSizeAndName):
        print("Received a connection from ", addr)
        fileSize = int(fileSizeAndName[:HEADERSIZE])
        fileName = str(fileSizeAndName[HEADERSIZE:], "utf-8")
        print(f'Incoming file: {fileName}, size: {fileSize} bytes')
        client.sendall(bytes("Header received", "utf-8"))
        bSize = 0
        print("Received a connection from ", addr)
        f = open(f'received\{fileName}','wb')
        #received_bytes = bytearray(client.recv(2048))
        while True:
            f.write(client.recv(2048))
            bSize += 2048
            if bSize > fileSize:
                sock.close()
                client.close()
                sys.exit(str(os.path.getsize(f'received\{fileName}')) + ' bytes')

if __name__ == "__main__":
    main()

客户

import socket
import argparse

HEADERSIZE = 10

parser = argparse.ArgumentParser()
parser.add_argument('filename')
parser.add_argument("address", help='IP address of the host')
parser.add_argument("port", type=int, help='Portnumber of the host')
args = parser.parse_args()

filename = args.filename.split('/')[len(args.filename.split('/')) - 1]

with open(args.filename, 'rb') as f:
    contents = f.read()

msg = f'{len(contents):<{HEADERSIZE}}' + filename

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((args.address, args.port))
s.sendall(bytes(msg, 'utf-8'))
data = s.recv(128)
print(str(data, 'utf-8'))
if(data):
    s.sendall(contents)
    s.close()

print(bytes(msg,'utf-8'))
print(f'File size: {len(contents)}')

我不知道错误在哪里。我对 txt 文件进行了同样的尝试,但它在文件的 和 处丢失了一些内容。感谢您的帮助。

标签: pythonsockets

解决方案


关闭连接时忘记关闭文件。

这是一个最小的工作示例,根据您的代码略有更新:

import socket
import argparse
import os
import sys
import threading

HEADERSIZE = 10

def serve():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(("127.0.0.1", 20000))
    sock.listen(5)
    (client, addr) = sock.accept()
    fileSizeAndName = client.recv(128)
    if(fileSizeAndName):
        print("Received a connection from ", addr)
        fileSize = int(fileSizeAndName[:HEADERSIZE])
        fileName = str(fileSizeAndName[HEADERSIZE:], "utf-8")
        print(f'Incoming file: {fileName}, size: {fileSize} bytes')
        client.sendall(bytes("Header received", "utf-8"))
        bSize = 0
        print("Received a connection from ", addr)
        f = open(f'received/{fileName}','wb')
        #received_bytes = bytearray(client.recv(2048))
        while True:
            f.write(client.recv(2048))
            bSize += 2048
            if bSize > fileSize:
                f.close()
                sock.close()
                client.close()
                print("Received file:", str(os.path.getsize(f'received/{fileName}')) + ' bytes')
                sys.exit(0)

def client():
    filename = "foo"
    contents = b'\0' * 64000

    msg = f'{len(contents):<{HEADERSIZE}}' + filename

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 20000))
    s.sendall(bytes(msg, 'utf-8'))
    data = s.recv(128)
    print(str(data, 'utf-8'))
    if(data):
        s.sendall(contents)
        s.close()

    print(msg)
    print(f'File size: {len(contents)}')


if __name__ == "__main__":
    threading.Thread(target=serve).start()
    client()

在这里,我发送了 64000 NUL 字节。如果删除该f.close()行,您将获得以下输出:

Received a connection from  ('127.0.0.1', 43812)
Incoming file: foo, size: 64000 bytes
Received a connection from  ('127.0.0.1', 43812)
Header received
64000     foo
File size: 64000
Received file: 61440 bytes

现在,随着f.close().

Received a connection from  ('127.0.0.1', 43838)
Incoming file: foo, size: 64000 bytes
Header received
Received a connection from  ('127.0.0.1', 43838)
64000     foo
File size: 64000
Received file: 64000 bytes

这次服务器将文件保存为正确的大小。

种类。


推荐阅读