2014-02-09 1 views
0

У меня есть простая игра XO, в которой несколько клиентов играют в XO Chess друг с другом. Я построил сервер, который связывается с каждым подключенным клиентом. (Когда клиент подключается к серверу, я создаю новый класс (реализую Runnable), обрабатываю этот сокет, затем запускаю Thread ... У меня есть список, хранящий весь клиент во внешнем классе). Когда клиент хочет начать игру, он сделайте себе новый сервер и отправьте информацию о номере (его имя, IP-адрес, порт ...) на Сервер. И на сервере у меня есть Список, который добавляет эту комнату в список и отправляет ее другим Клиентам.Java Socket - Обновление переменной экземпляра Список из темы

public class ServerController { 
private ServerView view; 
private ServerSocket myServer; 
private int serverPort = 8881; 
private List<ExchangeData> list; 
private volatile List<Room> rooms; 


public ServerController(ServerView view) { 
    this.view = view; 
    openServer(serverPort); 
    view.showMessage("TCP server is running..."); 
    list = new ArrayList<ExchangeData>(); 
    rooms = new ArrayList<Room>(); 
    while (true) { 
     listening(); 
    } 

} 

private void openServer(int portNumber) { 
    .... 
} 

private void listening() { 

    try { 
     Socket clientSocket = myServer.accept(); 

     ExchangeData ex = new ExchangeData(clientSocket); 
     Thread thread = new Thread(ex); 
     thread.start(); 
     list.add(ex); 

    } catch (IOException e) { 
     System.out.print(e.toString()); 
    } 
} 

class ExchangeData implements Runnable { 
    private Socket clientSocket; 
    private ObjectOutputStream oos; 
    private ObjectInputStream ois; 
    private boolean run = true; 

    public ExchangeData(Socket socket) { 
     try { 
      clientSocket = socket; 
      oos = new ObjectOutputStream(clientSocket.getOutputStream()); 
      ois = new ObjectInputStream(clientSocket.getInputStream()); 
     } catch (Exception ex) { 
      System.out.println(ex.toString()); 
     } 


    } 

    public void closeConnection() { 
     ..... 
    } 



    public void sendData(Object o) { 
     try { 

      oos.writeObject(o); 
     } catch (Exception ex) { 
      view.showMessage(ex.toString()); 
     } 
    } 

    public void run() { 
     try { 

      while (run) { 
       Object data = ois.readObject(); 
       if (data instanceof Object[]) { 
        Object[] o = (Object[]) data; 
        String s = o[0].toString(); 

        if (s.equalsIgnoreCase("Open Room")) { 

         Room r = (Room) o[1]; 
         String username = r.getUsername(); 
         InetSocketAddress isa = r.getIsa(); 
         **rooms.add(r);** 
         List<Room> l = new ArrayList<Room>(rooms); 

         for (ExchangeData ex : list) { 
          ex.sendData(username + " Open A room at : " 
            + isa); 
          **ex.sendData(rooms);** 

         } 

        } else if (s.equalsIgnoreCase("Close Room")) { 
         Room room = (Room) o[1]; 
         rooms.remove(room); 
         List<Room> l = new ArrayList<Room>(rooms); 
         for (ExchangeData ex : list) { 
          ex.sendData(l); 
         } 
        } 

       } else if (data instanceof String) { 
        String s = data.toString(); 
        if (s.equalsIgnoreCase("Quit")) { 
         stopThread(); 
         list.remove(this); 
         closeConnection(); 

        } 
       } 

      } 

     } catch (Exception ex) { 
      try { 
       stopThread(); 
       list.remove(this); 
      } catch (ExceptionInInitializerError e) { 
       e.printStackTrace(); 

      } 
     } 
    } 
} 

}

Проблема заключается в том, когда я исполняю rooms.add (г), другие темы, кажется, не видеть, что "обновление". Например: 1) Первый игрок открывает комнату - размер номера 1; 2) Второй игрок открывает новый номер - размер комнаты теперь 2 (я попытался добавить некоторые строки кода в сторону метода sendData (Object o), который печатает размер комнаты и все равно 2. Но когда строка ObjectoutputStream .write (o), он фактически записывает значение комнат, в которых выполняется Thread (первый игрок), до которого будет 1. Если я создаю новый список, например List l = new ArrayList (комнаты), как я сделал с «Закрывающейся комнатой «Тогда отправьте это, это работает. Я не понимаю, почему? Кто-то, пожалуйста, объясните это мне. Извините за мой плохой английский :(

ответ

1

Когда вы отправляете один и тот же объект через некоторое время через данный объект ObjectOutputStream, поток пишет полное состояние объекта в первый раз, но потом отправляет некоторую ссылку на этот объект.

Это позволяет отправлять сложные графы объектов с циклическими ссылками, не потребляя слишком большой полосы пропускания и не вдаваясь в бесконечные циклы (отправьте A, которые ссылаются на B, поэтому отправляйте B, который ссылается на A, поэтому отправляйте A, которые ссылаются на B и т. Д.).

Итак, если вы хотите отправить новую копию своего списка, сначала вам необходимо использовать метод ObjectOutputStream reset().

+0

Вау, Большое спасибо, Низет, я потратил несколько дней, чтобы прочитать о потоковом безопасном, параллелизме и т. Д., Я мог бы проголосовать за вас. – user2747502

Смежные вопросы