Java多线程服务器 - 高CPU利用率和java.net.SocketException:套接字关闭

Java多线程服务器 - 高CPU利用率和java.net.SocketException:套接字关闭

问题描述:

这是我写的第一个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

CPU利用率高是因为您的客户端线程除了使用空循环烧坏CPU外没有其他任何操作。至于SocketException,它按计划运作,所以抓住它并处理它。

+0

那么,客户端应该只运行1秒,然后它会自动断开连接。那么CPU不应该被“释放”/?另外,对于“套接字异常”,你的意思是说代码中没有必要的错误,这只是自然发生的事情? –

+0

而在完整的程序中,客户端也有一个接口与几个功能,正如我所说,如果我让一个客户端连接超过30秒,CPU将达到100%。 –

+1

代码有很多错误,但套接字异常只是尝试使用封闭套接字的正常结果。高CPU使用率是忙碌等待的正常结果。我建议删除所有的代码,找到一些适当的教程,然后再次正确地做。 – Kayaman