2014-11-28 2 views
0

나는 주로 UDP와 컴퓨터가 서로 이야기하는 방법을 배우기 위해 간단한 Java 채팅 프로그램을 만들고 있습니다.다른 클라이언트가 서버에 보낼 때 UDP 서버를 클라이언트에 푸시하는 방법

지금까지 클라이언트에 연결할 클라이언트를 수신하도록 서버를 설정할 수 있었으며 서버를 통해 한 클라이언트에서 다른 클라이언트로 메시지를 리디렉션 할 수도 있습니다. 즉,

클라이언트 A -> 서버 -> 클라이언트 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(); 
    } 
} 

클라이언트 측

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(); } 

} 

He 나는 동시에 두 개의 메인을 실행하려고하면 내가 오류입니다 재 (이 오류가 나에게 의미가 대부분의 경우, 난 그냥 듣고 클라이언트를하려면 어떻게 다른 모르겠어요) :

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. 이제 마지막 단계에서 서버로부터 수신 한 포트 번호에서 수신 클라이언트에 리스너/ServerSocket의 시작을 갱신 고유 한 포트에서 실행중인 서버가 있다고 가정하면 클라이언트는 고유 한 포트에서 실행합니다.
  6. 클라이언트가 다른 클라이언트를위한 서버로 메시지를 보낼 때. 서버는 단순히 수신 클라이언트 포트를 검색하고 수신자에게 메시지를 보내도록 클라이언트 연결을 설정합니다.
+0

적어도 UDP 소켓을 청취 할 수 있습니다. - http://freecodetrips.blogspot.de/2009/06/java-socket-that-reuse-address.html 또는 MultiCastSocket을 사용하는 (ab) – zapl

+0

에서 사용할 수있는'SO_REUSE_ADDR' 옵션이 있습니다. 간단하고 훌륭합니다. 나는 그것을 시험해 볼 것이고 만약 내가 일하게한다면 당신에게 알려줄 것입니다. 일반적으로 각 클라이언트 - 서버 관계에 대해 고유 한 포트를 보유하는 것이 좋습니다. 다시 한 번 감사드립니다! – Jona

+1

@Jona 클라이언트가 동일한 시스템에서 실행되는지 또는 다른 시스템에서 실행되는지에 따라 다릅니다. 클라이언트가 다른 시스템에서 실행되는 경우. 클라이언트와 서버 소켓 모두 동일한 포트 일 수 있습니다. –

0

'수신자'스레드 용 소켓을 리 바인드해서는 안됩니다. 이 라인을 제거하십시오 sock = new DatagramSocket(PORT_NUMBER+1);. 패킷을 보내고 받으려면 소켓 하나만 있으면되므로 소켓을 다시 바인딩하면 안됩니다. 패킷을 받기를 기다리는 중이면 스레드가 멈추고 패킷을 보낼 수 없으므로 둘 다 동시에 수행해야하는 경우 두 개의 소켓을 사용해야합니다. 문제가 해결 되었습니까?

+0

고맙습니다. David, 먼저 Juned의 전술을 시도한 다음 자신의 것을 확인합니다. – Jona

관련 문제