客户端服务器、对象输入/输出、死锁



我对编写基于客户端/服务器的应用程序很陌生。服务器类和客户端类都是在线程中启动的。通过tcp使用对象输出/输入流也是新手。我对连载从来都不感兴趣。在我的应用程序中,我试图使用对象输入/输出流,但打开它们似乎会导致我的应用软件失效。有趣的是,如果我评论两行:

outStream = new ObjectOutputStream(socket.getOutputStream());
inStream = new ObjectInputStream(socket.getInputStream());

连接运行良好,应用程序进入下一个面板等。但我仍然无法在整个套接字中发送任何对象。当我真的试图打开那些溪流。它仍然连接,但应用程序被冻结。我有两个问题:第一:使用序列化更好吗第二:如果我可以使用Object流,我应该如何打开它们?我可以在服务器/客户端线程中执行吗?

感谢您抽出时间

这是ClientApp的代码:

public void run()
{
while (true)
{
try // odswiezanie co sekunde
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
try // polaczenie
{
if (connecting)
{
socket = new Socket(hostIP, port);
JOptionPane.showMessageDialog(null, "Connection established!");
connected = true;
connecting = false;
frame.settingPanelForClient.bPlayerName.setText("Put the ships on your board!");
outStream = new ObjectOutputStream(socket.getOutputStream());
inStream = new ObjectInputStream(socket.getInputStream());
connectionEstablished(frame);
}
}
catch (UnknownHostException e)
{
JOptionPane.showMessageDialog(frame, "Unknown server!");
connected = false;
} 
catch (IOException e)
{
JOptionPane.showMessageDialog(frame,"An Error occured while trying to connect to the server!");
e.getMessage();
e.printStackTrace();
connected = false;
} 
catch (IllegalThreadStateException e)
{
e.printStackTrace();
}
try // odbior obiektow
{
if(connected)
{
while(!opponentIsReady){
System.out.println("wszedlem do connected!(klient) ");
System.out.println(opponentIsReady);
if(!opponentIsReady)
{
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
}
if(iAmReady && !opponentIsReady)
{
System.out.println("wszedlem do iAmReady i wysylam wiadomosc o gotowosci do klienta!");
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
outStream.writeObject(iAmReady);
outStream.flush();
}
if(opponentIsReady)
{
sendMap();
proceedToNextPanel(frame);
opponentIsReady = false;
}
}}

}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}

是否对Map对象使用Serializable接口?

如果您在某个步骤中仍然处于冻结状态,可能是因为您试图读取对象(从服务器或客户端),但对方并没有发送它。当对象未被读取时,它将等待内容。

我不知道你的服务器是如何工作的,但当oppenentReadyfalse时,你读了两次响应。

if(inStream.readObject()!=null){if(inStream.readObject()instanceofBoolean){//。。。}}
如果这不是预期的行为,则应将其存储在本地变量中。

再一次,这是我想要(分步骤)实现的smt

1. user choose to open connection(he becomes a server and waits for a client
to connect) - done.
2. second user choose to connect(becomes a client and connects to the 
second player(server) - done.
3. Both get message that the connection is established and they are moved 
to the next Panel where they do specific operations - done.
4.When anyone of them finishes, I want to tell it to the second guy
(it is represented by a boolean local varable) - here comes the problem.
5. When both have finished, they should be moved to the next Panel where
they play.(before they start playing, Maps that they have set in the previous Panel 
should be sent to each other.

如果只有我知道也许不知道如何发送这些信息,我可以处理下一步但是发送代码应该放在哪里,因为它似乎放错了地方。以下是客户端/服务器类的完整代码:

connecting-在按下按钮后在另一个类中设置为true。

iAmready-当玩家完成设置地图时设置为true,并且应该发送给对手,因为它通过在获取时将opponentIsReady设置为true来触发特定操作。

public class ClientApp implements Runnable
{
public static String hostIP = "127.0.0.1";
public static int port = 1000;
public static boolean connected = false;
public static boolean connecting = false;
public static boolean iAmReady = false;
public static boolean opponentIsReady = false;
public static Socket socket = null;
public static ObjectInputStream inStream;
public static ObjectOutputStream outStream;
public final Frame frame;
public static Map mapToGet;
public static Map mapToSend;

public ClientApp(Frame parent)
{
frame = parent;
mapToGet = new Map();
mapToSend = new Map();
}
@Override
public void run()
{
while (true)
{
try // odswiezanie co sekunde
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
try // polaczenie
{
if (connecting)
{
socket = new Socket(hostIP, port);
JOptionPane.showMessageDialog(null, "Connection established!");
connected = true;
connecting = false;
frame.settingPanelForClient.bPlayerName.setText("Put the ships on your board!");
connectionEstablished(frame);
}
}
catch (UnknownHostException e)
{
JOptionPane.showMessageDialog(frame, "Unknown server!");
connected = false;
} 
catch (IOException e)
{
JOptionPane.showMessageDialog(frame,"An Error occured while trying to connect to the server!");
e.getMessage();
e.printStackTrace();
connected = false;
} 
catch (IllegalThreadStateException e)
{
e.printStackTrace();
}
try // odbior obiektow
{
if(connected)
{
FileOutputStream out = new FileOutputStream("/tmp/message.ser");
outStream = new ObjectOutputStream(out);
FileInputStream in = new FileInputStream("/tmp/message.ser");
inStream = new ObjectInputStream(in);
while(!opponentIsReady){
System.out.println("wszedlem do connected!(klient) ");
System.out.println(opponentIsReady);
if(!opponentIsReady)
{
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
}
if(iAmReady && !opponentIsReady)
{
System.out.println("wszedlem do iAmReady i wysylam wiadomosc o gotowosci do klienta!");
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
outStream.writeObject(iAmReady);
outStream.flush();
}
if(opponentIsReady && iAmReady)
{
sendMap();
proceedToNextPanel(frame);
opponentIsReady = false;
}
}
inStream.close();
outStream.close();
in.close();
out.close();
}

}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
public static void connectionEstablished(Frame frame)
{
frame.remove(frame.connectPanel);
frame.getContentPane().add(frame.settingPanelForClient);
frame.validate();
frame.repaint();
}
public static void proceedToNextPanel(Frame frame)
{
frame.remove(frame.settingPanelForClient);
frame.getContentPane().add(frame.opponentsMove);
frame.validate();
frame.repaint();
}
public static Map getMap()
{
try
{
if (connected)
if (inStream.readObject() != null && inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
return mapToGet;
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
public static void sendMap()
{
if (connected)
if (mapToSend != null)
{
try
{
outStream.writeObject(mapToSend);
outStream.flush();
} catch (IOException e)
{
e.printStackTrace();
}
}
}

}

public class ServerApp implements Runnable
{
public static int port = 1000;
public static boolean connected = false;
public static boolean connecting = false;
public static boolean iAmReady = false;
public static boolean opponentIsReady = false;
public static Socket socket = null;
public static ServerSocket hostServer = null;
public static ObjectInputStream inStream;
public static ObjectOutputStream outStream;
public static Map mapToGet;
public static Map mapToSend;
final Frame frame;

public ServerApp(Frame parent)
{
frame = parent;
mapToGet = new Map();
mapToSend = new Map();
}
@Override
public void run()
{
while(true)
{
try 
{ 
Thread.sleep(1000);
}
catch (InterruptedException e) {}
try 
{
if (connecting) 
{
hostServer = new ServerSocket(port);
socket = hostServer.accept();
connected = true;
connecting = false;
JOptionPane.showMessageDialog(null, "Connection Established!");
frame.settingPanelForServer.bPlayerName.setText("Put the ships on your board!");
connectionEstablished(frame);
}
}
catch (UnknownHostException e) 
{
connected = connecting = false;
}
catch (IOException e)
{
connected = connecting = false;
} 
try // odbior obiektow
{
if(connected)
{
while(!opponentIsReady){
System.out.println("wszedlem do connected(server)");
System.out.println(opponentIsReady);
if(!opponentIsReady)
{
inStream = new ObjectInputStream(socket.getInputStream());
if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}
}
if(iAmReady && !opponentIsReady)
{
System.out.println("wszedlem do iAmReady i wysylam wiadomosc o gotowosci do servera!");
outStream = new ObjectOutputStream(socket.getOutputStream());
JOptionPane.showMessageDialog(frame, "Waiting for opponent to finish");
outStream.writeObject(iAmReady);
outStream.flush();
}
if(opponentIsReady && iAmReady)
{
sendMap();
proceedToNextPanel(frame);
opponentIsReady = false;
}
}}

}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
public static void connectionEstablished(Frame frame)
{
frame.remove(frame.waitPanel);
frame.getContentPane().add(frame.settingPanelForServer);
frame.validate();
frame.repaint();
}
public static void proceedToNextPanel(Frame frame)
{
frame.remove(frame.settingPanelForServer);
frame.getContentPane().add(frame.playPanelForServer);
frame.validate();
frame.repaint();
}
public static Map getMap()
{
try
{
if (connected)
if (inStream.readObject() != null && inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
return mapToGet;
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
public static void sendMap()
{
if (connected)
if (mapToSend != null)
{
try
{
outStream.writeObject(mapToSend);
outStream.flush();
} catch (IOException e)
{
e.printStackTrace();
}
}
}

}

正如我之前所说,对于同一个对象,不能多次使用readObject()。

例如,用途:

Object objectRead=inStream.readObject();
if (objectRead != null) {
if (objectRead instanceof Boolean) {
opponentIsReady = Boolean.valueOf(objectRead);
System.out.println(opponentIsReady);
} else if (objectRead instanceof Map) {
mapToGet = (Map) objectRead;
}
}

代替:

if(inStream.readObject() != null)
{
if(inStream.readObject() instanceof Boolean)
{
opponentIsReady = inStream.readBoolean();
System.out.println(opponentIsReady);
}
else if(inStream.readObject() instanceof Map)
{
mapToGet = (Map) inStream.readObject();
}
}

我想你不明白它是如何工作的:重新发布客户端/服务器连接时,可以使用线程读取或写入对象。

我给你代码,你可以测试以了解它是如何工作的:

服务器应用程序:

公共类ServerApp实现Runnable{public static int port=1000;public static boolean opponentIsReady=false;public static套接字=null;public static ServerSocket hostServer=null;public static ObjectInputStream inStream;公共静态ObjectOutputStream outStream;公共静态mapToGet;公共静态映射发送;最终框架;private boolean connected=false;公共ServerApp(框架父级){frame=父项;mapToGet=新映射();mapToSend=新映射();}@Overridepublic void run(){//服务器初始化端尝试{hostServer=新的ServerSocket(端口);JOptionPane.showMessageDialog(框,"等待对手完成");//Accept将等待客户端尝试连接socket=hostServer.accept();JOptionPane.showMessageDialog(null,"连接已建立!");//重新发布连接时初始化流inStream=新的ObjectInputStream(socket.getInputStream());outStream=新的ObjectOutputStream(socket.getOutputStream);frame.settingPanelForServer.bPlayerName.setText("把船放在你的船上!");connectionEstablished(框架);connected=true;}catch(IOException ex){Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE,null,ex);}int x=0;//循环用于发送/接收所有消息while(已连接){尝试{尝试{线程睡眠(1000);}catch(InterruptedException ex){Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE,null,ex);}Object o=String.format("我给你发了一条消息(%s)",x++);outStream.writeObject(o);对象响应=inStream.readObject();System.out.println("响应:"+响应);}catch(IOException ex){Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE,null,ex);connected=false;}catch(ClassNotFoundException ex){Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE,null,ex);connected=false;}}System.err.println("连接已关闭");}公共静态空连接建立(帧-帧){frame.remove(frame.waitPanel);frame.getContentPane().add(frame.settingPanelForServer);frame.validate();frame.repaint();}公共静态void processedToNextPanel(框架){frame.remove(frame.settingPanelForServer);frame.getContentPane().add(frame.playPanelForServer);frame.validate();frame.repaint();}公共静态Map getMap(){尝试{if(inStream.readObject()!=null&&inStream.readObject(映射实例){mapToGet=(Map)inStream.readObject();return mapToGet;}}catch(ClassNotFoundException e){e.printStackTrace();}catch(IOException e){e.printStackTrace();}返回null;}公共静态void sendMap(){if(mapToSend!=null){尝试{outStream.writeObject(mapToSend);outStream.flush();}catch(IOException e){e.printStackTrace();}}}}

ClientApp:

公共类ClientApp实现Runnable{public static字符串hostIP="127.0.0.1";public static int port=1000;public static boolean connected=false;公共静态布尔连接=true;公共静态布尔值iAmReady=false;public static boolean opponentIsReady=false;public static套接字=null;public static ObjectInputStream inStream;公共静态ObjectOutputStream outStream;公共最终框架;公共静态mapToGet;公共静态映射发送;public ClientApp(框架父级){frame=父项;mapToGet=新映射();mapToSend=新映射();}@Overridepublic void run(){尝试{//客户端初始化端socket=新套接字(hostIP,端口);//如果套接字连接成功,则通过,否则将抛出execeptionJOptionPane.showMessageDialog(null,"连接已建立!");//初始化流outStream=新的ObjectOutputStream(socket.getOutputStream);inStream=新的ObjectInputStream(socket.getInputStream());frame.settingPanelForClient.bPlayerName.setText("把船放在你的船上!");connectionEstablished(框架);connected=true;}catch(IOException ex){Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE,null,ex);}//循环将接收服务器消息并发送响应while(已连接){尝试{对象serverMessage=inStream.readObject();System.out.println("服务器已发送:"+serverMessage);对象myResponse=String.format("我收到%s",serverMessage);outStream.writeObject(myResponse);}catch(IOException ex){Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE,null,ex);connected=false;}catch(ClassNotFoundException ex){Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE,null,ex);connected=false;}}System.err.println("连接已关闭");}公共静态空连接建立(帧-帧){frame.remove(frame.connectPanel);frame.getContentPane().add(frame.settingPanelForClient);frame.validate();frame.repaint();}公共静态void processedToNextPanel(框架){frame.remove(frame.settingPanelForClient);frame.getContentPane().add(frame.opponentsMove);frame.validate();frame.repaint();}公共静态Map getMap(){尝试{如果(已连接){if(inStream.readObject()!=null&&inStream.readObject(映射实例){mapToGet=(Map)inStream.readObject();return mapToGet;}}}catch(ClassNotFoundException e){e.printStackTrace();}catch(IOException e){e.printStackTrace();}返回null;}公共静态void sendMap(){如果(已连接){if(mapToSend!=null){尝试{outStream.writeObject(mapToSend);outStream.flush();}catch(IOException e){e.printStackTrace();}}}}}

最新更新