python - 为什么我在通过 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 文件进行了同样的尝试,但它在文件的 和 处丢失了一些内容。感谢您的帮助。
解决方案
关闭连接时忘记关闭文件。
这是一个最小的工作示例,根据您的代码略有更新:
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
这次服务器将文件保存为正确的大小。
种类。
推荐阅读
- c++ - 为什么我的代码没有打印最大的数字?
- sharepoint - 谷歌 Colab - Sharepoint
- python - 如何在 django ManyToMany 管理员中搜索
- php - Magento 管理页面需要永远加载
- java - NullPointerException 仅在平板电脑上
- laravel - Laravel 6 会话不会在 web.php 中持续存在
- mysql - 你如何在 MySQL 中按天返回最大值?
- amazon-web-services - 为私有子网创建路由表
- c++ - 在类内部使用具有非静态大小的数组
- javascript - 如何将 Highcharts 甘特图格式化为虚线而不是实线?