2014-02-23 210 views
0

在發送一條指令後關閉客戶端時,代碼正常工作。但是當我希望客戶端和服務器連接持續存在時,客戶端可以一個接一個地向服務器發送多條指令,在服務器端收到空指針異常,並在客戶端收到消息java.net.SocketException: Socket is closed。客戶端向服務器發送文件並且服務器成功接收文件後,會發生這種情況。需要幫忙。該錯誤發生在連接類代碼行switch(clientMsg)。在我看來,出於某種原因BufferedReaderinnull,但我可能會誤解這一點。代碼如下。謝謝。嘗試從InputStream重複讀取時發生空指針異常

服務器

public class server { 
private static ServerSocket serverSocket; 
private static Socket socket = null; 

public static void print(Object s) { 
    System.out.println(s); 
} 


@SuppressWarnings("resource") 
public static void main (String args[]) throws IOException { 
    System.out.print("Specify listening port: "); 
    Scanner _a = new Scanner(System.in); 
    int a = _a.nextInt(); 
    try{ 
     serverSocket = new ServerSocket(a); 
    } 
    catch(IOException e) { 
     System.out.println(e); 
    } 

    while (true) { 
     try { 
      socket = serverSocket.accept(); 
      print("Connected to " + socket); 

      Thread client = new Thread(new Connection(socket)); 
      client.start(); 
     } 
     catch (IOException e) { 
      print(e); 
     } 
    } 

} 

} 

連接

public class Connection implements Runnable { 

public static void print(Object s) { 
    System.out.println(s); 
} 

private Socket socket; 
private BufferedReader in = null; 

public Connection(Socket client) { 
    this.socket = client; 
} 

@Override 
public void run(){ 
    try { 
     in = new BufferedReader(new InputStreamReader(
       socket.getInputStream())); 

     String clientMsg; 
     while (true) { 
      clientMsg = in.readLine(); 
      switch (clientMsg) { 
      case "1": 
       receiveFile(); //method code not included 
       break; 

      default: 
       print("Command not recognized"); 
       break; 
      } 
      //in.close(); 
     } 

    }//try run() 
    catch (IOException e) { 
     print(e); 
    } 
} 

客戶

public class client { 
private static Socket connectToServer; 
private static String fileName; 
private static BufferedReader keybrdIn; 
private static PrintStream msgToServer; 

public static void println(Object e) { 
    System.out.println(e); 
} 

public static void print(Object e) { 
    System.out.print(e); 
} 

public static void main(String args[]) throws IOException{ 
    try{ 
     print("Enter IP: "); 
     String ip = new Scanner(System.in).nextLine();   
     print("Enter port: "); 
     int port = new Scanner(System.in).nextInt(); 
     connectToServer = new Socket(ip, port); 
     keybrdIn = new BufferedReader(new InputStreamReader(System.in)); 
    }catch(IOException e) { 
     println(e); 
    } 

    msgToServer = new PrintStream(connectToServer.getOutputStream()); 

    while (true) { 
     try { 
      switch(Integer.parseInt(action())) { //action() method code not included 
      case 1: 
       msgToServer.println("1"); 
       sendFile(); 
       break; 
      default: 
       println("Invalid input"); 
       break; 
      } 
     }catch (IOException e) { 
      println(e); 
     } 
    } 
} 

SENDFILE()

public static void sendFile() throws IOException { 
    print("Enter file name: "); 
    fileName = keybrdIn.readLine(); 

    File file = new File(fileName); 

    byte[] bytearray = new byte[8192]; 
    FileInputStream fis = new FileInputStream(file); 
    BufferedInputStream bis = new BufferedInputStream(fis); 
    DataInputStream dis = new DataInputStream(bis); 
    OutputStream os = connectToServer.getOutputStream(); 
    DataOutputStream dos = new DataOutputStream(os); 
    dos.writeUTF(file.getName()); 
    int count; 
    while ((count = dis.read(bytearray)) > 0){ 
     dos.write(bytearray, 0, count); 
    } 
    dis.close(); 
    dos.flush(); 
    dos.close(); 
} 

receiveFile()

public void receiveFile() { 
    try { 
     int count; 

     DataInputStream clientFileStream = new DataInputStream(socket.getInputStream()); 

     String fileName = clientFileStream.readUTF(); 
     OutputStream fileOutput = new FileOutputStream("_" + fileName); 

     byte[] mybytearray = new byte[8192]; 
     BufferedOutputStream bos = new BufferedOutputStream(fileOutput); 

     System.out.println("Downloading " + fileName + " ..."); 
     //outToClient().writeBytes("Uploading. Please wait...\n"); 
     while ((count = clientFileStream.read(mybytearray)) > 0){ 
      bos.write(mybytearray, 0, count); 
     } 
     fileOutput.close(); 
     bos.close(); 
     clientFileStream.close(); 

    } 
    catch (IOException e) { 
     print(e); 
    } 
} 
+0

在服務器上,你永遠不會檢查傳入的消息是否爲空 – mangusta

+0

我沒有。請看看上面的代碼。但即使我包含一個'if(in!= null)'語句,也會發生同樣的錯誤。 – 1xQ

+1

可能是文件傳輸後發送到服務器的東西,如果你給你的「sendFile()」可以得出「某些東西」 – mangusta

回答

1

在SENDFILE(),您關閉該關閉你的底層連接的輸出流中的數據輸出流。

根據Socket.getOutputStream()的文檔:

"Closing the returned OutputStream will close the associated socket".

+0

na bro!如果我不關閉'dos',那麼服務器會掛起...因爲數據輸出流永遠不會停止寫入服務器的輸入流。發送永遠不會完成。如果關閉輸出流會終止相應的套接字,那麼我怎麼才能完成一個在發送文件後仍然存在的客戶端服務器程序? – 1xQ

+1

@ 1xQ:這是您協議的問題......您應該發送文件長度,以便服務器知道需要多少字節。 (並且不要關閉輸出流) –

+0

@Eyal Schneider:我剛開始的時候,也出現了同樣的問題。不過,我現在再來看看。但是我不這樣做的原因是因爲在非常大的文件的情況下會導致堆錯誤。我需要傳輸2GB以上的文件。 – 1xQ

1

既然你已經關閉的流,它也將關閉套接字以及提到的Eyal。但是,在關閉流的時刻,服務器端會意識到這一點,併爲read()結果返回-1。 因此,即使您沒有在開始時指定文件長度,通常情況下也會運行良好。

但是,由於您已關閉流,無論如何您都無法重新使用它。要解決此問題,可能需要更改Client類,以便客戶端應創建套接字連接,發送文件,關閉套接字。這是打開的客戶端套接字的一個生命週期。

或者可能在Client類的while循環中,1)將ip,port和filename發送2)創建新的線程並提供這些信息,讓線程打開連接,發送文件,關閉連接3)並在此期間,客戶端while()可以保留從用戶發送的下一個IP,端口和文件名。通過這樣做,您無需等待文件傳輸完成後再等待客戶端程序。

+1

輸入流在流結束時返回-1,但在這種情況下,BufferedInputStream.readLine()返回null。 –

+0

@wonhee:你答案的最後部分看起來很有趣。我會試試看看是否有效。 – 1xQ

0

關於服務器中的NPE,readLine()在流結束時返回null。你忽略了它。你應該在調用之後立即測試它,如果null關閉套接字並退出讀循環。

相關問題