2015-07-18 2 views
0

Для начала это приложение JavaFX с классической архитектурой MVC. Этот ролик приложения кубится и отображает их. Цель состоит в том, чтобы отобразить их для нескольких клиентов. Я использую многопоточный «эхо-сервер» с сокетами для работы с клиентами. Поскольку в JavaFX мы не можем напрямую отправлять узлы через сокет, я решил отправить аргументы, которые сгенерированы клиентом, а затем клиент отправляет их на сервер, чтобы он мог эхо аргументы всем подключенным клиентам.Java Multi-threaded socket client/server: отправка и получение объектов Enummap

Вот как это работает:

Во-первых, основной поток сервера создается. Он создает ServerSocket, а цикл while создает новый поток, который будет обрабатывать подключенный клиент. Этот основной поток сервера имеет 3 метода: 2, которые будут отслеживать подключенный клиент, и 1, который отправляет входящие аргументы всем подключенным клиентам.

public class DiceRollServerThread implements Runnable 
{ 
    private Server _server; 
    private Server_C controller; 
    private Vector<ObjectOutputStream> tabClients = new Vector<ObjectOutputStream>(); // Contain all outpput streams to connected clients 
    private Thread t; 
    private ServerSocket diceSS; 

    public DiceRollServerThread(Server server) throws IOException 
    { 
     _server = server; 

     controller = _server.getController(); 

     String port = "2000"; 
     String ip = "127.0.0.1"; 

     controller.setConsole("IP : "+ip+"\n"+"Port : "+port); 

     diceSS = new ServerSocket(Integer.parseInt(port), 0, InetAddress.getByName(null)); 

     t = new Thread(this); 
     t.start(); 
    } 

