簡體   English   中英

關閉后Java客戶端/服務器資源泄漏

[英]Java Client/Server resource leak after closing

我正在嘗試實現Java命令行聊天服務器和客戶端。 我正在使用4個類,Server.java設置了ServerSocket並接受所有連接。 Client.java可以連接到服務器,然后使用SendMessages.java和ReceiveMessages.java為客戶端和服務器創建2個線程。 線程負責從stdin中獲取輸入並將其發送到套接字的輸出流,並使用傳入的輸入流將其打印到stdout。 啟動服務器並連接客戶端時,一切正常,聊天也有效。 但是,當客戶端或服務器終止時,會導致資源泄漏。 我希望SendMessages類和ReceiveMessages類能夠檢測到客戶端或服務器的連接何時終止,並關閉所有資源以避免資源泄漏。 這是代碼:

Server.java

import java.net.*;
import java.io.*;
import java.util.*;
public class Server{
public static void main(String[] args) throws SocketException,IOException{
    ServerSocket s = new ServerSocket(8000);
    s.setSoTimeout(10000000);
    while(true){
        Socket clientSocket = s.accept();
    handle(clientSocket);

}  
}

   static void handle(Socket clientSocket) throws IOException{
    System.out.println("connection accepted from " + clientSocket.getRemoteSocketAddress());
    receiveMessages(clientSocket);
    sendMessages(clientSocket);
  }

  static void receiveMessages(Socket clientSocket) throws IOException{
    (new Thread(new ReceiveMessages(clientSocket))).start();;

  }

  static void sendMessages(Socket clientSocket)throws IOException{
    (new Thread(new SendMessages(clientSocket))).start();
  }
}

Client.java

import java.net.*;
import java.io.*;
import java.util.*;

public class Client{


public static void main(String[] args) throws IOException, UnknownHostException, ConnectException{
    String hostname = args[0];
    int port = Integer.parseInt(args[1]);
    Socket s = null;
    s = connect(hostname, port);
    handle(s);
}


public static Socket connect(String hostname, int port) throws UnknownHostException, IOException, ConnectException{
    Socket s = null;
    try{
    s = new Socket(hostname, port);
    } catch(ConnectException e){
        System.out.println("Connect Exception caught!");
    }
return s;
}

static void handle(Socket clientSocket) throws IOException, UnknownHostException{
receiveMessages(clientSocket);
sendMessages(clientSocket);
}

static void receiveMessages(Socket clientSocket) throws IOException, NullPointerException{
    (new Thread(new ReceiveMessages(clientSocket))).start();
  }

static void sendMessages(Socket clientSocket)throws IOException, NullPointerException{
  (new Thread(new SendMessages(clientSocket))).start();
}

}

SendMessages.java

import java.io.*;
import java.net.*;
import java.util.*;
public class SendMessages implements Runnable{
Socket clientSocket;

public SendMessages(Socket clientSocket){
    this.clientSocket = clientSocket;
}

public void run(){
    System.out.println("SendMessages thread has started.");
    Scanner sc = new Scanner(System.in);
    PrintWriter out = null;
    try{
    out = new PrintWriter(clientSocket.getOutputStream(), true);
    }
    catch(IOException | NullPointerException e){}

    String message;

    while(true){
        message = sc.nextLine();
        out.println(message);
        if(out.checkError()){
            out.close();
            sc.close();
            System.out.println("SendMessages closed");
        }
    }

}
}

ReceiveMessages.java

import java.io.*;
import java.net.*;
import java.util.*;
public class ReceiveMessages implements Runnable{
    Socket clientSocket;
    public ReceiveMessages(Socket clientSocket){
        this.clientSocket = clientSocket;
    }
    public void run(){
        System.out.println("ReceiveMessages thread has started.");
        BufferedReader in = null;
        try{
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        }catch(IOException|NullPointerException e){}
        String message;
        try{
            while(true){
            while((message = in.readLine())!= null){
                System.out.println(message);
            }

    }
    } catch(IOException|NullPointerException e){
        System.out.println("ReceiveMessages resources closed.");
        try{  
        in.close();
            clientSocket.close();
            }
            catch(IOException f){}
    }
}
}

謝謝!

所以我最近遇到了這樣的問題。

問題是,通過關閉連接的一側,將保留“半開”連接(不再是真正的連接)。

如果配對的服務/設備仍處於活動狀態,則Socket API沒有檢查選項。

那么該怎么辦呢? 我本人更喜歡心跳的概念。 每10秒鍾(或任何其他時間范圍,由您決定),心跳將發送到套接字的輸出流。 當流不再可用時,此操作將引發IOException。 因此,您可以捕獲異常並處理catch塊中的所有“關閉”操作。

例:

    public class Heartbeater
    implements Runnable
{
  private OutputStream os;
  private ServerHandler servhand;
  private Logger logger = Logger.getLogger( Logger.GLOBAL_LOGGER_NAME );

  //NOTE: ServerHandler is my class which handles the socket of the server after ServerSocket.accept();
  public Heartbeater( OutputStream os, ServerHandler servhand )
  {
    this.servhand = servhand;
    this.os = os;
  }

  @Override
  public void run()
  {
    try
    {
      Thread.currentThread().setName( "Heartbeater" );
      // while the handler's connection is alive
      while ( servhand.isConnectionAlive() )
      {

        Thread.sleep( 10000 );

        // dummy write to trigger the exception if the client does not respond properly
        os.write( "_HEARTBEAT_".getBytes() );

      }
    }
    catch ( InterruptedException e )
    {
      logger.log( Level.SEVERE, "HEARTBEATER GOT INTERRUPTED", e );
      Thread.currentThread().interrupt();
    }
    catch ( IOException e )
    {
      logger.log( Level.INFO, "The connection to the client has been lost." );
      // Here you would define the resource close operation.
      servhand.setConnectionAlive( false );
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM