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

时间:2017-04-15 10:22:22

标签: java multithreading sockets client-server

这是我编写的第一个java socket / multithreaded应用程序,因此我想为你即将见证的恶意代码道歉。

无论如何,大多数人可能会认为这个代码是基本的,一个允许一次来自更多客户端的标准服务器。此外,服务器有一个只有一个StopServer按钮的接口,它关闭服务器,同时客户端除了连接到服务器然后断开连接之外什么都不做。

现在,如果我只是运行服务器类,没关系,没有什么“坏”发生,当我关闭它时,它会很好地关闭,但是:

1:如果我运行服务器类,然后运行客户端类一次,让客户端断开连接,然后尝试关闭服务器,我收到错误:

  

java.net.SocketException:socket closed

2:每个客户端只需短暂运行即可增加约30-35%的CPU利用率,并且该利用率将保留在“Java(TM)平台SE二进制”流程中,只要服务器继续运行。如果我让客户端连接到服务器,比方说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:socket closed'在上面代码的第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
        }

    }

请注意,这只是我正在构建的整个应用程序的一个片段,我试图仅发布与服务器 - 客户端通信有关的内容,所以我删除了其他所有内容,我说这是为了防止你看到可能没有任何意义的东西,我可能省略删除它

我看到这个问题被标记为重复,我认为这是不公平的。首先,在“类似”问题中,问题很明显,关闭了outpot流,关闭了套接字,但套接字仍然被使用,同时,我的程序关闭了所有内容,并且还有我提到的CPU问题,因为我无法从所谓的“类似”问题中得到任何答案。

1 个答案:

答案 0 :(得分:2)

高CPU利用率是因为除了使用空循环烧录CPU之外,客户端线程还没有做任何其他事情。对于SocketException,它按计划运行,所以抓住并处理它。