2016-09-01 5 views
2

많은 클라이언트에 참여할 수있는 서버를 만들었습니다.
그러나 문제가 있습니다.
서버를 시작/중지해야하는 START/STOP 버튼을 추가했습니다. 그러나 코드가 원하는대로 작동하지 않습니다. 연결이 닫히지 않고 코드가 IOException "Server is this"(ServerLogic 부분)로 이동합니다.
클라이언트는 여전히 서버에 연결할 수 있습니다.자바 : 예외없이 서버를 중지하는 방법 (소켓 닫기)

서버 LOGIC

public class ServerLogic 
{ 

private static ServerSocket m_sSocket; 
private static Set<ServerSubscriber> m_subscriberList = new HashSet<ServerSubscriber>(); 
private static boolean m_isServerRun = false; 

private static class ServerLogicHolder 
{ 
    static final ServerLogic INSTANCE = new ServerLogic(); 
} 


private ServerLogic() 
{} 


public static ServerLogic getServerLogic() 
{ 
    return ServerLogicHolder.INSTANCE; 
} 


/** 
* It starts listening of incoming connections from the clients. 
* 
* @param port 
*/ 
public void startListening(int port) 
{ 
    try 
    { 
     if (!m_isServerRun) 
     { 
      m_sSocket = new ServerSocket(port); 
      K6s.getUiServerConsole().addLine(Config.LOG_START); 
      m_isServerRun = true; 
     } 
     else 
     { 
      System.out.println(Config.LOG_ERROR1); 
     } 
    } 
    catch (IOException e) 
    { 
     System.out.println(Config.LOG_ERROR1); 
    } 

    try 
    { 
     while (isServerRun()) 
     { 
      new Thread(new ServerSubscriber(m_sSocket.accept(), K6s.getUiServerConsole())).start(); 
     } 
    } 
    catch (IOException e1) 
    { 
     /* 
     java.net.SocketException: socket closed 
     at java.net.DualStackPlainSocketImpl.accept0(Native Method) 
     at java.net.DualStackPlainSocketImpl.socketAccept(Unknown Source) 
     at java.net.AbstractPlainSocketImpl.accept(Unknown Source) 
     at java.net.PlainSocketImpl.accept(Unknown Source) 
     at java.net.ServerSocket.implAccept(Unknown Source) 
     at java.net.ServerSocket.accept(Unknown Source) 
     at org.czarny.k6s.comm.ServerLogic.startListening(ServerLogic.java:69) 
     at org.czarny.k6s.gui.K6s$2$1.run(K6s.java:138) 
     at java.lang.Thread.run(Unknown Source) 
     */ 
    } 
} 


/** 
* Just close server's socket. 
*/ 
public void stopListening() 
{ 
    if (m_isServerRun) 
    { 
     try 
     { 
      m_isServerRun = false; 
      m_sSocket.close(); 
      m_sSocket = null; 
     } 
     catch (IOException e) 
     { 
      m_isServerRun = true; 
      System.out.println(Config.LOG_ERROR4); 
     } 
    } 
} 


public HashSet<ServerSubscriber> getSubscriberList() 
{ 
    return (HashSet<ServerSubscriber>) m_subscriberList; 
} 


public boolean isServerRun() 
{ 
    return m_isServerRun; 
} 
} 

클라이언트 가입자 (안이 켜지지 코드가 제거되었습니다) START/STOP에게 내가 놓친 무엇

uiStart.addActionListener(new ActionListener() 
    { 
     public void actionPerformed(ActionEvent arg0) 
     { 
      if (!ServerLogic.getServerLogic().isServerRun()) 
      { 
       uiStart.setText(Config.GUI_BTN_STOP); 
       new Thread(new Runnable() 
       { 
        public void run() 
        { 
         try 
         { 
          ServerLogic.getServerLogic().startListening(Integer.parseInt(uiServerPort.getText())); 
         } 
         catch (Exception e) 
         { 
          e.printStackTrace(); 
         } 
        } 
       }).start(); 
      } 
      else 
      { 
       ServerLogic.getServerLogic().stopListening(); 
       m_uiServerConsole.addLine(Config.LOG_STOP); 
       uiStart.setText(Config.GUI_BTN_START); 
      } 
     } 
    }); 

