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问题,我无法从所谓的“类似”问题中得到任何答案。
CPU利用率高是因为您的客户端线程除了使用空循环烧坏CPU外没有其他任何操作。至于SocketException
,它按计划运作,所以抓住它并处理它。
那么,客户端应该只运行1秒,然后它会自动断开连接。那么CPU不应该被“释放”/?另外,对于“套接字异常”,你的意思是说代码中没有必要的错误,这只是自然发生的事情? –
而在完整的程序中,客户端也有一个接口与几个功能,正如我所说,如果我让一个客户端连接超过30秒,CPU将达到100%。 –
代码有很多错误,但套接字异常只是尝试使用封闭套接字的正常结果。高CPU使用率是忙碌等待的正常结果。我建议删除所有的代码,找到一些适当的教程,然后再次正确地做。 – Kayaman
重复,但是你省略了所有相关的代码,并且忽略了一个循环内的'IOException' *。 – EJP
@EJP那么,我想知道为什么我上面提到的发生,所以我认为只有添加与问题相关的代码部分才是最好的方法。其次,如果您可以进一步详细说明“忽略循环内部的IOException是否正常”,以及在哪里以及如何解决该问题,我将不胜感激。 第三,我没有看到它是如何重复的,他的问题很明显,关闭了套接字的输出流,然后尝试使用输入流,同时我将它们全部关闭在一起。而且,我也遇到了CPU问题,这在他的问题中没有解决。 –
发生这种情况是因为你正在关闭套接字,然后继续使用它并忽略这样告诉你的异常。全面的努力。至于'忽略循环内部的IOException',解决方法是*找到*在循环内忽略IOException的地方,*停止*这样做。它在黑色和白色。我发现它:你也可以。毕竟,你写了它。 – EJP