为什么我不能通过Java中的socket发送图像?

时间:2015-05-12 18:15:48

标签: java image sockets

当我尝试使用Java通过套接字从客户端向服务器端发送图片时,我发现了一个非常奇怪的事情。这是我在Class ImgSender客户端的代码,它扩展了Thread类:

public class ImgSender extends Thread
{
    Socket img_s;
    BoolFlag imageready,dataready;
    ImgBoundingBox image;
    ByteArrayOutputStream byteArrayOutputStream;;

public ImgSender(Socket s,BoolFlag dataready,BoolFlag imageready,ImgBoundingBox image)
{
    this.img_s=s;
    this.imageready=imageready;
    this.image=image;
    this.dataready=dataready;
}
public void run()
{
    boolean running=true;
    while(running)
    {
        // System.out.println("Img sender running");
        if(imageready.getFlag())
        { System.out.println("trying to send img");
            try
            {
                  OutputStream outputStream = img_s.getOutputStream();
                  ImageIO.write(image.getImg(), "jpg", outputStream);

                  System.out.println("Send image"+System.currentTimeMillis());
                  outputStream.flush();
                  outputStream.close();
                  imageready.setFlag(false);

            }
            catch(Exception e)
            {
                System.out.println("image client send failed");
                imageready.setFlag(false);
            }
        }
    }    
}

奇怪的是,当我评论出第一个陈述时:

System.out.println("Img sender running");

图像不会被发送到服务器,并且不会打印出“尝试发送img”。如果我没有对它进行评论,或者,我在if语句之前做了一些其他的东西,比如sleep(),可以将图片发送到服务器并打印“尝试发送img”。此外,如果我通过设置一个断点来调试程序:

if(imageready.getFlag())

然后逐步执行它,它将传递if语句并成功发送它。

就服务器端而言,这里是Class ImgManager的代码:

private class ImgManager extends Thread
{
    Socket img_s; 
    boolean working=true;

   public ImgManager(Socket s)
   {        
       this.img_s=s;
   }


   public void run()
   {
       while(working)
       {
           try
           {
                   InputStream inputStream = img_s.getInputStream();
                   System.out.println("Reading: " + System.currentTimeMillis());

                   BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(inputStream));

                   System.out.println("Received " + image.getHeight() + "x" + image.getWidth() + ": " + System.currentTimeMillis());
                   ImageIO.write(image, "jpg", new File("img.jpg"));
            }
            catch(Exception e )
            {  
                working=false;
                System.out.println("stopped working socket");
            }

       }
   }

    public void end()
    {
        try
        {
            working=false;
            img_s.close();
        }
        catch(Exception e)
        {
            System.out.println("connection close failed");
        }
    }

}

}
}

当它收到图像时,它会打印出图片的大小,以便我们知道它是否可以获得图像。

我在不同的机器(mac和pc windows7)和不同的软件(blueJ,eclipse甚至用命令行启动它)上尝试了这两个程序。问题表明无论在哪个环境中。

以下是存储在Google云端硬盘中的整个项目代码的链接: 服务器:https://drive.google.com/file/d/0B6w_5_wGgS14UnZCbXJKUGdvSFE/view?usp=sharing 客户端:https://drive.google.com/file/d/0B6w_5_wGgS14aUlmcG4yQWVnemM/view?usp=sharing

我认为最好下载源代码并查看其中,很难在此处描述所有内容。真诚地寻找你的帮助!

1 个答案:

答案 0 :(得分:0)

您描述的行为:它有时有效,有时无效,取决于延迟或执行它的机器通常指向竞争条件What is a race condition?)。

此处使用

BoolFlag来指示处理何时开始,因此可能由不同的线程访问(setValuegetValue或类似)。如果我们有一个声明如下:

// b is a BoolFlag
if (b.getValue()) { // (1)
    b.setValue(false); // (2)
}

然后,在(1)执行之前,两个线程可能会在(2)处成功完成测试。因此,为了使代码线程安全,这两个操作必须在一个步骤中执行,它们必须是 atomic 。 Java为此提供了java.util.concurrent.atomic.*个类,例如AtomicBoolean具有函数compareAndSet(expectedValue, newValue),如果操作成功,则只返回true。当然,如您所述,您也可以使用synchronized自行编写,并在public synchronized boolean compareAndSet(...)实施中添加BoolFlag

在我说谎之前,这似乎也值得一读Volatile boolean vs AtomicBoolean