    @Override 
    public void run() 
    { 
     while (true) // bloquing on ss.accept 
     { 
      try 
      { 
       new DiceRollThread(diceSS.accept(), this); 
      } 
      catch (IOException e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    } 

    synchronized public void sendAll(EnumMap<ARGS, String> arguments) throws IOException 
    { 
     ObjectOutputStream out; 

     for (int i = 0; i < tabClients.size(); i++) // browsing connected clients 
     { 
      out = (ObjectOutputStream) tabClients.elementAt(i); 
      if (out != null) 
      { 
       out.writeObject(arguments); 
       out.flush(); 
      } 
     } 
    } 

    synchronized public void delClient(int i) 
    { 
     if (tabClients.elementAt(i) != null) // If element exist ... 
     { 
      tabClients.removeElementAt(i); // ... delete it 
      System.out.println("delClient"); 
     } 
    } 

    synchronized public int addClient(ObjectOutputStream out) 
    { 
     tabClients.addElement(out); // Adding new output stream to vector 
     System.out.println("addClient");  
     return tabClients.size()-1; // return client number (size-1) 
    } 

    public Server get_server() 
    { 
     return _server; 
    } 
} 

Вот это обработка резьбы клиентов:

public class DiceRollThread implements Runnable 
{ 
    private Thread t; 
    private Socket _s; 
    private ObjectOutputStream out; 
    private ObjectInputStream in; 
    private DiceRollServerThread _serverThread; // to use main thread methods 
    private int numClient=0; 
    private Server _server; 
    private EnumMap<ARGS,String> _arguments; 

    DiceRollThread(Socket s, DiceRollServerThread serverThread) 
    { 
     _s = s; 
     _serverThread = serverThread; 
     _server = _serverThread.get_server(); 

     try 
     { 
      out = new ObjectOutputStream(_s.getOutputStream()); 
      in = new ObjectInputStream(_s.getInputStream()); 
      numClient = _serverThread.addClient(out); 
      _server.getController().setConsole("Client n°"+numClient+" connected."); 
     } 
     catch (IOException e) 
     { 

     } 

     t = new Thread(this); 
     t.start(); 
    } 

    @Override 
    public void run() 
    { 
     try 
     { 
      while(_s.getInputStream().read() != -1) // verifying if connection is still up 
      { 
       _arguments = (EnumMap<ARGS, String>) in.readObject(); // Problem is here 

       if(_arguments != null) 
       { 
        System.out.println(_arguments); 
        _serverThread.sendAll(_arguments); 
       } 
      } 
     } 
     catch (ClassNotFoundException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 
     finally // Usually happens when client disconnect 
     { 
      try 
      { 
       _server.getController().setConsole("Client n°"+numClient+" disconnected."); 
       _serverThread.delClient(numClient); // deleting from the vector 
       _s.close(); // Closing socket if not done by upper exception 
      } 
      catch (IOException e) 
      { 

      } 
     } 
    } 

Теперь на стороне клиента. Главное приложение имеет контроллер, который получит значение двух полей и хранить их в следующем Enummap

public class Arguments 
{ 
    public enum ARGS {Couleur,Valeur}; 
} 

А затем отправляет его в следующей цепи обработки резьбы на сервере.

private void roll() 
{ 
    arguments.put(ARGS.Couleur, box_couleur.getValue().toString()); 
    arguments.put(ARGS.Valeur, randInt(1,Integer.parseInt(box_de.getValue()))); 

    diceRollThread.send(arguments); // the thread gives his reference to the controller when created 
} 

Клиент нить (которым подключен к серверу)

public class DiceRollThread implements Runnable 
{ 
    private DiceRoll_C _controller; 
    private Socket s; 
    private ObjectOutputStream out; 
    private ObjectInputStream in; 
    private Thread t; 
    private EnumMap<ARGS,String> _arguments; 

    DiceRollThread(DiceRoll diceroll) throws IOException 
    { 
     _controller = diceroll.getController(); 
     _controller.setDiceRollThread(this); 

     String port = "2000"; 
     String ip = "127.0.0.1"; 

     try 
     { 
      s = new Socket(InetAddress.getByName(ip),Integer.parseInt(port)); 
      out = new ObjectOutputStream(s.getOutputStream()); 
      in = new ObjectInputStream(s.getInputStream()); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 

     t = new Thread(); 
     t.start(); 
    } 

    @Override 
    public void run() 
    { 
     try 
     { 
      _arguments = (EnumMap<ARGS, String>) in.readObject(); 

      if(_arguments != null) 
      { 
       _controller.addDice(_arguments); // Creating dice from received arguments 
      } 
     } 
     catch (ClassNotFoundException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 
     finally 
     { 
      try 
      { 
       s.close(); 
      } 
      catch (IOException e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void send(EnumMap<ARGS,String> arguments) // arguments received from the controller, sends them to the server 
    { 
     try 
     { 
      out.writeObject(arguments); 
      out.flush(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 
    } 

Типичный сценарий выглядит следующим образом: Запуск сервера> запуск клиента (подключение сделано успешно)> пользователь пресс-н-ролл. Когда пользователь нажимает рулон, 2 значения сохраняются в enummap, созданных контроллером, контроллер перенаправляет этот enummap на клиентский поток методом send(); и этот метод записывает enumap в поток objectoutput.

Проблема возникает на следующем шаге. Подключение обработки нити клиента на стороне сервера получает EnumMap из потока

_arguments = (EnumMap<ARGS, String>) in.readObject(); 

Но, похоже, она не в состоянии бросить его EnumMap и бросает исключение

java.lang.ClassCastException: java.io.ObjectStreamClass не может быть приведен к java.util.EnumMap

в java.lang.Thread.run (Unknown Source)

Что я делаю неправильно?

ответ

1
while(_s.getInputStream().read() != -1) // verifying if connection is still up 

Проблема здесь. Он потребляет байт из входного потока и поэтому ставит сериализацию из синхронизации с отправителем.

Он также не выполняет цель, указанную в комментарии.Правильный способ сделать это только для того, чтобы поймать IOException: connection reset, который возникнет из-за отправки поврежденному соединению, или EOFException, который возникает из-за чтения прошлого конца потока.

+0

Изменено до (правда), и ошибок больше нет. Спасибо ! – Ishtaar

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