这是我编写的第一个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问题,因为我无法从所谓的“类似”问题中得到任何答案。
答案 0 :(得分:2)
高CPU利用率是因为除了使用空循环烧录CPU之外,客户端线程还没有做任何其他事情。对于SocketException
,它按计划运行,所以抓住并处理它。