2013-11-29 2 views
2

Я пишу чат-программу в java, и я застрял часами с этой проблемой. Это мой класс, который ждет, чтобы клиенты подключились к серверу. Каждый раз, когда подключается новый клиент, я создаю новый объект ChatClient(String name, DatagramSocket serverSocket,InetAddress IPAddress, int port).Возможно ли, что несколько потоков прослушиваются на одном DatagramSocket?

Моя идея заключалась в том, что каждый объект ChatClient прослушивается в сокете и когда пакет отправляется с того же IP-адреса, что и ChatClient, он будет обрабатывать его, иначе ничего не делать.

Как сейчас, когда у меня только один клиент подключен; клиент получает каждые 2 пакета, а затем run() в WaitForConnection() получает все остальное.

Итак, мой вопрос: возможно ли, что несколько потоков прослушивают один и тот же DatagramSocket без потерь (каждый получает все посылку). Если есть решение, как?

private ArrayList<ChatClient> clients; 
    private DatagramSocket serverSocket; 
    private boolean running; 

    public WaitForConnection() { 
     running = true; 
     clients = new ArrayList<ChatClient>(); 

     try { 
      serverSocket = new DatagramSocket(ChatServer.port); 
     } catch (SocketException e) { 
      System.out 
        .println("Couldn't open socket. Port might alreadybe in use"); 
      e.printStackTrace(); 
     } 
     try { 
      serverSocket.setReuseAddress(true); 
     } catch (SocketException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void run() { 

     while (running) { 
      for (ChatClient ch : clients) { 
       System.out.println(ch.toString()); 
      } 

      byte[] handShake = new byte[1024]; 
      DatagramPacket receivePacket = new DatagramPacket(handShake, 
        handShake.length); 

      try { 
       serverSocket.receive(receivePacket); 
      } catch (IOException e) { 
       System.out.println("Waiting for connections error"); 
       e.printStackTrace(); 
      } 
      String connect = new String(receivePacket.getData()); 
      System.out.println(connect); 

      InetAddress IPAddress = receivePacket.getAddress(); 

      // if connect == "OPEN_CONNECTION" -> new client want to connect. 
      if (connect.contains("openconnection")) { 

       int port = receivePacket.getPort(); 

       try { 

        ChatClient chatClient = new ChatClient(
          IPAddress.getHostName(), serverSocket, IPAddress, 
          port); 

        // Don't want double clients. 
        for (int i = 0; i < clients.size(); i++) { 
         if (clients.get(i).equals(chatClient)) { 
          clients.remove(i); 
         } 
        } 
        clients.add(chatClient); 

       } catch (IOException e) { 
        System.out.println("Couldn't connect to client"); 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

Код для ChatClient, если вам нужно посмотреть на него.

public class ChatClient extends Thread { 
    private InetAddress IPAddress; 
    private DatagramSocket serverSocket; 
    private int port; 
    private String name; 

    public ChatClient(String name, DatagramSocket serverSocket, 
      InetAddress IPAddress, int port) throws IOException { 
     super(name); 
     this.name = name; 
     this.IPAddress = IPAddress; 
     this.serverSocket = serverSocket; 
     this.port = port; 

     byte[] confirmConnection = new byte[1024]; 
     String connected = "Connection to server established"; 
     confirmConnection = connected.getBytes(); 

     serverSocket.send(new DatagramPacket(confirmConnection, 
       confirmConnection.length, IPAddress, port)); 
     start(); 

    } 

    public void run() { 
     while (true) { 
      byte[] message = new byte[1024]; 
      DatagramPacket receivedPacket = new DatagramPacket(message, 
        message.length); 
      try { 
       serverSocket.receive(receivedPacket); 
      } catch (IOException e) { 
       System.out 
         .println("Something went wrong receiving data in ChatClient"); 
      } 
      if (receivedPacket.getAddress().equals(IPAddress)) { 
       String connect = new String(receivedPacket.getData()); 
       connect = connect.toUpperCase(); 
       System.out.println(connect + "client side"); 
       message = connect.getBytes(); 
       try { 
        serverSocket.send(new DatagramPacket(message, 
          message.length, IPAddress, port)); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

ответ

4

Возможно получение нескольких потоков из одного и того же DatagramSocket, но только одна из них получит каждую дейтаграмму.

Я не понимаю, почему вы думаете, что вам нужно это.

+0

Okey, спасибо. Лучше ли один класс получать все данные, а затем распространять данные на нужный клиент, для которого он предназначался? – Jakkra

+1

@ Jakkra, это единственный разумный способ - UDP не имеет подключений, поэтому вам нужно реализовать свою маршрутизацию сообщений на уровне приложений. –

+0

@ EJP вы можете проверить http://stackoverflow.com/questions/29391196/multiple-threads-listening-to-single-socket – Kushal

1

Технически это невозможно, поскольку сетевое оборудование принимает пакет только один раз. Но тогда вы всегда можете дублировать его в памяти после его чтения. В вашем коде в основном просто Arrays.copyOf(receivePacket)

Для более сложной версии вы можете использовать пакет NIO и работать с селектором. Это позволит вам иметь все сетевые соединения, проходящие через поток один, который считывает и распределяет данные для обработки потоков. Это избавит вас от лишних затрат на нарезку, если у вас много соединений от многих клиентов.