我正在实施服务器 - 客户端解决方案。详细地说,服务器端是用java实现的,应该是多线程的。客户端将是一个Android应用程序,它连接到java serversocket。
我已经为这个项目做了一些工作,但现在我遇到了一个问题,我无法找到解决方案。我已经研究了很多,但我找不到任何有用的答案。
这是服务器代码:
public class Server implements Runnable{
protected int serverPort = 8001;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread = null;
protected Vector<WorkerThread> threads;
protected volatile Vector<Player> players;
protected Vector<Game> games;
protected synchronized Vector<Player> getPlayers()
{
return players;
}
public Server(int port)
{
this.serverPort = port;
this.threads = new Vector<WorkerThread>(1);
this.games = new Vector<Game>(1);
this.players = new Vector<Player>(1);
}
@Override
public void run() {
System.out.println("Server starting");
synchronized (this)
{
this.runningThread = Thread.currentThread();
}
try
{
openServerSocket();
while (! isStopped())
{
Socket clientSocket = null;
try
{
clientSocket = this.serverSocket.accept();
}
catch (IOException e)
{
if (isStopped())
System.out.println("Server stopped.");
break;
}
this.threads.add(new WorkerThread(clientSocket));
}
}
finally
{
for (int i=0;i<this.threads.size();i++)
this.threads.get(i).stopThread();
System.out.println("Server stopped");
}
}
private void openServerSocket()
{
try
{
this.serverSocket = new ServerSocket(this.serverPort);
System.out.println("Server is listening");
}
catch (IOException e)
{
throw new RuntimeException("Cannot open port "+this.serverPort,e);
}
}
public synchronized void stop()
{
this.isStopped = true;
try
{
this.serverSocket.close();
}
catch (IOException e)
{
throw new RuntimeException("Error closing server", e);
}
}
private synchronized boolean isStopped()
{
return this.isStopped;
}
public class WorkerThread extends Thread
{
protected Socket clientSocket = null;
protected ObjectOutputStream oos = null;
protected ObjectInputStream ois = null;
private Player player;
protected ReadThread readThread;
public WorkerThread(Socket clientSocket)
{
this.clientSocket = clientSocket;
this.start();
}
@Override
public void run() {
// synchronized (players)
// {
int playerId = 0;
if (getPlayers().size() > 0)
playerId = getPlayers().get(getPlayers().size()-1).id + 1;
player = new Player(playerId,"NoName");
getPlayers().add(player);
// }
try
{
oos = new ObjectOutputStream(clientSocket.getOutputStream());
ois = new ObjectInputStream(clientSocket.getInputStream());
System.out.println("WorkerThread and streams created!");
readThread = new ReadThread(ois, this);
System.out.println("ReadThread created!");
while (this.isInterrupted() == false)
{
try {
Thread.sleep(500);
System.out.println("WorkerThread is waiting ...");
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
readThread.stopThread();
try
{
oos.close();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try
{
ois.close();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try
{
clientSocket.close();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("WorkerThread and streams destroyed!");
}
}
protected synchronized void stopThread()
{
// synchronized (players)
{
getPlayers().remove(player);
}
System.out.println("Player removed from list");
this.interrupt();
}
public void sendPackage(DataPackage p)
{
try {
oos.writeObject(p);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void processPlayerPackage(PlayerPackage p)
{
}
private void processStringPackage(StringPackage p)
{
String msg = p.data;
System.out.println("Incoming command: " + msg);
//Kommandos auswerten
if (msg.equalsIgnoreCase("Start new game"))
{
// games.add(new Game(p));
// sendMsg("New game created!");
// System.out.println("New game created");
}
else if (msg.toLowerCase().startsWith("playername="))
{
String name = msg.substring("playername=".length());
player.name = name;
sendPackage(new StringPackage("Hallo "+name));
System.out.println("Player send name");
}
else if (msg.equalsIgnoreCase("Get running games"))
{
// sendPackage(new StringPackage("Hallo "+name));
// sendMsg("Running games following:");
// sendObject(games);
// wr.sendPackage(p);
System.out.println("Player requested running games");
}
else if (msg.equalsIgnoreCase("Get player count"))
{
// synchronized (players)
{
sendPackage(new StringPackage("Playercount="+players.size()));
}
System.out.println("Player requested player count");
}
else if (msg.equalsIgnoreCase("Get active players"))
{
// sendMsg("Active players following:");
// synchronized (players)
{
for (int i=0;i<getPlayers().size();i++)
System.out.println("Player" + i + ": "+getPlayers().get(i).name);
sendPackage(new PlayerPackage(getPlayers()));
}
System.out.println("Player requested active players");
}
else if (msg.equalsIgnoreCase("Start game"))
{
System.out.println("Player wants to start a game");
}
else if (msg.equalsIgnoreCase("Logout"))
{
this.stopThread();
}
else
System.out.println("Command could not be processed: " + msg);
}
protected void processPackage(DataPackage p) {
if (p instanceof StringPackage)
{
processStringPackage((StringPackage) p);
}
else if (p instanceof PlayerPackage)
{
processPlayerPackage((PlayerPackage) p);
}
else
{
}
}
}
public class ReadThread extends Thread
{
private ObjectInputStream in;
private WorkerThread thread;
public ReadThread(ObjectInputStream in, WorkerThread r)
{
this.thread = r;
this.in = in;
this.start();
}
@Override
public void run()
{
while (this.isInterrupted() == false)
{
try {
DataPackage p = (DataPackage) this.in.readObject();
if (p != null)
thread.processPackage(p);
} catch (SocketException e) {
e.printStackTrace();
thread.stopThread();
break;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
// e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("ReadThread has stopped!");
}
public synchronized void stopThread()
{
this.interrupt();
}
}
}
问题是,每个WorkerThread似乎都有自己的服务器开头的共享变量状态。例如,如果建立了连接,则会在WorkerThread中创建一个新的Player,并从服务器添加到Vector players
。在此之后,我使用包含此Player Vector的ObjectOutputStream发送一个Object。对于此数据传输,我创建了一个新类,它实现了Serializable
PlayerPackage
。
public class PlayerPackage extends DataPackage {
private static final long serialVersionUID = -5206233636684028091L;
protected Vector<Player> data;
public PlayerPackage(Vector<Player> v)
{
this.data = v;
}
public Vector<Player> getData() {
return data;
}
public void setData(Vector<Player> data) {
this.data = data;
}
}
如果有其他连接,则会创建另一个Player对象并添加到向量中。所以球员矢量现在包含两名球员。为了测试,我在发送之前打印矢量的内容。此输出是正确的,因为它打印两个连接的两个播放器。但是如果我创建并向两个连接发送新的PlayerPackage
,则只有第二个和更新的连接才能获得两个玩家。第一个连接仍然只有一个Player(第一个玩家)获得一个PlayerPackage
我已经尝试使用synchronize
和volatile
来解决此问题,但我的尝试都没有帮助。
我知道这是很多要阅读的代码,但我认为我应该为您提供有关我特定问题的详细信息。