2017-04-15 10 views
1

이 글은 내가 작성한 첫 번째 Java 소켓/다중 스레드 응용 프로그램이므로, 여러분이 목격하려고하는 극악한 코드에 대해 사과하고 싶습니다.Java 다중 스레드 서버 - CPU 사용률이 높고 java.net.SocketException : 소켓이 닫혔습니다.

어쨌든 대부분의 사용자는이 코드를 한 번에 더 많은 클라이언트와의 연결을 허용하는 기본 서버로 간주 할 것입니다. 또한 서버에는 서버를 닫는 StopServer 버튼이있는 인터페이스가 있지만 클라이언트는 서버에 연결 한 다음 연결을 끊는 것 외에는 다른 작업을 수행하지 않습니다. 단순히 서버 클래스를 실행하는 경우

이제, 괜찮아, 아무것도 '나쁜'어떻게 내가 그것을 닫을 때, 그것은하지만, 잘 닫습니다 : 나는 서버 클래스를 실행하는 경우, 다음 :

1 내가 한 번 클라이언트 클래스를 실행하는 서버를 닫으려고 다음 클라이언트 차단을하자, 나는 오류를 얻을 :

java.net.SocketException: socket closed

2 : 각 클라이언트는 CPU 사용률 ~ 30-35%에 대해 추가합니다 단지 짧은 실행이고, 그 이용은 "Java (TM) Platform SE Binary"프로세스에 남아있을 것이다. 계속 실행됩니다. 클라이언트를 서버에 연결하면 30 초, CPU 사용률은 100 %에 도달합니다.

또한 약간의 연구를했으며 "소켓 폐쇄 예외"는 소켓을 닫은 다음 계속 사용하려고 시도했음을 의미하며 서버가 서버를 처리하는 방법에도 문제가있을 수 있음을 알고 있습니다. 연결이 끊어진 클라이언트. 위의 코드의 라인 65에 :

서버

import java.sql.*; 
import java.net.*; 
import java.io.*; 
import java.util.*; 
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 



