为什么每次发送都有新的ObjectOutputStream,而每次接收都有新的ObjectInputStream? +管理while(true)?

时间:2013-12-10 09:27:33

标签: java while-loop objectoutputstream objectinputstream

我有两个问题 完整的工作SSCCE位于底部。
简单的客户端和服务器;先运行服务器,然后运行客户端 你会看到两个框架,每个框架的左上角都有一个蓝色的球。

服务器端的球是被动的 客户端的球是活跃的

通过使用鼠标,您可以移动客户端球,您将看到服务器球更新其位置,但您无法移动服务器球。没关系。

第一个问题是,如果您查看代码,您会发现每次发送都需要新的ObjectOutputStream,并且每次接收都需要新的ObjectInputStream

客户端:

  Runnable send = new Runnable()
  {
     ....
     //if you comment the following line the sending/receiving will not work!
     oos = new ObjectOutputStream(socket.getOutputStream());
     oos.writeObject(dp);  
     ....
  }

服务器

   Runnable receive = new Runnable()
   {
      ....
      //if you comment the following line the sending/receiving will not work!
      ois = new ObjectInputStream(socket.getInputStream());
      DataObject dp = (DataObject) ois.readObject();
      ....
   }

正确的预期行为是因为在创建时已经创建了两个对象ObjectOutputStreamObjectInputStream。无需在每次发送之前和每次接收之前重新创建它们。

如何解决这个问题?

第二个问题: 当有东西需要阅读时,有什么东西可以写入和读取吗?

换句话说;在发送和接收端使用while(true)会导致无限次写入和读取。那么只有在有更新时才会发送一些技巧。并且只有在有东西被发送时才收到?我尝试了许多技巧,但没有产生好结果。

使用BufferedReader内置了类似的内容,即使使用while(true),循环也会停止,直到有一些新行要读取。

BufferedReader fromClient;

String line = fromClient.readLine();

