2016-10-08 3 views
1

죄송합니다. 검색했지만 모든 대답으로 문제가 해결되지 않는 것 같습니다. 여러 개의 클라이언트 메시지에 응답 할 ServerSocket을 만들려고 할 때이 오류가 발생합니다.java.net.BindException : 주소가 이미 사용 중입니다. 바인딩 할 수 없습니다.

내 서버 코드 :

package Server; 

import java.net.*; 
import java.io.*; 

public class Server { 
    public final static int defaultPort = 7; 

    public static void main(String[] args) { 
     try { 
      ServerSocket ss = new ServerSocket(defaultPort);    
      int i = 0; 
      while (true) { 
       try { 
        System.out.println("Server is running on port " 
          + defaultPort); 
        Socket s = ss.accept(); 
        System.out.println("Client " + i + " connected"); 
        RequestProcessing rp = new RequestProcessing(s, i); 
        i++; 
        rp.start(); 
       } catch (IOException e) { 
        System.out.println("Connection Error: " + e); 
       } 
      } 
     } catch (IOException e) { 
      System.err.println("Create Socket Error: " + e); 
     } finally { 

     } 
    } 
} 

class RequestProcessing extends Thread { 
    Socket channel; 
    int soHieuClient; 

    public RequestProcessing(Socket s, int i) { 
     channel = s; 
     clientNo = i; 
    } 

    public void run() { 
     try { 
      byte[] buffer = new byte[6000]; 
      DatagramSocket ds = new DatagramSocket(7);   
      while (true) { 
       DatagramPacket incoming = new DatagramPacket(buffer, 
         buffer.length); 
       ds.receive(incoming); 
       String theString = new String(incoming.getData(), 0, 
         incoming.getLength()); 
       System.out.println("Client " + clientNo 
         + " sent: " + theString); 
       if ("quit".equals(theString)) { 
        System.out.println("Client " + clientNo 
          + " disconnected"); 
        ds.close(); 
        break; 
       } 
       theString = theString.toUpperCase(); 
       DatagramPacket outsending = new DatagramPacket(
         theString.getBytes(), incoming.getLength(), 
         incoming.getAddress(), incoming.getPort()); 
       System.out.println("Server reply to Client " 
         + clientNo + ": " + theString); 
       ds.send(outsending); 
      } 
     } catch (IOException e) { 
      System.err.println(e); 
     } 

    } 
} 

내 클라이언트 코드 :

package Client; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 
import java.net.Socket; 

public class Client extends Object { 
    public final static int serverPort = 7; 

    public static void main(String[] args) { 
     try { 

      DatagramSocket ds = new DatagramSocket(); 
      InetAddress server = InetAddress.getByName("192.168.109.128"); 
      Socket s = new Socket("192.168.109.128", 7);    
      String theString = ""; 
      do { 
       System.out.print("Enter message: "); 
       InputStreamReader isr = new InputStreamReader(System.in); 
       BufferedReader br = new BufferedReader(isr); 
       theString = br.readLine(); 
       byte[] data = theString.getBytes(); 
       DatagramPacket dp = new DatagramPacket(data, data.length, 
         server, serverPort); 

       ds.send(dp); 
       System.out.println("Sent to server server: " + theString); 

       byte[] buffer = new byte[6000]; 

       DatagramPacket incoming = new DatagramPacket(buffer, 
         buffer.length); 
       ds.receive(incoming); 
       System.out.print("Server reply: "); 
       System.out.println(new String(incoming.getData(), 0, incoming 
         .getLength())); 

      } while (!"quit".equals(theString)); 
      s.close(); 
     } catch (IOException e) { 
      System.err.println(e); 
     } 
    } 
} 

첫 번째 클라이언트로는 원활하게 작동 연결합니다. 하지만 두 번째 클라이언트에서 java.net.BindException throw합니다 : 이미 사용중인 주소 : 바인딩 할 수 없습니다. 두 번째 클라이언트는 전송하지 및 메시지를받을 수 있지만 클라이언트 없음 RequestProcessing.run 당신은 생성자에서 수신 소켓을 무시하고 하나의 동일한 포트에서 DatagramSocket로를 열하기로 결정, 그래서 여전히 0

Server is running on port 7 
Client 0 connected 
Server is running on port 7 
Client 0 sent: msg 0 
Server reply to Client 0: MSG 0 
Client 1 connected 
Server is running on port 7 
java.net.BindException: Address already in use: Cannot bind 
Client 0 sent: msg 1 <<-- this one is sent from client 1 but Client No is 0 
Server reply to Client 0: MSG 1 
+0

코드가 의미가 없습니다. TCP 부분을 전혀 필요로하지 않거나 서버의 여러 UDP 소켓을 필요로하지 않습니다. – EJP

답변

2

하다 할 수 있습니다 듣고있다. 무슨 일이 일어날 것이라고 기대 했습니까?

class RequestProcessing extends Thread { 
    Socket channel; 
    int soHieuClient; 

    public RequestProcessing(Socket s, int i) { 
     // ***************** 
     // The processor should be using this socket to communicate 
     // with a connected client *using TCP Streams* 
     channel = s; 
     clientNo = i; 
    } 

