Java 通过socketChannel发送jpeg图像

Java 通过socketChannel发送jpeg图像,java,image,nio,socketchannel,Java,Image,Nio,Socketchannel,我目前正在测试一个小游戏所需的编程技能,我计划最终编写一个小游戏,而我目前正在通过套接字通道传输图像。我计划在我写的一个“战舰”程序上测试这一点,通过向你的对手发送某种“化身”或“个人资料图片”。 我有一个普通插座的工作示例: 服务器端: try { ServerSocket serverSocket = new ServerSocket(port); //provided at an earlier point in the code Socket se

我目前正在测试一个小游戏所需的编程技能,我计划最终编写一个小游戏,而我目前正在通过套接字通道传输图像。我计划在我写的一个“战舰”程序上测试这一点,通过向你的对手发送某种“化身”或“个人资料图片”。 我有一个普通插座的工作示例:

服务器端:

    try {
        ServerSocket serverSocket = new ServerSocket(port); //provided at an earlier point in the code
        Socket server = serverSocket.accept();
        BufferedImage img = ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));
        //here would be code to display the image in a frame, but I left that out for readability
        server.close();
        serverSocket.close();
    } catch(Exception e) {   //shortened version to improve readability
               e.printStackTrace();
    }
    ByteBuffer imgbuf = ByteBuffer.allocate(40395);
    int imageBytes = socketChannel.read(imgbuf);
    while (true) {
        if (imageBytes == (0 | -1)) {
            imageBytes = socketChannel.read(imgbuf);
        } else {
            break;
        }
    }
    byte[] byteArray = imgbuf.array();
    System.out.println(byteArray.length);
    InputStream in = new ByteArrayInputStream(byteArray);
    BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
        imageBytes = socketChannel.read(imgbuf);
    } else {
        break;
    }
}
byte[] byteArray = imgbuf.array();
System.out.println(byteArray.length);
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
客户端:

    Socket client = new Socket(ip, port);
    bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    //the image is located at /resources/images/ship_1.jpeg
    ImageIO.write(bimg,"JPG",client.getOutputStream());
    client.close();
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
    //i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
    ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    byte[] byteArray;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(bimg, "jpg", baos);
    baos.flush();
    byteArray = baos.toByteArray();
    baos.close();
    socketChannel.socket().getOutputStream().write(byteArray);
BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
//i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
到目前为止,一切正常。
现在,socketChannels(Java NIO)的问题是:

客户端:

    Socket client = new Socket(ip, port);
    bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    //the image is located at /resources/images/ship_1.jpeg
    ImageIO.write(bimg,"JPG",client.getOutputStream());
    client.close();
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
    //i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
    ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    byte[] byteArray;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(bimg, "jpg", baos);
    baos.flush();
    byteArray = baos.toByteArray();
    baos.close();
    socketChannel.socket().getOutputStream().write(byteArray);
BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
//i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
服务器端:

    try {
        ServerSocket serverSocket = new ServerSocket(port); //provided at an earlier point in the code
        Socket server = serverSocket.accept();
        BufferedImage img = ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));
        //here would be code to display the image in a frame, but I left that out for readability
        server.close();
        serverSocket.close();
    } catch(Exception e) {   //shortened version to improve readability
               e.printStackTrace();
    }
    ByteBuffer imgbuf = ByteBuffer.allocate(40395);
    int imageBytes = socketChannel.read(imgbuf);
    while (true) {
        if (imageBytes == (0 | -1)) {
            imageBytes = socketChannel.read(imgbuf);
        } else {
            break;
        }
    }
    byte[] byteArray = imgbuf.array();
    System.out.println(byteArray.length);
    InputStream in = new ByteArrayInputStream(byteArray);
    BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
        imageBytes = socketChannel.read(imgbuf);
    } else {
        break;
    }
}
byte[] byteArray = imgbuf.array();
System.out.println(byteArray.length);
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
到目前为止,我还没有真正使用过图像,所以可能只是在使用缓冲区时出现了一些错误,或者是我找不到的任何东西。
无论如何,如果我执行该程序(使用许多不同的代码,工作正常),我会在为服务器端提供的最后一行收到一个异常:
javax.imageio.IIOException:无效的JPEG文件结构:缺少SOS标记


任何帮助都将不胜感激

我最终自己找到了解决方案,首先将图像转换成字节数组,然后再通过套接字发送。
代码:

客户端:

    Socket client = new Socket(ip, port);
    bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    //the image is located at /resources/images/ship_1.jpeg
    ImageIO.write(bimg,"JPG",client.getOutputStream());
    client.close();
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
    //i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
    ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    byte[] byteArray;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(bimg, "jpg", baos);
    baos.flush();
    byteArray = baos.toByteArray();
    baos.close();
    socketChannel.socket().getOutputStream().write(byteArray);
BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
//i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
服务器端:

    try {
        ServerSocket serverSocket = new ServerSocket(port); //provided at an earlier point in the code
        Socket server = serverSocket.accept();
        BufferedImage img = ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));
        //here would be code to display the image in a frame, but I left that out for readability
        server.close();
        serverSocket.close();
    } catch(Exception e) {   //shortened version to improve readability
               e.printStackTrace();
    }
    ByteBuffer imgbuf = ByteBuffer.allocate(40395);
    int imageBytes = socketChannel.read(imgbuf);
    while (true) {
        if (imageBytes == (0 | -1)) {
            imageBytes = socketChannel.read(imgbuf);
        } else {
            break;
        }
    }
    byte[] byteArray = imgbuf.array();
    System.out.println(byteArray.length);
    InputStream in = new ByteArrayInputStream(byteArray);
    BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
        imageBytes = socketChannel.read(imgbuf);
    } else {
        break;
    }
}
byte[] byteArray = imgbuf.array();
System.out.println(byteArray.length);
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {

如果您感兴趣,我从中获得了将图像转换为字节数组的代码,反之亦然。

我看到的最大问题是假设
imgbuf.array()
累积了所有数据。该方法只返回支持缓冲区的数组。将缓冲区视为一个数据块,因为它是()

要在“服务器”端创建完整的映像,您需要一个完整的数据数组。所以你必须做一些不同的事情。这根本不是经过优化的代码,但它应该可以帮助您开始:

ArrayList<byte> fullImageData = new ArrayList<byte>();
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);

while ((imageBytes = socketChannel.read(imgbuf)) > 0)
{
    imgbuf.flip(); // prepare for reading

    while(imgbuf.hasRemaining())
    {
        fullImageData.add(imgbuf.get());
    }

    imgbuf.clear(); // prepare for next block
}

byte[] byteArray = fullImageData.toArray();
System.out.println(byteArray.length);
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage img = ImageIO.read(in);

你不需要这些

客户端:

    Socket client = new Socket(ip, port);
    bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    //the image is located at /resources/images/ship_1.jpeg
    ImageIO.write(bimg,"JPG",client.getOutputStream());
    client.close();
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
    //i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
    ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
    BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
    byte[] byteArray;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(bimg, "jpg", baos);
    baos.flush();
    byteArray = baos.toByteArray();
    baos.close();
    socketChannel.socket().getOutputStream().write(byteArray);
BufferedImage bimg = ImageIO.read(getClass().getResource("/images/ship_1.jpeg"));
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
//i do NOT know if the following line works - System.out.println() statements after it are not executed, so ... probably doesn't work either.
ImageIO.write(bimg, "jpeg", socketChannel.socket().getOutputStream());
您根本不需要
ImageIO
来完成此操作。它只是一个简单的字节拷贝:

InputStream in = getClass().getResource("/images/ship_1.jpeg");
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
    socketChannel.socket().getOutputStream().write(buffer, 0, count);
}
服务器端:

    try {
        ServerSocket serverSocket = new ServerSocket(port); //provided at an earlier point in the code
        Socket server = serverSocket.accept();
        BufferedImage img = ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));
        //here would be code to display the image in a frame, but I left that out for readability
        server.close();
        serverSocket.close();
    } catch(Exception e) {   //shortened version to improve readability
               e.printStackTrace();
    }
    ByteBuffer imgbuf = ByteBuffer.allocate(40395);
    int imageBytes = socketChannel.read(imgbuf);
    while (true) {
        if (imageBytes == (0 | -1)) {
            imageBytes = socketChannel.read(imgbuf);
        } else {
            break;
        }
    }
    byte[] byteArray = imgbuf.array();
    System.out.println(byteArray.length);
    InputStream in = new ByteArrayInputStream(byteArray);
    BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
        imageBytes = socketChannel.read(imgbuf);
    } else {
        break;
    }
}
byte[] byteArray = imgbuf.array();
System.out.println(byteArray.length);
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage img = ImageIO.read(in);
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
int imageBytes = socketChannel.read(imgbuf);
while (true) {
    if (imageBytes == (0 | -1)) {
这毫无意义。它将
imageBytes
0 |-1
进行比较,后者为“0xffffff”,仅在流结束时为真

        imageBytes = socketChannel.read(imgbuf);
在这种情况下,再次阅读是徒劳的。它将只返回另一个-1

    } else {
        break;
因此,如果你没有得到-1,也就是说,一旦你真的读取了一些数据,你就已经崩溃了

    }
}
byte[] byteArray = imgbuf.array();
System.out.println(byteArray.length);
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage img = ImageIO.read(in);
你也不需要这些

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteBuffer imgbuf = ByteBuffer.allocate(40395);
while ((imageBytes = socketChannel.read(imgbuf)) > 0)
{
    imgbuf.flip();
    while(imgbuf.hasRemaining())
    {
        baos.write(imgbuf.get());
    }
    imgbuf.compact();
}
BufferedImage img = ImageIO.read(new ByteArrayInputStream(baos.toByteArray()));

您是否尝试过使用类来发送图像?通常,通过套接字发送任意大小的二进制数据的最佳方法是首先发送长度,然后发送数据。这使接收者能够准确地知道需要多少数据,并能正确地进行操作。@jtahlborn是的,我以后会改变这一点。然而,考虑到我知道测试图像的大小,我只是在这里硬编码了大小。@JonahHaney那么我该如何编写代码呢?我仍然在使用套接字通道:/NOTE:我找到了一个解决方案,不需要写额外的答案-我将自己回答,以供将来的读者阅读。基本上,我将图像转换为字节数组,然后将其发送到服务器。我感谢您的回答,尽管我自己设法解决了这个问题。不过,您的描述和解释更为详细-我想我刚刚找到了一种在google上将图像转换为字节数组的较短方法^^^这甚至不编译,而且在列表中累积字节的想法很可笑。添加到ArrayList与写入ByteArrayOutputStream有何实质性区别?这基本上是相同的解决方案。至于不编译,我可以在使用IDE的机器上修复代码。您不需要客户端中的
ByteArrayOutputStream
。您可以使用
ImageIO
直接写入套接字输出流,甚至不需要这样做。由于我在回答中概述的原因,您的服务器端代码仍然无法工作。