【问题标题】:Issues sending jpg-image over java socket using datainput/-outputstream使用 datainput/-outputstream 通过 java 套接字发送 jpg-image 的问题
【发布时间】:2014-12-09 23:40:06
【问题描述】:

我希望通过 TCP 套接字连接将 JPG 图像从客户端发送到服务器。我将文件转换为客户端中的字节数组,然后在发送数组长度后将其发送到服务器。服务器一次一个字节地从 socketinputstream 读取数据到一个新的字节数组,然后将其写入 jpg 文件。但是数据已损坏,无法查看此图像。下面是客户端和服务器的核心java代码。

客户:

Socket s = new Socket("localhost", 666);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
String imgPath = "C:/Users/huehuehue/Documents/Uni/D0036D/prick1.JPG";
File file = new File(imgPath);
byte[] b = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(b);
fis.close();
dos.writeInt((int) file.length());
dos.flush();
dos.write(b, 0, b.length);
dos.flush();

服务器:

ServerSocket serverSocket = new ServerSocket(666);
Socket connect = serverSocket.accept();
DataInputStream dis = new DataInputStream(connect.getInputStream());
File file = new File("C:/Users/huehuehue/Documents/Uni/D0036D/PLAYERprick.JPG");
FileOutputStream fos = new FileOutputStream(file);
int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
int i = 0;
for(i = 0; i < arrlen; i++) {
    b[i] = dis.readByte();
    i++;
}
fos.write(b, 0 , b.length);

我不明白为什么这不起作用,非常感谢任何帮助或建议。

【问题讨论】:

    标签: java sockets file-io iostream bufferedimage


    【解决方案1】:
    int arrlen = dis.readInt();
    byte[] b = new byte[arrlen];
    int i = 0;
    for(i = 0; i < arrlen; i++) {
        b[i] = dis.readByte();
        i++;
    }
    

    您将i 增加两次,因此您忽略了一半的输入,并将您不会忽略的内容写入错误的插槽。幸运的是,有一种更简单的方法,效率也更高:

    int arrlen = dis.readInt();
    byte[] b = new byte[arrlen];
    dis.readFully(b);
    

    NB fis.read(b); 无效。你不能假设它填满了缓冲区。你也应该在这里使用DataInputStream.readFully()。

    【讨论】:

    • 嘿,甚至没有注意到双倍增量,在凌晨 3 点编码时很容易错过愚蠢的事情。 readFully() 函数也很神奇,感谢您的帮助
    【解决方案2】:

    您需要匹配套接字的两端并且您的客户端没有完全填充您的byte[];相反,您的客户端可以在读取每个字节时发送它。而且,由于 Java 提供了BufferedInputStream,您不必直接手动使用和调整byte[] 缓冲区。相反,您可以这样做,

    Socket s = new Socket("localhost", 666);
    String imgPath = "C:/Users/huehuehue/Documents/Uni/D0036D/prick1.JPG";
    File file = new File(imgPath);
    try (InputStream is = new BufferedInputStream(new FileInputStream(file));
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());) {
        dos.writeLong(file.length()); // <-- remember to read a long on server.
        int val;
        while ((val = is.read()) != -1) {
            dos.write(val);
        }
        dos.flush();
    }
    

    此外,您的服务器可以使用类似的 BufferedOutputStream 来获得类似缓冲区的好处

    ServerSocket serverSocket = new ServerSocket(666);
    File file = new File("C:/Users/huehuehue/Documents/Uni/D0036D/PLAYERprick.JPG");
    try (Socket s = serverSocket.accept();
            DataInputStream dis = new DataInputStream(
                    s.getInputStream());
            OutputStream fos = new BufferedOutputStream(
                    new FileOutputStream(file));) {
        long arrlen = dis.readLong();
        for (long i = 0; i < arrlen; i++) {
            fos.write(dis.read());
        }
        fos.flush();
    }
    

    无需手动管理。注意上面使用BufferedInputStream 和BufferedOutputStream 来管理缓冲作为优化。您可以删除它们并直接从File 流中读取和写入。

    【讨论】:

    • 你实际上并没有告诉他他的代码有什么问题。如果发件人提前终止,您的代码将写入大量 0xff 字节。它需要检查。
    • @EJP 现在是 2014 年,当文件协议不支持大于 2 GB 的文件时,这让我很恼火。无论如何,我在原始帖子中包含了 BufferedOutputStream,但我已经对其进行了编辑以尝试澄清。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 2014-01-11
    相关资源
    最近更新 更多