Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Python接收图像_Python_Sockets_Tcp - Fatal编程技术网

用Python接收图像

用Python接收图像,python,sockets,tcp,Python,Sockets,Tcp,以下代码适用于可以接收字符串的python服务器 import socket TCP_IP = '127.0.0.1' TCP_PORT = 8001 BUFFER_SIZE = 1024 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((TCP_IP, TCP_PORT)) s.listen(1) conn, addr = s.accept() print 'Connection address:', addr w

以下代码适用于可以接收字符串的python服务器

import socket

TCP_IP = '127.0.0.1'
TCP_PORT = 8001
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)

conn, addr = s.accept()
print 'Connection address:', addr
while 1:
    length = conn.recv(1027)
    data = conn.recv(int(length))
    import StringIO
    buff = StringIO.StringIO()
    buff.write(data)
    if not data: break
    print "received data:", data
    conn.send('Thanks')  # echo
    get_result(buff)    
conn.close()
有人能帮我编辑这段代码或创建一段类似的代码,以便能够接收图像而不是字符串吗?

首先,您的代码实际上无法接收字符串

这一行:

length = conn.recv(1027)
…将接收1到1027字节之间的任何位置

您需要循环每个
recv
并累积一个缓冲区,如下所示:

def recvall(conn, length):
    buf = b''
    while len(buf) < length:
        data = conn.recv(length - len(buf))
        if not data:
            return data
        buf += data
    return buf
while True:
    length = recvall(conn, 1027)
    if not length: break
    data = recvall(conn, int(length))
    if not data: break
    print "received data:", data
    conn.send('Thanks')  # echo

出于性能方面的考虑,您可以使用
StringIO
或其他技术来代替串联,但我忽略了这一点,因为这样更简单、更简洁,而且理解代码比性能更重要

同时,值得指出的是,1027字节对于长度前缀来说是一个荒谬的巨大空间。此外,您的发送代码必须确保实际发送1027字节,无论发生什么情况。您的响应必须始终精确到6字节长,才能正常工作

def send_string(conn, msg):
    conn.sendall(str(len(msg)).ljust(1027))
    conn.sendall(msg)
    response = recvall(conn, 6)
    return response
但至少现在它是可行的


那么,你为什么认为它有效呢

TCP是字节流,而不是消息流。无法保证从一侧发送的单个
将与另一侧的下一个
recv
匹配。但是,当您在同一台计算机上同时运行两台计算机时,发送相对较小的缓冲区,并且不会将计算机加载得太厉害,它们通常会以1:1的比例匹配。毕竟,每次你调用
recv
,对方可能只有时间
发送一条消息,这条消息本身就在操作系统的缓冲区中,所以操作系统只会给你全部信息。因此,您的代码将在初始测试中正常工作

但是,如果您通过路由器将消息发送到另一台计算机,或者如果您等待对方进行多个
发送
呼叫的时间足够长,或者如果您的消息太大,无法放入单个缓冲区,或者如果您运气不好,那么缓冲区中可能会有2-1/2条消息等待,操作系统将为您提供全部2-1/2条消息。然后,您的下一个
recv
将获得剩余的1/2消息


那么,你是如何使这项工作适用于图像的呢?这取决于你的意思

您可以将图像文件以字节序列的形式读入内存,然后在该序列上调用
send\u string
,它将正常工作。然后,另一方可以保存该文件,或将其解释为图像文件并显示它,或显示它想要的任何内容

或者,您可以使用类似于
PIL
的方法来解析图像文件并将其解压缩为位图。然后,以某种方式(例如,
pickle
it)、
send_string
标题对标题数据(宽度、高度、像素格式等)进行编码,然后
send_string
位图

如果标头具有固定大小(例如,它是一个简单的结构,您可以使用
struct.pack
进行序列化),并且包含足够的信息让另一方计算位图的长度(以字节为单位),则无需
发送每个字符串
;只需使用
conn.sendall(序列化的\u头)
然后
conn.sendall(位图)

首先,您的代码实际上无法接收字符串

这一行:

length = conn.recv(1027)
…将接收1到1027字节之间的任何位置

您需要循环每个
recv
并累积一个缓冲区,如下所示:

def recvall(conn, length):
    buf = b''
    while len(buf) < length:
        data = conn.recv(length - len(buf))
        if not data:
            return data
        buf += data
    return buf
while True:
    length = recvall(conn, 1027)
    if not length: break
    data = recvall(conn, int(length))
    if not data: break
    print "received data:", data
    conn.send('Thanks')  # echo

出于性能方面的考虑,您可以使用
StringIO
或其他技术来代替串联,但我忽略了这一点,因为这样更简单、更简洁,而且理解代码比性能更重要

同时,值得指出的是,1027字节对于长度前缀来说是一个荒谬的巨大空间。此外,您的发送代码必须确保实际发送1027字节,无论发生什么情况。您的响应必须始终精确到6字节长,才能正常工作

def send_string(conn, msg):
    conn.sendall(str(len(msg)).ljust(1027))
    conn.sendall(msg)
    response = recvall(conn, 6)
    return response
但至少现在它是可行的


那么,你为什么认为它有效呢

TCP是字节流,而不是消息流。无法保证从一侧发送的单个
将与另一侧的下一个
recv
匹配。但是,当您在同一台计算机上同时运行两台计算机时,发送相对较小的缓冲区,并且不会将计算机加载得太厉害,它们通常会以1:1的比例匹配。毕竟,每次你调用
recv
,对方可能只有时间
发送一条消息,这条消息本身就在操作系统的缓冲区中,所以操作系统只会给你全部信息。因此,您的代码将在初始测试中正常工作

但是,如果您通过路由器将消息发送到另一台计算机,或者如果您等待对方进行多个
发送
呼叫的时间足够长,或者如果您的消息太大,无法放入单个缓冲区,或者如果您运气不好,那么缓冲区中可能会有2-1/2条消息等待,操作系统将为您提供全部2-1/2条消息。然后,您的下一个
recv
将获得剩余的1/2消息


那么,你是如何使这项工作适用于图像的呢?这取决于你的意思

您可以将图像文件以字节序列的形式读入内存,然后在该序列上调用
send\u string
,它将正常工作。然后,另一方可以保存该文件,或将其解释为图像文件并显示它,或显示它想要的任何内容

或者,您可以使用类似于
PIL
的方法来解析图像文件并将其解压缩为位图。然后,以某种方式(例如,
pickle
it)、
send_string
标题对标题数据(宽度、高度、像素格式等)进行编码,然后
send_string
位图

如果标头具有固定大小(例如,它是一个简单的结构,您可以使用
struct.pack
进行序列化),并且包含足够的信息让另一方以字节为单位计算位图的长度,则无需
发送\u string