2014-11-28 2 views
0

Я работаю над простой программой чата Java, в основном, чтобы узнать о UDP и о том, как компьютеры разговаривают друг с другом.Как заставить UDP-сервер нажимать на Клиент, когда другой клиент отправляет сервер

До сих пор мне удалось настроить сервер, чтобы прослушивать подключение к нему клиентов, и я даже могу перенаправить сообщения от одного клиента к другому, хотя сервер - то есть:

Client A -> сервер -> Client B

Я добрался до места, где сервер фактически посылает пакет (sock.send (пакетов)), но загвоздка в том, что клиенты не» действительно «знаю», чтобы слушать. Они просто знают, как отправить сервер.

Я попытался настроить run() для клиента, аналогично тому, что у меня есть с сервером, но как только я вытаскиваю двух клиентов, моя программа вылетает из-за того, что я пытаюсь прослушивать один и тот же порт.

код сервера (Просьба игнорировать весь материал сепаратора, это просто способ я использую для отправки различных частей информации в настоящее время):

package com.jona.chat.UDP; 

import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 
import java.sql.SQLException; 
import java.util.TreeMap; 

public class UDPServer extends Thread{ 

    final int PORT_NUMBER = 4447; 
    private String separator = "~!~--//1337"; //IGNORE THIS 
    protected DatagramSocket sock = null; 
    private TreeMap<String,InetAddress> nameIPTree = new TreeMap<String,InetAddress>(); //IGNORE THIS 


    public static void main(String args[]) throws IOException{ 

     UDPServer SERVER = new UDPServer(); 

     //calls the run() method 
     SERVER.start(); 
    } 

    public UDPServer() throws IOException{ 

     sock = new DatagramSocket(PORT_NUMBER); 
    } 

    public void run(){ 
     System.out.println("Waiting for Client"); 
     while(true){ 

      try{ 

       //======================================================================================================== 
       //Prepare the packet to receive data from client 
       //======================================================================================================== 

       //Buffer (byte array) that will receive the client's data 
       byte[] buffer = new byte[512]; 

       //Create a packet using the empty buffer and its length 
       DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 

       //======================================================================================================== 
       //Receive the packet from the client, execute the statement, and get the result 
       //======================================================================================================== 

       //Receive the packet 
       sock.receive(packet); 
       System.out.println("Server: Received packet from Client"); 

       //Extract the data 
       String fromUser = new String(packet.getData(), 0, packet.getLength()); 
       //Parse data 
       String[] instructions = fromUser.split(separator); //IGNORE THIS 

       //Add UserName and IP to tree 
       if(instructions[0].equals("LOGIN")){ 
        System.out.println("Logged in!"); 
        nameIPTree.put(instructions[1], packet.getAddress()); 

        run(); 
       } 
       //Send message to recipient and upload to DB 
       else if(instructions[0].equals("MESSAGE")){ 

        //Create a string composed of the sender and the message 
        String toUser = instructions[2] + separator + instructions[3]; 

        //Store the string in the buffer 
        buffer = toUser.getBytes(); 

        //Make a new packet with the buffer, its length, the RECEPIENT'S IP (retrieved from tree, hence receiving user HAS TO BE LOGGED IN) 
        //and the port number the server uses 

        packet = new DatagramPacket(buffer, buffer.length, nameIPTree.get(instructions[2]), PORT_NUMBER+1); 

        //Send the packet 
        sock.send(packet); 
        System.out.println("Server: Sent result to Client: " + toUser); 
       } 

       } 
       catch (IOException e){ 
        e.printStackTrace(); 
        break; 
       } 
     } 
     System.out.println("Closing the socket"); 
     sock.close(); 
    } 
} 

Client Side

public class UDPClient extends Thread{ 

    final int PORT_NUMBER = 4447; 
    private String separator = "~!~--//1337"; 

    public String TalkToServer(String message){ 

     try{ 
      //======================================================================================================== 
      //Create a datagram socket 
      //======================================================================================================== 
      DatagramSocket sock = new DatagramSocket(); 

      //======================================================================================================== 
      //Connect & Send to server 
      //======================================================================================================== 

      //Create a byte array called buffer that will hold the instructions to be sent to the server 
      byte[] buffer = message.getBytes("UTF-8"); 

      //Get the IP address to which the packet will be sent 
      InetAddress ipAddress = InetAddress.getByName("123.45.67"); 

      //Create a datagram packet which is composed of the buffer (message), its length, the IP address, 
      //and the port (matches with server's listening port) to send the data on 
      DatagramPacket packet = new DatagramPacket(buffer, buffer.length, ipAddress, PORT_NUMBER); 

//same thing in both ifs, I know, I just wanted to see what it was doing 
       if(message.substring(0, 5).equals("LOGIN")){ 

        System.out.println("Client: Logging in"); 


       //Send the packet 
       sock.send(packet); 
       System.out.println("Client: Sent packet to Server\nSent: " + message); 

       sock.close(); 
       return null; 
      } 
      if(message.substring(0, 7).equals("MESSAGE")){ 

       System.out.println("Client: Sending message to server"); 

       //Send the packet 
       sock.send(packet); 
       System.out.println("Client: Sent packet to Server\nSent: " + message); 

       sock.close(); 
       return null; 
      } 
     } 
     catch(IOException e){System.out.print(e);} 
     return null; 
    } 
} 