    public void run() { 
     try { 
      byte[] buffer = new byte[6000]; 
      // ***************************** 
      // But, instead of using the this.channel, your code 
      // decides to ignore the TCP socket, 
      // then open another UDP *"server-side like"* socket. 
      // First time it's OK, but the second thread attempting 
      // to open another DatagramSocket on the same port will fail. 
      // It's like attempting to open two TCP ServerSockets on the 
      // same port 
      DatagramSocket ds = new DatagramSocket(7); 

[추가]

당신은 당신이 사용하게 될 어떤 프로토콜을 결정해야합니다 : 다음 아마 그래서 DatagramSocket의, TCP 통신을하지 않으려는, 당신이 ServerSocket/Socket 쌍을 사용하는 경우.

UDP 통신을 원하면 ServerSocket/Socket은 접근 방식과 관련이 거의없고 DatagramSocket을 사용해야합니다. 구성 :

  1. with a port on the serverside - 한 번만 수행하십시오.
  2. without any port for the client sideDatagramPackets을 서버 주소 및 포트로 한정하십시오.

Datagram client/server configurations에 대한 Oracle 사이트의 자습서를 참조하십시오.

+1

TCP 포트는 UDP 포트와 별개입니다. 그의 문제는 모든 클라이언트 연결에서 UDP 포트 7에 바인딩하려고 계속한다는 사실에 있습니다. – selbie

+0

@selbie true ... –

1

main 서버 소켓에서 새 클라이언트 TCP 연결을 수신 할 때마다 RequestProcessing 클래스의 다른 인스턴스가 위로 올라옵니다. RequestProcessing 인스턴스 스레드를 처음 시작하면 UDP 포트 7에 성공적으로 바인드됩니다. 그러나 두 번째 클라이언트가 연결되고 다른 프로세스가 이미 존재하는 동안 RequestProcessing의 다른 인스턴스를 시작하려고 시도합니다. 그게 효과가 없을거야.

RequestProcessing 클래스가 매번 새 포트를 선택하고 어느 포트가 선택되었는지 TCP 소켓으로 다시 신호를 보내도록 프로토콜을 수정해야합니다.

하지만 그것이 나라면 나는 이것을 할 것이다. 모든 클라이언트에 대해 단일 RequestProcessing 인스턴스가 있어야합니다. UDP 에코 소켓이 패킷이 도착한 주소로 응답을 보내면이 클래스의 인스턴스 하나만 있으면됩니다.

0

의 TCP 솔루션 :

유틸리티 클래스 (I 여러 장소에서 같은 코드를 쓰기에는 너무 게으른) :

public class SocketRW { 
    Socket socket; 
    BufferedReader in; 
    PrintWriter out; 

    public SocketRW(Socket socket) 
    throws IOException 
    { 
     super(); 
     this.socket = socket; 
     if(null!=socket) { 
     this.in=new BufferedReader(new InputStreamReader(socket.getInputStream())); 
     this.out=new PrintWriter(socket.getOutputStream()); 
     } 
    } 

    public String readLine() 
    throws IOException { 
     return this.in.readLine(); 
    } 

    public void println(String str) { 
     this.out.println(str); 
    } 

    public Socket getSocket() { 
     return socket; 
    } 

    public BufferedReader getIn() { 
     return in; 
    } 

    public PrintWriter getOut() { 
     return out; 
    } 
    } 

Server 코드 - 더 이상 데이터 그램을 바로 입력을 사용하여/출력 소켓의 동일한 IO 스트림을 사용하여 더 이상 데이터 그램 소켓 - 유틸리티

public class TCPServer 
    implements Runnable // in case you want to run the server on a separate thread 
    { 
    ServerSocket listenOnThis; 

    public TCPServer(int port) 
    throws IOException { 
     this.listenOnThis=new ServerSocket(port); 
    } 

    @Override 
    public void run() { 
     int client=0; 
     while(true) { 
     try { 
      Socket clientConn=this.listenOnThis.accept(); 
      RequestProcessing processor=new RequestProcessing(clientConn, client++); 
      processor.start(); 
     } catch (IOException e) { 
      break; 
     } 

     } 
    } 

    static public void main(String args[]) { 
     // port to be provided as the first CLI option 
     TCPServer server=new TCPServer(Integer.valueOf(args[0])); 
     server.run(); // or spawn it on another thread 
    } 
    } 

    class RequestProcessing extends Thread { 
    Socket channel; 
    int clientNo; 

    public RequestProcessing(Socket s, int i) { 
     channel = s; 
     clientNo = i; 
    } 

    public void run() { 
     try { 
     SocketRW utility=new SocketRW(this.channel);   
     while (true) { 
      String theString=utility.readLine().trim(); 
      System.out.println("Client " + clientNo 
       + " sent: " + theString); 
      if ("quit".equals(theString)) { 
      System.out.println("Client " + clientNo 
       + " disconnected"); 
      this.channel.close(); 
      break; 
      } 
      theString = theString.toUpperCase(); 
      utility.println(theString); 
     } 
     } catch (IOException e) { 
     System.err.println(e); 
     } 
    } 
    } 

클라이언트 코드를 사용하여 리더/라이터로 포장 소켓에서 스트림.

class TCPClient 
    implements Runnable // just in case you want to run multithreaded clients 
    { 
    Socket socket; 

    public TCPClient(InetAddress serverAddr, int port) 
    throws IOException { 
     this.socket=new Socket(serverAddr, port); 
    } 

    public void run() { 
     String theString=""; 
     InputStreamReader isr = new InputStreamReader(System.in); 
     try { 
     SocketRW utility=new SocketRW(this.socket); 
     BufferedReader br = new BufferedReader(isr); 
     do { 
      System.out.print("Enter message: "); 
      theString = br.readLine().trim(); 
      utility.println(theString); 
      System.out.println("Sent to server server: " + theString); 

      String received=utility.readLine(); 
      System.out.println("Server reply: "+received); 

     } while (!"quit".equals(theString)); 
     } 
     catch(IOException e) { 
     e.printStackTrace(); 
     } 
    } 

    static public void main(String[] args) { 
     int port=Integer.valueOf(args[0]); // will throw if its no OK. 

     TCPClient client=new TCPClient(
      InetAddress.getByName("192.168.109.128"), 
      port 
    ); 

     client.run(); 
    } 
    } 
관련 문제