用Python接收图像
以下代码适用于可以接收字符串的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
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