을 처리

public class ServerSubscriber implements Runnable 
{ 

private Socket m_socket; 
private LogComponent m_serverConsole; 
private PrintWriter m_outComm; 

private String m_subscriberIP; 
private String m_subscriberName; 
private String m_subsctiberLogInfo; 


ServerSubscriber(Socket socket, LogComponent serverConsole) 
{ 
    m_socket = socket; 
    m_serverConsole = serverConsole; 
    try 
    { 
     m_outComm = new PrintWriter(socket.getOutputStream(), true); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
    } 
    sendMessage(Config.MSG_HANDSHAKE); 
} 


/** 
* This method runs messages from this subscriber. 
*/ 
public void run() 
{ 
    String line; 
    BufferedReader inComm = null; 

    try 
    { 
     inComm = new BufferedReader(new InputStreamReader(m_socket.getInputStream())); 
    } 
    catch (IOException e) 
    { 
     m_serverConsole.addLine(Config.LOG_ERROR3); 
    } 

    while (ServerLogic.getServerLogic().isServerRun()) 
    { 
     try 
     { 
      //do something here 
    } 
} 
} 

버튼?
예외없이 올바르게 연결을 종료하는 방법은 무엇입니까?
소켓을 닫기 전에 모든 클라이언트에게 닫기 요청을하거나 서버의 소켓을 닫기 만하면 충분합니까?
감사합니다.

+1

예외 스택 추적을 추가 하시겠습니까? –

+0

물론. 미안, 잊어 버렸어. – rainbow

+1

accept() 메서드에있는 ServerSocket을 닫으면 * 물론 accept() 메서드는 예외로 중단됩니다. 차단 방법은 일반적으로 중단됩니다. 예외를 잡아야하고 catch 블록 내에서 소켓이 닫혀 졌기 때문에 예외가 던져 졌는지 결정할 필요가있다 * 또 다른 이유가있는 경우 *. 예를 들어 catch 블록에서 isClosed()를 사용하면됩니다. – Durandal

답변

3

서버를 시작/중지해야하는 START/STOP 버튼이 추가되었습니다. 그러나 코드는 내가 원하는처럼 작동하지 않습니다 연결 당신이 ServerSocket 아닌 받아 소켓을 폐쇄하고 있기 때문에입니다

폐쇄되지 않습니다.

및 코드는 IOException "서버 문제"(ServerLogic 부분)로 이동합니다.

정상입니다. 여기에 아무 것도 없습니다.

또한 클라이언트는 여전히 서버에 연결할 수 있습니다.

아니요. 기존 클라이언트는 기존 연결을 계속 사용할 수 있습니다. 그것들을 닫으려면 그들을 닫으십시오.

예외없이 올바르게 연결을 종료하는 방법은 무엇입니까?

그냥 닫습니다. 일반적인 경우에 예외를 발생시키지 않고 그렇게 할 수는 없으며 원하는 이유가 없습니다. 허용 소켓 스레드가 읽기 타임 아웃을 사용하고 기존의 모든 연결을 즉시 중단하는 대신 읽기 시간 초과 후 닫고 종료하는 것이 더 좋습니다. 타임 아웃 시간을 15 초 정도로 짧게 설정하면 STOP 버튼이 상당히 반응 할 수 있습니다.

소켓을 닫기 전에 모든 클라이언트에게 닫기 메시지를 보내거나 서버의 소켓을 닫기 만하면 충분합니까?

소켓을 닫기 만하면됩니다.여분의 메시지를 보내더라도 값은 추가되지 않습니다. 클라이언트는 자신의 읽기에서 보통 스트림 끝 표시를 얻거나 해당 쓰기에서 IOException: connection reset을 가져옵니다.

+0

나는 마지막 줄에 잘못되었다. 나는 동의한다, +1. –

+0

이 답변은 제가 알아야 할 모든 것을 설명합니다.고맙습니다. – rainbow