public class Server extends JFrame 
    { private Connection con; 
    private static int port = 44444; 
    private boolean serverKeepGoing; 
    private static int uniqueId; 
    private ArrayList<ClientThread> al; 
    private ServerSocket serverSocket; 
    public Scanner keyboard = new Scanner(System.in); 

    public static void main(String[] args) throws IOException 
     { Server server = new Server(port); 
      server.start(); 

     } 


    public void ServerClose() 
     { 
      serverKeepGoing = false; 
      try 
      { 
      for(int i = 0; i < al.size(); ++i) 
       { ClientThread tc = al.get(i); 
       try 
        { 
        tc.in.close(); 
        tc.out.close(); 
        tc.socket.close(); } 
       catch(IOException e) { e.printStackTrace(); } 

       serverSocket.close();} 

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


    public Server (int port) 
     { 

     serverInterface(); 
     al = new ArrayList<ClientThread>(); 
     } 




    public void start() 
      { serverKeepGoing = true; 

      try 
      { serverSocket = new ServerSocket(port); 
       System.out.println("Server is running!"); 

       while(serverKeepGoing) 
       { Socket socket = serverSocket.accept(); // accept connection. LINE 65 
        // ^ALSO :java.net.SocketException: socket closed 
        // if I was asked to stop 



       if(!serverKeepGoing) 
        { ServerClose(); break;} 

        ClientThread t = new ClientThread(socket); // make a thread of it 
        al.add(t);         // save it in the ArrayList 
        t.start(); 


       } 



       ServerClose(); // means the server has got to be closed 

      }catch (IOException e) { e.printStackTrace(); System.out.println("Error in method start"); } 


     } 


    public synchronized void remove(int id) { 
     // scan the array list until we found the Id 
     for(int i = 0; i < al.size(); ++i) { 
      ClientThread ct = al.get(i); 
      // found it 
      if(ct.id == id) { 
       al.remove(i); 
       return; 
      } 
     } 
    } 



    class ClientThread extends Thread 
     { // the socket where to listen/talk 
     Socket socket; 
     BufferedReader in; 
     PrintWriter out; 
     boolean clientKeepGoing; 
     // my unique id (easier for deconnection) 
     int id; 


     public ClientThread(Socket socket) 
      { id = ++uniqueId; 
      this.socket = socket; 

      try 
      { 

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


      } 
      catch (IOException e) { return; } 


     } 


     public void run() 
      { 
      boolean clientKeepGoing = true; 
      while(clientKeepGoing) 
       { try 
        { 





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


       } 
      // remove myself from the arrayList containing the list of the 
      // connected Clients 
      remove(id); 
      close(); 
      } 


     // try to close everything 
     private void close() 
      { clientKeepGoing = false; 
      try { 
       if(out != null) out.close(); 
      } 
      catch(Exception e) {} 
      try { 
       if(in != null) in.close(); 
      } 
      catch(Exception e) {}; 
      try { 
       if(socket != null) socket.close(); 
      } 
      catch (Exception e) {} 

      } 


    } 

    public void serverInterface(){ 
     JFrame frame = new JFrame("Server"); 

     frame.setLayout(null); 

     int windowWidth = 300; 
     int windowHeight = 400; 

     frame.setBounds(250, 150, windowWidth, windowHeight); 

     JButton stopServer = new JButton("Stop server"); 

     stopServer.setFocusable(false); 

     stopServer.setBounds(60, 275, 175, 20); 

     frame.add(stopServer); 

     stopServer.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) 
      { 
       ServerClose(); 
       System.exit(1); 
      } 
     }); 



     frame.setResizable(false); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 


    public void windowClosing(WindowEvent e) 
    { ServerClose(); 
     System.exit(1); 
    } 
    public void windowClosed(WindowEvent e) {} 
    public void windowOpened(WindowEvent e) {} 
    public void windowIconified(WindowEvent e) {} 
    public void windowDeiconified(WindowEvent e) {} 
    public void windowActivated(WindowEvent e) {} 
    public void windowDeactivated(WindowEvent e) {} 
    } 

'소켓이 닫혀 java.net.SocketException의'

여기에 코드입니다. 이것이 내가 현재 구축하고있는 전체 응용 프로그램의 단지 조각이다

클라이언트

import java.net.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import java.util.*; 
import javax.swing.*; 

public class Client 
    { private BufferedReader in; 
    private PrintWriter out; 
    private Socket socket; 
    private int port; 
    private String server; 


    public static void main(String[] args) 
     { int portNumber = 44444; 
     String serverAddress = "localhost"; 

     Client client = new Client(serverAddress, portNumber); 

     if(!client.start()) 
      return;  

     } 


    public Client(String server, int port) 
     { this.server = server; 
     this.port = port; 
     } 



    public boolean start() 
     { // try to connect to the server 
     try { 
      socket = new Socket(server, port); 
     } 
     // if it failed not much I can do 
     catch(Exception ec) { 
      System.out.println("Error connectiong to server:" + ec); 
      ec.printStackTrace(); 
      return false; 
     } 


     try 
     { 
      in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
      out = new PrintWriter(socket.getOutputStream(), true);; 
     } 
     catch (IOException eIO) { 
      System.out.println("Exception creating new Input/output Streams: " + eIO); 
      eIO.printStackTrace(); 
      return false; 
     } 

     // creates the Thread to listen from the server 
     new ListenFromServer().start(); 


     // success we inform the caller that it worked 
     return true; 
    } 





    class ListenFromServer extends Thread 
     { 
     public void run() 
      { while(true) 
       { 




       disconnect() ; 
       break; 
       } 
      } 


     } 

    public void disconnect() 
     { try { 
      if(in != null) in.close(); 
     } 
     catch(Exception e) {} // not much else I can do 
     try { 
      if(out != null) out.close(); 
     } 
     catch(Exception e) {} // not much else I can do 
     try{ 
      if(socket != null) socket.close(); 
     } 
     catch(Exception e) {} // not much else I can do 
     } 

    } 

주, 나는 서버 - 클라이언트 통신을해야했던 것만 게시하려고, 그래서 삭제 다른 모든 것들, 난 당신이 아마 어떤 목적이없는 것을 볼 경우이 말인지, 나는 아마 그것을 내가있을 생각 나는 질문이 중복으로 표시있어 볼


을 삭제 생략 불공정 . 첫째, '비슷한'질문에서, 문제는 분명했고, 소켓을 닫은 아웃 포스트 스트림이 닫혀 있었지만 소켓은 여전히 ​​사용되었습니다. 반면에, 내 프로그램은 모든 것을 모두 닫았으며, 제가 언급 한 CPU 문제도 가지고 있습니다. 나는 이른바 '비슷한'질문에서 답을 얻을 수 없다.

+0

중복되었지만 관련 코드를 모두 생략했습니다. 내부에서 'IOException' *을 무시하면 루프가 시작됩니다. – EJP

+0

@EJP 글쎄, 내가 왜 위에서 언급 한 일이 일어 났는지 알고 싶다. 그래서 나는 문제와 관련있는 코드 부분을 추가하는 것이 최선의 방법이라고 생각한다. 둘째로, "루프 내부의 IOException을 무시하는 것이 무엇인지"에 대해 더 자세히 설명 할 수 있다면, 해결해야 할 부분과해야 할 일에 대해 고맙게 생각합니다. 셋째, 어떻게 복제본인지 알지 못합니다. 문제는 분명합니다. 소켓의 출력 스트림을 닫은 다음 입력을 사용하려고합니다. 동시에 모든 것을 함께 닫습니다. 또한, 나는 또한 그의 질문에 해결되지 않은 CPU 문제가있어. –

+0

그것은 소켓을 닫은 다음 계속 사용하고 그렇게하는 예외를 무시하기 때문에 발생합니다. 모든 노력이 힘들다. '루프 안에서 IOException'을 무시하는 것에 대한 해결책은 루프 내에서 'IOException'을 무시하고 * stop *하는 것을 * 찾기 *하는 것입니다. 흑인과 백인이 있습니다. 나는 그것을 발견했다 : 당신도 할 수있다. 결국 당신은 그것을 썼습니다. – EJP

답변

2

높은 CPU 사용률은 클라이언트 스레드가 빈 루프를 사용하여 CPU를 굽는 것 외에 다른 작업을 수행하지 않기 때문입니다. SocketException은 계획대로 작동하므로이를 잡아서 처리하십시오.

+0

글쎄, 클라이언트는 자동으로 연결 해제되기 전에 1 초 동안 만 실행된다고 가정합니다. 그러면 CPU가 '해제'하지 않아야합니까 /? 또한 "소켓 예외"에 대해서는 코드에 아무런 문제가 없다고 말하는 것은 자연 스럽다. –

+0

전체 프로그램에서 클라이언트는 또한 여러 기능을 가진 인터페이스를 가지고 있으며, 말했듯이 클라이언트를 30 초 이상 연결하면 CPU가 100 %가됩니다. –

+1

코드에는 많은 문제가 있지만 소켓 예외는 닫힌 소켓을 사용하려는 일반적인 결과 일뿐입니다. CPU 사용량이 많으면 바쁜 대기를 수행하는 것이 일반적입니다. 모든 코드를 삭제하고 적절한 자습서를 찾은 다음 올바르게 다시 수행하는 것이 좋습니다. – Kayaman