在Java客户端和Twisted Python套接字服务器之间发送缓冲的映像

时间:2012-06-12 21:53:52

标签: java python sockets twisted

我有一个服务器端函数,可以使用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)

这适用于发送和接收字符串,但图像转换(通常)失败。 我试图理解为什么图像没有被正确读取。我最好的猜测是客户端没有读取正确的字节数,但老实说我不知道​​为什么会这样。情况下。

旁注:

  • 我意识到char [] - String-to-bytes-to-BufferedImage Java逻辑是环形的,但直接读取字节流会产生相同的错误。
  • 我有一个版本的工作,其中客户端套接字不是持久的,即。处理请求并删除连接。该版本工作正常,因为我不需要关心图像大小,但我想学习为什么建议的方法不起作用。

3 个答案:

答案 0 :(得分:2)

  1. BufferedReader.read()不能保证填充缓冲区,将图像转换为String并返回不仅是没有意义的,而是错误的。

  2. 字符串不是二进制数据的容器,并且无法保证往返行程。

  3. 最好重新设计协议,以便您可以摆脱readLine(),并以二进制形式发送长度,并可以使用DataInputStream读取整个流。

    通常在处理二进制协议时,答案始终为DataInputStreamDataOutputStream,除非字节顺序不是规范网络字节顺序,这是协议设计错误,其中您需要查看按字节排序的ByteBuffers

答案 1 :(得分:1)

在服务器代码中,您使用sys.getsizeof是错误的。返回bytestring对象的大小,而你想要的是bytestring中的字节数,即它的长度len(img_string)

此外,在客户端代码中,.readLine方法读取字符,直到它看到'\r'可能跟随'\n''\n',因此使用'\r'作为如果图像数据的第一个字节恰好是0x0A,即终止符将导致问题,即'\n'

答案 2 :(得分:0)

我希望问题是您尝试使用ReadergetBytes()来读取二进制数据(图像)。

Reader堆栈将从底层套接字流中获取字节,将它们转换为字符(使用平台的默认字符编码),并将它们作为String返回。然后再次使用默认编码将String内容转换回字节。对于二进制数据,字节到字符的初始转换可能是“有损”的。

此修复不是使用Reader / BufferedReader。使用InputStreamBufferedInputStream。您不是通过发送编码为文本的图像大小来使自己变得容易,但是您可以通过一次读取一个字节来处理它,直到您获得换行符,并将它们“手动”转换为整数。

(如果在“网络订单”中将大小作为固定大小的二进制整数发送,则可以使用DataInputStream代替...)