while (!(line.equals("Bye"))
{
   System.out.println(line);
   line = fromClient.readLine();
}

SSCCE:

服务器包:
BallServer:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JFrame;


public class BallServer extends JComponent
{

   public int x;
   public int y;
   Socket socket;
   ObjectInputStream ois;
   public ServerSocket serverSocket;

   public BallServer()
   {
      try
      {
         serverSocket = new ServerSocket(2222);
         socket = serverSocket.accept();
         openStreams();
         new Thread(receive).start();
      } catch (IOException ex)
      {
         Logger.getLogger(BallServer.class.getName()).log(Level.SEVERE, null, ex);
      }
   }

   private void openStreams()
   {
      if (socket != null)
      {
         try
         {
            ois = new ObjectInputStream(socket.getInputStream());
         } catch (IOException ex)
         {
            Logger.getLogger(BallServer.class.getName()).log(Level.SEVERE, null, ex);
         }
      }
   }
   Runnable receive = new Runnable()
   {
      @Override
      public void run()
      {
         while (true)
         {
            if (socket != null)
            {
               try
               {
                  //if you comment the following line the sending/receiving will not work!
                  ois = new ObjectInputStream(socket.getInputStream());
                  DataObject dp = (DataObject) ois.readObject();
                  x = dp.x;
                  y = dp.y;
                  repaint();
                  System.out.println("x: " + x + " y: " + y);

               } catch (IOException | ClassNotFoundException ex)
               {
                  Logger.getLogger(BallServer.class.getName()).log(Level.SEVERE, null, ex);
               }
            }
         }
      }
   };

   @Override
   public void paint(Graphics g)
   {
      Graphics2D g2d = (Graphics2D) g;

      g2d.setColor(Color.WHITE);
      g2d.fillRect(0, 0, getWidth(), getHeight());

      g2d.setColor(Color.BLUE);
      g2d.fillOval(x - 50, y - 50, 100, 100);

      try
      {
         Thread.sleep(50);
      } catch (Exception ex)
      {
      }

   }

   public static void main(String[] args)
   {
      JFrame frame = new JFrame();
      frame.setTitle("Ball server");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      frame.add(new BallServer());

      frame.pack();
      frame.setSize(650, 500);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }
}

DataObject:

import java.io.Serializable;

public class DataObject implements Serializable
{
   public int x = 0;
   public int y = 0;
}

客户端套餐:
ClientBall:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JFrame;


public class ClientBall extends JComponent
{

   public int x;
   public int y;
   Socket socket;
   DataObject dp;
   ObjectOutputStream oos;
   Thread sendThread;

   public ClientBall()
   {
      dp = new DataObject();
      this.addMouseMotionListener(new MouseMotionAdapter()
      {
         @Override
         public void mouseDragged(MouseEvent e)
         {
            x = e.getX();
            y = e.getY();

            ClientBall.this.dp.x = x;
            ClientBall.this.dp.y = y;

            repaint();
         }
      });

      setSocket();
      openStreams();
      sendThread = new Thread(send);
      sendThread.start();
   }
   Runnable send = new Runnable()
   {
      @Override
      public void run()
      {
         while (true)
         {
            if (socket != null)
            {
               try
               {
                 //if you comment the following line the sending/receiving will not work!
                  oos = new ObjectOutputStream(socket.getOutputStream());
                  oos.writeObject(dp);
                  System.out.println("client write");
               } catch (IOException ex)
               {
                  Logger.getLogger(ClientBall.class.getName()).log(Level.SEVERE, null, ex);
               }
            }
         }
      }
   };

   private void setSocket()
   {
      try
      {
         socket = new Socket("localhost", 2222);
      } catch (UnknownHostException ex)
      {
         Logger.getLogger(ClientBall.class.getName()).log(Level.SEVERE, null, ex);
      } catch (IOException ex)
      {
         Logger.getLogger(ClientBall.class.getName()).log(Level.SEVERE, null, ex);
      }
   }

   private void openStreams()
   {
      if (socket != null)
      {
         try
         {
            oos = new ObjectOutputStream(socket.getOutputStream());
         } catch (IOException ex)
         {
            Logger.getLogger(ClientBall.class.getName()).log(Level.SEVERE, null, ex);
         }
      }
   }

   @Override
   public void paint(Graphics g)
   {
      Graphics2D g2d = (Graphics2D) g;

      g2d.setColor(Color.WHITE);
      g2d.fillRect(0, 0, getWidth(), getHeight());

      g2d.setColor(Color.BLUE);
      g2d.fillOval(x - 50, y - 50, 100, 100);

      try
      {
         Thread.sleep(50);
      } catch (Exception ex)
      {
      }
   }

   public static void main(String[] args)
   {
      JFrame frame = new JFrame();
      frame.setTitle("Ball client");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      frame.add(new ClientBall());

      frame.pack();
      frame.setSize(650, 500);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }
 }

DataObject:

import java.io.Serializable;

public class DataObject implements Serializable
{
   public int x = 0;
   public int y = 0;
}

3 个答案:

答案 0 :(得分:1)

  

第一个问题是,如果你查看代码,你会发现每个发送都需要一个新的ObjectOutputStream,每个接收需要一个新的ObjectInputStream

我不会说'要求'。我会说'表演'。它当然不是必需的,如果你这样做会导致各种各样的问题。

//if you uncomment the following line the sending/receiving will not work!
//if you uncomment the following line the sending/receiving will not work!

我同意。为什么要这样? 不要取消注释。它不会起作用。省略它。或者你的意思是说'如果你评论以下一行'它将不起作用?在这种情况下,我不同意。你应该删除这两行。

  

如何解决这个问题?

如何解决问题?

public class BallServer extends JComponent
{

   public int x;
   public int y;
   Socket socket;
   ObjectInputStream ois;

这都错了。 SocketObjectInputStream应该是每个已接受连接实例化的Runnable类的成员。不是服务器类的成员......除非你只想要一个连接?

  

当有东西要写时,是否有写技术

是的,只需致电writeObject().

  

并在有东西要读的时候阅读?

只需致电readObject().它会阻止,直到有东西要读。

答案 1 :(得分:0)

  

正确的预期行为是因为两个对象ObjectOutputStream和ObjectInputStream都已在创建时创建。无需在每次发送之前和每次接收之前重新创建它们。如何解决?

创建一次并将它们存储在保存socket的位置,并每次重复使用。注意:如果您以多线程方式访问,则需要添加锁定以避免损坏流。

  

当有东西需要阅读时,有什么东西可以写入和读取吗?

“要写的东西”很容易,只要你有东西要写,而不是你不写的时候调用writeXxxx。只有在您知道有什么需要阅读的情况下才能阅读。例如如果对于每个,你只需要一个,这是有效的。在更一般的情况下,你需要线程总是等待阅读。

答案 2 :(得分:0)

run()方法中不需要此行oos = new ObjectOutputStream(socket.getOutputStream());

您只需在写入服务器或客户端后执行此操作

oos.writeObject(dp);
oos.flush();