2015-01-13 3 views
1

간단한 에코 서버가 있는데 연결된 사용자가 서버에 아무 것도 입력하지 않으면 모든 다른 클라이언트와 해당 클라이언트가 메시지 "+ MOD"를 받겠습니다.Java TCP Echo 서버 - 브로드 캐스트

지금 모든 클라이언트에게 보내지는 않겠지 만 내 코드에서 무엇이 잘못되었는지 모르기 때문에 메시지를 보낸 클라이언트에게 메시지 "+ MOD"를 보냅니다. 모든 다른 사람들도 그렇게해야합니다.

나는 그것을 얻지 못한다. 나는 모든 클라이언트를 통과하는 루프를 가지고 있지만 여전히 모든 것을 전송하지는 않는다.

SERVER :

package com.murplyx.server; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 

public class Server { 
    public static ServerSocket server; 
    public static ArrayList<Socket> clients = new ArrayList<Socket>(); 

    public static void broadcast(String message) { 
     try { 
      for (Socket socket : clients) { 
       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 

       out.println(message); 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String args[]) { 
     try { 
      server = new ServerSocket(9000); 

      while (true) { 
       clients.add(server.accept()); 

       for (Socket socket : clients) { 
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

        String line = in.readLine(); 

        if (line != null) { 
         broadcast(line + " | MOD"); 
        } 
       } 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

CLIENT :

package com.murplyx.client; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 

public class Client { 
    public static void main(String args[]) { 
     try { 
      while (true) { 
       Socket socket = new Socket("localhost", 9000); 

       BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 

       BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 

       out.println(input.readLine()); 

       System.out.println(in.readLine()); 

       socket.close(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

이 도와주세요.

고맙습니다.

+0

(이 코드는 내가 첨부 된 링크의 코드 (또한 귀하의 질문에)와 함께 간다, 서버의 while 루프 전에 넣어)()', 당신은'out.close()'를 사용하여 반복 할 때마다'PrintWriter'를 닫아야합니다. – colti

+0

제대로 기억한다면 PrintWriter를 닫으면 기본 소켓이 닫힙니다. 한 번 이상 방송해야한다면 닫지 않을 것입니다. – Aify

답변

2

당신이 가진 문제 중 하나는 각 클라이언트가 무한 반복적으로 read stdin, write socket, read socket, write stdout, ...을 수행한다는 것입니다. 당신이 방송 때

모든 다른 클라이언트는 여전히 일반적으로 read stdin 단계에 앉아, 그래서 소켓에서 읽을 수 기다리고 물건가 있다는 것을 그들은 모른다. 그들은 여전히 ​​사용자가 무언가를 입력하기를 기다리고 있습니다.

가장 간단한 옵션 중 하나는 각 클라이언트에서 두 개의 스레드를 시작하는 것입니다. 하나는 read stdin, write socket, ...이고 다른 하나는 read socket, write stdout입니다.

[우리가 동시에에서 사용 가능한 입력 에 대한 여론 조사 소켓과 표준 입력 모두에 자바 NIO를 사용하는 또 다른 (잠재적으로 더 정교한) 옵션].

두 번째 문제는 서버의 accept 호출을 차단 한 다음 각 소켓에서 을 읽는 것입니다.. 한 스레드에서 accept 일 수 있으며 클라이언트 당 다른 스레드 읽고 다른 클라이언트에게 다시 브로드 캐스팅하십시오. NIO는 여기서도 좋은 옵션이 될 수 있습니다. 클라이언트를 읽으려면 폴링 할 수 있습니다.

+0

accept에서 Plus 서버가 중단됩니다. – Fildor

+0

@Fildor 너무 - 아직 그것을 발견하지 못했습니다. – Alnitak

+0

코드로 보여 주실 수 있습니까? Q를 게시 한 후에 모든 클라이언트가 테스트 한 이후로 동일한 IP를 가졌다 고 생각했습니다. – super

0

나는 ArrayLists 소켓 놀이 방법을 정확하게 확실하지 않다, 그래서 내가하기 위해 할 수있는 생각하는 것을 볼 몇 가지

을 (여기 Java EchoTCPServer - Send to all clients을 편집 코드 참조) 나는 분명히 다시 정상 배열을 사용하여 갈 것입니다 고정 : 클라이언트에

:

-Stop는 동안 루프에서 소켓을 닫는. while 루프 바깥 쪽에서 닫습니다 (클라이언트가 서버로 완료 될 때). 또한 루프 외부의 소켓을 선언하십시오.

참고 : 클라이언트가 서버에 연결하기 위해 소켓을 만들면 자동으로 장치 포트가 제공되므로 서로 다른 두 장치가 동일한 IP를 서버에 연결하지 않습니다. TCP 연결은 서버 소켓과 클라이언트 소켓의 두 포트로 구성되며 소켓은 [deviceip : port, serverip : port] (iirc)로 표시됩니다.

- 또한 클라이언트에서 while 루프를 이동할 때마다 새 판독기를 선언 할 필요가 없습니다. 그 모든 것을 외부에 두십시오. while 루프 내의 유일한 것은 readline + print 문입니다.

-readLine은 차단 방법입니다. (이것이 의미하는 바를 모를 경우 readLine은 실제로 행을 읽을 때까지 프로그램을 멈추게 할 것입니다. 이것을 우회하려면 if 문을 .ready() 함수와 결합하여 사용할 수 있습니다. "읽어"할 수있는 일이 있다면 늘 "내의 readLine"에 붙어 아무런 입력이 없다면, 그래서 기능 검사, 확인하기 위해 서버에서

:.

와요 내가 말했듯이, 나는 좋겠

- 서버가 여전히 .accept()에서 멈추는 경우가 있습니다. 따라서 연결이 끝난 후에 한 번만 클라이언트의 입력을 읽을 수 있습니다. 스레드를 사용할 수 있습니다. 대신에 들으려면, 여전히 작동 할 것입니다.

예 : Server.broadcast`에서

// create a tcp listener thread to deal with listening to clients 
Thread listenerThread = new Thread() { 
    public void run() { 
     String clientSentence; 

     while (true) { 
      //loop through each connected socket  
      for (int i = 0; i <= intLastSocket; i++) { 
       Socket z = clientSocket[i]; 
       //make sure the socket is not null or closed (can't do anything 
       //with closed or null sockets   
       if ((z != null) && (!z.isClosed())) { 
        try { 
         // Deal with TCP input here 
         BufferedReader input = new BufferedReader(new 
          InputStreamReader(z.getInputStream())); 
         // read in a line but only if there is one 
         if (input.ready()) { 
          clientSentence = input.readLine(); 
         } 
        } catch (IOException x) { 
         printTCP("IOException caught when reading in: " 
           + x.toString()); 
        } 
        if (clientSentence != null) { 
         System.out.println("Received from client: " 
           + clientSentence); 
         //send this message to the client 
         outputStream[i].println(clientSentence + " | MOD"); 
        } 

        // clear the input 
        clientSentence = null; 
       } 
      } 
     } 
    } 
}; 
listenerThread.start(); 
+0

일반 배열과 비교하여'ArrayList <> '를 사용할 때 _zero_ 상호 작용이 있습니다. – Alnitak

+0

@Alnitak 당신은 더 자세히 설명 할 수 있습니까? – Aify

+1

_ "ArrayLists가 소켓으로 어떻게 작동하는지 정확히 모르겠습니다."_ 일반 배열로 플레이하는 것과 똑같은 방법입니다. – Alnitak

관련 문제