И, наконец, , вот как я пытался заставить клиента слушать (это в моем основном классе):

public static void main(String[] args) throws SocketException{ 

    MainGUI listener = new MainGUI(); 
    listener.start(); 

... 

public MainGUI() throws SocketException{ 


    sock = new DatagramSocket(PORT_NUMBER+1); 
} 
public void run(){ 


    byte[] buffer = new byte[512]; 
    DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 

    try { 
     sock.receive(packet); 
     String fromUser = new String(packet.getData(), 0, packet.getLength()); 
     //Parse data 
     String[] instructions = fromUser.split(separator); 
     System.out.println("Received message: " + instructions[1] + " from " + instructions[0]); 


    } catch (IOException e) { e.printStackTrace(); } 

} 

Он повторно это ошибка, я получаю, когда я пытаюсь запустить два Mains одновременно (эта ошибка имеет смысл для меня по большей части, я просто не знаю, что еще нужно сделать, чтобы получить клиент для прослушивания):

Exception in thread "main" java.net.BindException: Address already in use: Cannot bind 
    at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method) 
    at java.net.DualStackPlainDatagramSocketImpl.bind0(Unknown Source) 
    at java.net.AbstractPlainDatagramSocketImpl.bind(Unknown Source) 
    at java.net.DatagramSocket.bind(Unknown Source) 
    at java.net.DatagramSocket.<init>(Unknown Source) 
    at java.net.DatagramSocket.<init>(Unknown Source) 
    at java.net.DatagramSocket.<init>(Unknown Source) 
    at com.jona.chat.UDP.UDPServer.<init>(UDPServer.java:28) 
    at com.jona.chat.UDP.UDPServer.main(UDPServer.java:20) 

Заранее благодарим за помощь!

ответ

1

Вы не можете запускать два прослушивателя на одном и том же порту на одном компьютере/сетевом интерфейсе. Я предлагаю это решение, которое должно быть достаточно хорошим для запуска сервера и нескольких клиентов на одном компьютере.

  1. На вашем сервере, поддерживать список доступных клиентов прослушивания портов
  2. На сервере поддерживать карты клиентов и их порты прослушивания
  3. Перед начала прослушивателя клиента, сделать подключение клиента к серверу и задать на следующий доступный порт клиента
  4. сервер обновляет отображение клиент/порт
  5. Start слушающий/ServerSocket на клиенте прослушивания на номер порта, полученного от сервера на последнем этапе
  6. сейчас предположим, что у вас есть сервер, работающий на уникальном порту, клиенты, работающие на уникальных портах.
  7. Когда клиент отправляет сообщение на сервер, предназначенный для другого клиента. Сервер просто извлекает порт получающего клиента и делает клиентское соединение с ним получателем для отправки сообщения.
+0

Вы можете хотя бы прослушивать сокеты UDP. - Существует опция SO_REUSE_ADDR, которая может использоваться либо по адресу http://freecodetrips.blogspot.de/2009/06/java-socket-that-reuse-address.html, либо по (ab) с использованием MultiCastSocket – zapl

+0

. Это простой и блестящий. Я попробую и дам вам знать, буду ли я работать. Вообще говоря, эта хорошая практика - просто иметь уникальный порт для каждого отношения клиент-сервер? Еще раз спасибо! – Jona

+1

@Jona Зависит от того, работают ли клиенты на той же машине или другой. Если клиенты работают на разных машинах. Вы можете использовать один и тот же порт для клиентских и серверных сокетов. –

0

Вы не должны перепроверять сокет для потока «приемника». Удалите эту строку sock = new DatagramSocket(PORT_NUMBER+1);. Вам нужен только один сокет для отправки и получения пакетов, поэтому вам не следует перепроверять сокет. Хотя, если вы ожидаете получить пакет, это остановит ваш поток, и вы не сможете отправить пакет, поэтому, если вам нужно делать оба одновременно, вы должны использовать два сокета. Это исправляет вашу проблему?

+0

Ценит Дэвид, я сначала попробую тактику Юнеда, а затем посмотрю о твоем – Jona