2017-08-23 13 views
0

私はJavaでソケットゲームを使ってカードゲームを作りたいと思っています。私はこの "PlayerState"オブジェクトを持っていて、ロビーにいるかプレイする準備ができているすべてのプレイヤーを保持しています。問題は、サーバーがすべてのクライアントで同じオブジェクトを送信してもである、すべてのクライアントが不正なデータを持つ別のオブジェクトを受け取る...私はJavaソケット - 異なるオブジェクトを受け取っているクライアント

を説明しましょうこれは、オブジェクトを送信するサーバ内のメソッドです:

private void sendToAll(PlayersState playersState){ 
    resetLists(playersState.getLobbyPlayers(),playersState.getReadyPlayer()); 
    Iterator it = clientOutputStreams.iterator(); 

    while (it.hasNext()) 
     try { 
      ObjectOutputStream writer = (ObjectOutputStream) it.next(); 
      writer.writeObject(playersState); 
      writer.flush(); 
      System.out.println(playersState.getLobbyPlayers()); 
     } catch (Exception ex) { 
     } 
} 

このオブジェクト

private void whileChatting() throws IOException { 
     sendMessage("&nume"+nume); 
     do { 
      try { 
       Object object = input.readObject(); 

       if(object instanceof String) 
        showMessage("\n" + (String) object); 

       else if(object instanceof PlayersState){ 
        System.out.println(((PlayersState) object).getLobbyPlayers()); 
        PlayersState actualPlayerState = new PlayersState(); 
        actualPlayerState.setReadyPlayer(((PlayersState) object).getReadyPlayer()); 
        actualPlayerState.setLobbyPlayers(((PlayersState) object).getLobbyPlayers()); 
        resetLists(actualPlayerState.getLobbyPlayers(),actualPlayerState.getReadyPlayer()); 
       } 

      } catch (ClassNotFoundException var2) { 
       showMessage("Unknown data received!"); 
      } 
     } while(!message.equals("SERVER - END")); 
    } 

をrecieves、これは(クライアントとサーバの両方で利用可能な)オブジェクトであるCLIENT方法である

package sample; 

import java.io.Serializable; 
import java.util.ArrayList; 
import java.util.List; 


public class PlayersState implements Serializable{ 
    private static final long serialVersionUID = 7526472295622776147L; 
    private List<String> LobbyPlayers; 
    private List<String> ReadyPlayer; 

    public PlayersState(){ 
     LobbyPlayers = new ArrayList<>(); 
     ReadyPlayer = new ArrayList<>(); 
    } 

    public void removeFrom(String name, List<String> list){ 
     if(list.contains(name)) 
      list.remove(name); 
    } 

    public void addTo(String name, List<String> list){ 
     list.add(name); 
    } 

    public List<String> getLobbyPlayers() { 
     return LobbyPlayers; 
    } 

    public void setLobbyPlayers(List<String> lobbyPlayers) { 
     LobbyPlayers = lobbyPlayers; 
    } 

    public List<String> getReadyPlayer() { 
     return ReadyPlayer; 
    } 

    public void setReadyPlayer(List<String> readyPlayer) { 
     ReadyPlayer = readyPlayer; 
    } 
} 
私は3つのクライアントを開くと1の後に1がのは、user2はuser1と、サーバからのprintlnからの出力は次のようになりUSER3言わせ

:ここ

[user1, user2, user3] 
[user1, user2, user3] 
[user1, user2, user3] 

アップすべてが正常です。しかし、これは、クライアントが受け取るものです:

クライアント1(USER1):2(USER2)

[user1,user2] 
[user1,user2] 

クライアント3(ユーザー3)

[user1,user2,user3] 

はなぜ

[user1] 
[user1] 
[user1] 

クライアントクライアントはすべて同じデータを受信しませんか?あなたはmultiple-thread.likeこのでそれを同期する必要がありますのでPlayersState

+0

サーバーがクライアントにクライアントを送信するときに 'playersState'が変更されていますか。 – dabaicai

+0

それはどういう意味ですか? –

+0

サーバーで複数のスレッドを使用していますか?もしそうなら、 'PlayersState'インスタンスへのアクセスをどのように同期させますか? –

答えて

-1

は、可変クラスではありません:パフォーマンスのために、上記のコードで

tresetLists(playersState.getLobbyPlayers(),playersState.getReadyPlayer()); 
    Iterator it = clientOutputStreams.iterator(); 

    byte[] sendBytes=null; 
    synchronized (playersState) { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(bos); 
     oos.writeObject(playersState); 
     sendBytes = bos.toByteArray(); 
     oos.close(); 
    } 

    while (it.hasNext()) 
     try { 
      ObjectOutputStream writer = (ObjectOutputStream) it.next(); 
      writer.write(sendBytes); 
      writer.flush(); 
      System.out.println(playersState.getLobbyPlayers()); 
     } catch (Exception ex) { 
     } 

とロックのホールド時間を短縮、我々はplayersStateをロック一度それをsendBytesアレイに一度シリアル化してください。 もちろん、他のスレッドでgetLobbyPlayersgetReadyPlayerを呼び出すのと同じように、いつでもplayersStateを同期する必要があります。

+0

ロック変数を追加する必要がありますか? –

+0

私は自分の答えを更新し、 'ReentrantLock'を使わないで' synchronized'を使ってください。 'PlayersState'の同じインスタンスにアクセスするときは、同期させるべきです。 – dabaicai

+0

今サーバーはjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1502で \t java.io.ObjectInputStream $ BlockDataInputStream.peekByte(ObjectInputStream.java:2917)で\t java.io.EOFException くれてEOFException を与えますjava.io.ObjectInputStream.readObject(ObjectInputStream.java:422)java.lang.Thread.run(スレッドでsample.Main $ newClient.run(Main.java:258)で \t \tで) \t。java:748) –

関連する問題