我有一个服务器端函数,可以使用Python Imaging Library绘制图像。 Java客户端请求一个图像,该图像通过套接字返回并转换为BufferedImage。
我在数据前加上要发送的图像的大小,然后是CR。然后,我从套接字输入流中读取此字节数,并尝试使用ImageIO转换为BufferedImage。
在客户的缩写代码中:
public String writeAndReadSocket(String request) {
// Write text to the socket
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write(request);
bufferedWriter.flush();
// Read text from the socket
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Read the prefixed size
int size = Integer.parseInt(bufferedReader.readLine());
// Get that many bytes from the stream
char[] buf = new char[size];
bufferedReader.read(buf, 0, size);
return new String(buf);
}
public BufferedImage stringToBufferedImage(String imageBytes) {
return ImageIO.read(new ByteArrayInputStream(s.getBytes()));
}
和服务器:
# Twisted server code here
# The analog of the following method is called with the proper client
# request and the result is written to the socket.
def worker_thread():
img = draw_function()
buf = StringIO.StringIO()
img.save(buf, format="PNG")
img_string = buf.getvalue()
return "%i\r%s" % (sys.getsizeof(img_string), img_string)
这适用于发送和接收字符串,但图像转换(通常)失败。 我试图理解为什么图像没有被正确读取。我最好的猜测是客户端没有读取正确的字节数,但老实说我不知道为什么会这样。情况下。
旁注:
答案 0 :(得分:2)
BufferedReader.read()
不能保证填充缓冲区,将图像转换为String并返回不仅是没有意义的,而是错误的。
字符串不是二进制数据的容器,并且无法保证往返行程。
最好重新设计协议,以便您可以摆脱readLine()
,并以二进制形式发送长度,并可以使用DataInputStream
读取整个流。
通常在处理二进制协议时,答案始终为DataInputStream
和DataOutputStream
,除非字节顺序不是规范网络字节顺序,这是协议设计错误,其中您需要查看按字节排序的ByteBuffers
。
答案 1 :(得分:1)
在服务器代码中,您使用sys.getsizeof
是错误的。返回bytestring对象的大小,而你想要的是bytestring中的字节数,即它的长度len(img_string)
。
此外,在客户端代码中,.readLine
方法读取字符,直到它看到'\r'
可能跟随'\n'
或'\n'
,因此使用'\r'
作为如果图像数据的第一个字节恰好是0x0A,即终止符将导致问题,即'\n'
。
答案 2 :(得分:0)
我希望问题是您尝试使用Reader
和getBytes()
来读取二进制数据(图像)。
Reader
堆栈将从底层套接字流中获取字节,将它们转换为字符(使用平台的默认字符编码),并将它们作为String返回。然后再次使用默认编码将String内容转换回字节。对于二进制数据,字节到字符的初始转换可能是“有损”的。
此修复不是使用Reader
/ BufferedReader
。使用InputStream
和BufferedInputStream
。您不是通过发送编码为文本的图像大小来使自己变得容易,但是您可以通过一次读取一个字节来处理它,直到您获得换行符,并将它们“手动”转换为整数。
(如果在“网络订单”中将大小作为固定大小的二进制整数发送,则可以使用DataInputStream
代替...)