這是我寫的第一個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問題,我無法從所謂的「類似」問題中得到任何答案。
重複,但是你省略了所有相關的代碼,並且忽略了一個循環內的'IOException' *。 – EJP
@EJP那麼,我想知道爲什麼我上面提到的發生,所以我認爲只有添加與問題相關的代碼部分纔是最好的方法。其次,如果您可以進一步詳細說明「忽略循環內部的IOException是否正常」,以及在哪裏以及如何解決該問題,我將不勝感激。 第三,我沒有看到它是如何重複的,他的問題很明顯,關閉了套接字的輸出流,然後嘗試使用輸入流,同時我將它們全部關閉在一起。而且,我也遇到了CPU問題,這在他的問題中沒有解決。 –
發生這種情況是因爲你正在關閉套接字,然後繼續使用它並忽略這樣告訴你的異常。全面的努力。至於'忽略循環內部的IOException',解決方法是*找到*在循環內忽略IOException的地方,*停止*這樣做。它在黑色和白色。我發現它:你也可以。畢竟,你寫了它。 – EJP