我有两个问题
完整的工作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();
....
}
正确的预期行为是因为在创建时已经创建了两个对象ObjectOutputStream
和ObjectInputStream
。无需在每次发送之前和每次接收之前重新创建它们。
如何解决这个问题?
第二个问题: 当有东西需要阅读时,有什么东西可以写入和读取吗?
换句话说;在发送和接收端使用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;
}
答案 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;
这都错了。 Socket
和ObjectInputStream
应该是每个已接受连接实例化的Runnable
类的成员。不是服务器类的成员......除非你只想要一个连接?
当有东西要写时,是否有写技术
是的,只需致电writeObject().
并在有东西要读的时候阅读?
只需致电readObject().
它会阻止,直到有东西要读。
答案 1 :(得分:0)
正确的预期行为是因为两个对象ObjectOutputStream和ObjectInputStream都已在创建时创建。无需在每次发送之前和每次接收之前重新创建它们。如何解决?
创建一次并将它们存储在保存socket
的位置,并每次重复使用。注意:如果您以多线程方式访问,则需要添加锁定以避免损坏流。
当有东西需要阅读时,有什么东西可以写入和读取吗?
“要写的东西”很容易,只要你有东西要写,而不是你不写的时候调用writeXxxx。只有在您知道有什么需要阅读的情况下才能阅读。例如如果对于每个写,你只需要一个读,这是有效的。在更一般的情况下,你需要线程总是等待阅读。
答案 2 :(得分:0)
run()方法中不需要此行oos = new ObjectOutputStream(socket.getOutputStream());
。
您只需在写入服务器或客户端后执行此操作
oos.writeObject(dp);
oos.flush();