使用 TCP 套接字传输图像时缺少一像素行 [英] Missing one-pixel row while transfering image with TCP socket

查看:32
本文介绍了使用 TCP 套接字传输图像时缺少一像素行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在面临奇怪的错误,我有 python 脚本,它使用 TCP 套接字发送/接收数据,一切正常,但是当我尝试使用此脚本下载图像时,它会下载它,但是缺少一个像素行.关于如何修复它的任何想法?

I'm facing strange error right now, I have python script, that is sending/receiving data using TCP socket, everything works fine, but when I'm trying to download image with this script, it will download it, but there is a missing one-pixel row. Any ideas on how to fix it?

服务器下载脚本:

    def download(self, cmd):
        try:
            self.c.send(str.encode(cmd))
            command,filename=cmd.split(' ')
            nFile = open(filename, 'wb')
            i = self.c.recv(1024)
            while not ('complete' in str(i)):   
                nFile.write(i)
                i = self.c.recv(1024)
            nFile.close()
            self.reset = True
            print('\nGot that file')
        except Exception as e:
            print(e)

客户端上传脚本:

   def upload(self, filename):
    try:
        fd = open(filename, 'rb')
        data = fd.read(1024)
        while (data):
            self.s.sendall(data)
            data = fd.read(1024)
        self.s.send(str.encode('complete'))
        fd.close()
    except Exception as e:
        print(e)

示例 - 您可以看到,最后一行像素丢失了:

解决方案(1): 这不是解决方案,只是解决方法,使用另一个!

如果您之前删除有效负载的完整部分会发生什么将最后一块数据写入 nFile?– mtrw

What happens if you remove the complete part of the payload before writing the last chunk of data to nFile? – mtrw

问题在于向服务器发送完整"字符串,因为脚本没有足够的时间从图像中获取所有字节.因此,解决此问题的一种方法是将 sleep(0.2) 添加到脚本中.

The problem was with sending 'complete' string to the server, because the script had not enough time to get all bytes from the image. So one way to fix this is to add sleep(0.2) to the script.

客户端上传脚本:

   def upload(self, filename):
try:
    fd = open(filename, 'rb')
    data = fd.read(1024)
    while (data):
        self.s.sendall(data)
        data = fd.read(1024)
    sleep(0.2)
    self.s.send(str.encode('complete'))
    fd.close()
except Exception as e:
    print(e)

解决方案(2):

TCP 是一种没有消息边界的流协议.这意味着一个 recv 调用可以接收多个发送,或者一个发送可以在多次接收调用中收到.

TCP is a stream protocol with no message boundaries. This means that multiple sends can be received in one recv call, or one send can be received in multiple recv calls.

延迟解决方法可能无法可靠地工作.你需要定界流中的消息.

The delay work-around may not work reliably. You need to delimit messages in the stream.

——马克西姆·叶戈鲁什金

– Maxim Egorushkin

服务器下载脚本:

try:
    msg_header = self.c.recv(4)
    while len(msg_header) != 4:
        msg_header += self.c.recv(4 - len(msg_header))
    file_len = struct.unpack('<I', msg_header)[0]
    nFile = open(filename, 'wb')
    data = self.c.recv(file_len)
    while len(data) != file_len:
        data += self.c.recv(file_len - len(data))
    nFile.write(data)
    nFile.close()
    print('\nGot that file')
except Exception as e:
    print(e)

客户端上传脚本:

try:
    file_len = os.stat(filename).st_size
    msg_header = struct.pack('<I', file_len)
    self.s.sendall(msg_header)
    fd = open(filename, 'rb')
    data = fd.read(file_len)
    while (data):
        self.s.sendall(data)
        data = fd.read(file_len)
    fd.close()
except Exception as e:
    print(e)

推荐答案

问题在于向服务器发送完整"字符串,因为脚本没有足够的时间从图像中获取所有字节.因此,解决此问题的一种方法是将 sleep(0.2) 添加到脚本中.

The problem was with sending 'complete' string to the server, because the script had not enough time to get all bytes from the image. So one way to fix this is to add sleep(0.2) to the script.

TCP 是一种没有消息边界的流协议.这意味着在一个recv调用中可以接收多个send,或者在多个recv中可以接收一个send> 电话.

TCP is a stream protocol with no message boundaries. This means that multiple sends can be received in one recv call, or one send can be received in multiple recv calls.

延迟解决方法可能无法可靠地工作.您需要在流中分隔消息.

The delay work-around may not work reliably. You need to delimit messages in the stream.

在流中分隔消息有两种常用方法:

There are 2 common ways of delimiting messages in a stream:

  1. 使用标题作为消息的前缀.
  2. 用后缀结束消息.

<小时>

由于您发送的是二进制数据,因此任何后缀都可以自然地出现在有效载荷中.除非后缀比有效载荷长,这是不切实际的.


Since you are sending binary data any suffix can naturally be present in the payload. Unless the suffix is longer than the payload, which isn't practical.

因此,您可能想在这里做的是在您的有效负载前添加一个固定大小的标头.在这种特殊情况下,具有 4 字节二进制文件长度的标头就足够了.例如:

Hence, what you may like to do here is prefix a fixed-size header to your payload. In this particular case, a header with a 4-byte binary file length would suffice. E.g.:

file_len = os.stat(filename).st_size
msg_header = struct.pack('<I', file_len)
self.s.sendall(msg_header)

接收方需要先读取头部:

The receiver needs to read the header first:

msg_header = self.s.recv(4)
while len(msg_header) != 4:
    msg_header += self.s.recv(4 - len(msg_header))
file_len = struct.unpack('<I', msg_header)

然后从套接字中准确读取file_len.

And then read exactly file_len from the socket.

了解正在接收的文件的大小还允许您预先分配缓冲区以避免内存重新分配和/或预先分配整个文件以最大程度地减少磁盘碎片或避免在文件传输开始后出现磁盘空间不足错误.

Knowing the size of the file being received also allows you to preallocate the buffer to avoid memory reallocations and/or preallocate the entire file to minimize disk fragmentation or avoid out of disk space error after the file transfer has started.

这篇关于使用 TCP 套接字传输图像时缺少一像素行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