2016-09-01 8 views
2

私は多くのクライアントに参加することができるサーバーを作った。
しかし、私は問題があります。
サーバーを起動/停止するSTART/STOPボタンを追加しました。しかし、コードは私の望むように動作しません。接続はクローズされず、コードはIOExceptionになります(これはServerLogicの部分です)。
さらに、クライアントは引き続きサーバーに接続できます。Java:例外なくサーバーを停止する(ソケットを閉じる)方法は?

サーバー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; 
} 
} 

CLIENT加入者(ないneccessaryコードが削除されました)私は逃した何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 
    } 
} 
} 

ボタン?
例外なく接続を正しく閉じるにはどうすればよいですか?
Socketを閉じる直前にすべてのクライアントに送信する必要がありますか?閉じる必要があるか、サーバー上のSocketを閉じるだけで十分でしょうか?
よろしく。

+1

例外スタックトレースを追加してください。もちろん、 –

+0

。申し訳ありませんが、私は忘れてしまった。 – rainbow

+1

accept()メソッドにあるServerSocketを閉じると、もちろん*例外を伴いaccept()メソッドが中止されます。どのようにしてブロッキング方法が通常中止されるか。例外をキャッチする必要があります。catchブロック内で、ソケットが閉じられたために例外がスローされたかどうかを判断する必要があります。*または別の理由がある場合は*。 catchブロック内でisClosed()を使用するだけで、その決定を行うことができます。 – Durandal

答えて

3

サーバーを起動/停止するSTART/STOPボタンが追加されました。しかし、コードは私の望むように機能しません。接続は閉じられません。

これは、受け入れられたソケットではなく、ServerSocketを閉じているためです。

となり、コードはIOException「Server Logic」の「この問題」になります。

これは正常です。ここには何も間違っていない。

さらに、クライアントは引き続きサーバーに接続できます。

いいえできません。 既存のクライアントは、既存の接続を引き続き使用できます。それらを閉じたい場合は閉じてください。

例外なく接続を正しく閉じるにはどうすればよいですか?

ただ閉じます。一般的なケースで例外を発生させることなくそれを行うことはできません。あなたがしたい理由はありません。受け入れられたソケットスレッドが、既存のすべての接続を直ちに中止するのではなく、読み取りタイムアウトを使用して読み取りタイムアウトを取得した後に終了して終了する方が良いかもしれません。あなたのSTOPボタンが適度に反応するように、例えば15秒というように、タイムアウトを十分短くすることができます。

ソケットを閉じる前に、すべてのクライアントに送信する必要がありますか?閉じる必要がある、またはサーバー上のソケットを閉じるだけで十分でしょうか?

ソケットを閉じるだけで十分です。余分なメッセージを送信しても値は追加されません。クライアントは、通常のエンド・オブ・ストリーム・インジケーションを読み込み、またはIOException: connection resetを書き込みに使用します。

+0

私は最後の行で間違っていました。私は同意する、+1。 –

+0

この回答は、私が知る必要があるすべてのことを説明しています。ありがとうございました。 – rainbow

関連する問題