2017-04-15 101 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%。

此外,我做了一點研究,我知道「套接字關閉異常」意味着你關閉了套接字,然後繼續嘗試使用它,而且服務器如何處理斷開客戶端。

下面的代碼:

服務器

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異常:套接字關閉' 是在上面的代碼中的65行。

客戶

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的地方,*停止*這樣做。它在黑色和白色。我發現它:你也可以。畢竟,你寫了它。 – EJP

回答

2

CPU利用率高是因爲您的客戶端線程除了使用空循環燒壞CPU外沒有其他任何操作。至於SocketException,它按計劃運作,所以抓住它並處理它。

+0

那麼,客戶端應該只運行1秒,然後它會自動斷開連接。那麼CPU不應該被「釋放」/?另外,對於「套接字異常」,你的意思是說代碼中沒有必要的錯誤,這只是自然發生的事情? –

+0

而在完整的程序中,客戶端也有一個接口與幾個功能,正如我所說,如果我讓一個客戶端連接超過30秒,CPU將達到100%。 –

+1

代碼有很多錯誤,但套接字異常只是嘗試使用封閉套接字的正常結果。高CPU使用率是忙碌等待的正常結果。我建議刪除所有的代碼,找到一些適當的教程,然後再次正確地做。 – Kayaman