2013-10-29 16 views
1

在學校,我們有一個項目,我們必須從服務器向客戶端發送文件。我們遇到的問題是,當我們將文件從服務器傳輸到客戶端時,服務器會關閉連接。這是到目前爲止我們的代碼:在將文件傳輸到客戶端後保持套接字連接處於打開狀態java

客戶:

public static void main(String argv[]) throws Exception { 

    int port = 8888; //default 
    if (argv.length 
      > 0) { 
     port = Integer.parseInt(argv[0]); 
    } 

    Socket clientSocket = new Socket("127.0.0.1", port); 
    PrintStream outToServer = new PrintStream(
      clientSocket.getOutputStream()); 
    BufferedReader inFromServer = new BufferedReader(
      new InputStreamReader(clientSocket.getInputStream())); 



    File f = new File("dictionaryPart.txt"); 

    String serverCommand = inFromServer.readLine().toLowerCase(); 
    while (serverCommand != null) { 
     System.out.println(serverCommand); 
     switch (serverCommand) { 
      case "velkommen": 
       outToServer.println("Hej"); 
       break; 
      case "file": 
       f = copy(clientSocket, f); 
       String matches = CrackerCentralized.checkFile(f); 
       System.out.println(matches); 
       outToServer.println(matches); 
       break; 
     } 
     serverCommand = inFromServer.readLine().toLowerCase(); 
    } 
} 

public static File copy(Socket clientSocket, File f) { 
    try { 
     int filesize = 2022386; 
     int bytesRead; 
     int currentTot = 0; 

     byte[] buffer = new byte[filesize]; 
     InputStream is = clientSocket.getInputStream(); 
     FileOutputStream fos = new FileOutputStream(f); 
     BufferedOutputStream bos = new BufferedOutputStream(fos); 
     bytesRead = is.read(buffer, 0, buffer.length); 
     currentTot = bytesRead; 
     while (bytesRead != -1) { 
      bytesRead = is.read(buffer, currentTot, (buffer.length - currentTot)); 
      if (bytesRead >= 0) { 
       currentTot += bytesRead; 
      } 
     } 
     bos.write(buffer, 0, currentTot); 
     bos.flush(); 
     bos.close(); 
    } catch (IOException ex) { 
     Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    return f; 
} 

服務器:

try { 
     PrintStream outToClient = new PrintStream(connection.getOutputStream()); 
     OutputStream os = connection.getOutputStream(); 
     BufferedInputStream input = new BufferedInputStream(new FileInputStream(f)); 
     outToClient.println("file"); 
     final byte[] buffer = new byte[(int) f.length()]; 
     input.read(buffer, 0, buffer.length); 
     os.write(buffer, 0, buffer.length); 
     os.write(-1); 
     os.flush(); 
     System.out.println(connection.isClosed()); 
     os.close(); 
     System.out.println(connection.isClosed()); 
    } catch (IOException ex) { 
     Logger.getLogger(SocketController.class.getName()).log(Level.SEVERE, null, ex); 
    } 

我知道爲什麼連接不斷閉幕。我們通過編寫

output.close(); 

關閉套接字的輸出,但我不什麼其他的方式,我們必須努力做到這一點,使服務器保持監聽客戶回答(匹配/不匹配)知道,這樣服務器知道它應該發送更多的文件,或者如果客戶端成功..是否可以在不關閉與服務器的連接的情況下發送文件?我在過去的兩天中一直都搜索不到任何東西

感謝您的閱讀和幫助。

回答

2

爲了實現你所要求的,你需要建立一個服務器和客戶端能夠理解的通信協議。有些東西需要傳遞,說:「我開始向你發送信息」,還有一些內容說:「我已經完成了發送內容。」可能還有更多 - 如信息分隔(例如MIME多部分表單邊界)。但至少需要啓動和停止令牌。


擴展說明:請看代碼的最簡單形式: server:loop{write()} -> client:loop{read()}。關閉服務器端的流會將-1值發送到客戶端,通常將其作爲停止信號使用。如果您想要無限期維護連接,並在不同時間寫入客戶端,則必須發送一些內容,說明「此事務已完成」。以下是僞代碼 - 徒手,不編譯。

// SERVER 
private Socket socket; // initialized somewhere 

private static final byte[] STOP = "</COMMS>".getBytes(); 

public void sendData(byte[] bytes) throws IOException{ 

    OutputStream out = socket.getOutputStream(); 

    if(bytes != null){ 
     out.write(bytes,0,bytes.length); 
    } 

    out.write(STOP); 
} // notice we exit the method without closing the stream. 

// CLIENT 
private Socket socket; // initialized somewhere 
private static final byte[] STOP = "</COMMS>".getBytes(); 
private static final int BUFFER_SIZE = 1024 << 8; 
private InputStream in; 

public byte[] receiveData(){ 
    if(in == null){ 
     in = socket.getInputStream(); 
    } 
    byte[] content; 
    byte[] bytes = new byte[BUFFER_SIZE]; 
    int bytesRead; 
    while((bytesRead = in.read(bytes)) != -1){ // normal termination 
      if(receivedStop(bytes,bytesRead)){ // see if stopped 
       removeStopBytes(bytes,bytesRead); // get rid of the STOP bytes 
       content = buildContent(content,bytes,bytesRead); // transfer bytes to array 
       break; 
      } 
      content = buildContent(content,bytes,bytesRead); // transfer bytes to array 
    } 
    return content; 
} 

再次,這是徒手和沒有編譯或測試。我相信這不是完全正確的,但希望你能獲得要點。服務器寫入內容,但從不關閉流。客戶端讀取流查找停止內容,建立最終內容,直到到達停止。

+0

我不會,如果它太多,但你可以提供一個如何做到這一點的例子,或者告訴我更多關於它的一點點?我對套接字編程相當陌生,我不確定我是否理解你的意思。 – Ulbo

+1

+1用於確定對應用程序協議的需求。分隔符不是在協議中構造消息的唯一方式,您也可以簡單地在正在傳輸的消息長度的前面加上前綴,以便接收方知道要讀取多少個字節。 – Dev

1

感謝madConan的回覆,它給了我一個關於如何去做的好主意。我會在這裏發佈我的代碼,以便其他人可以在將來使用它。

服務器代碼

public void run() { 
    try { 
     PrintStream outToClient = new PrintStream(connection.getOutputStream()); 
     OutputStream os = connection.getOutputStream(); 
     BufferedInputStream input = new BufferedInputStream(new FileInputStream(f)); 
     outToClient.println("file"); 
     copy(input, os, f); 
     System.out.println(connection.isClosed()); 
    } catch (IOException ex) { 
     Logger.getLogger(SocketController.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

private static void copy(final InputStream is, final OutputStream os, File f) throws   IOException { 
    final byte[] stop = "stop".getBytes(); 
    final byte[] buffer = new byte[(int) f.length()]; 
    is.read(buffer, 0, buffer.length); 
    os.write(buffer, 0, buffer.length); 
    os.write(stop); 
    os.flush(); 
} 

客戶端代碼

public static File recieveData(Socket clientSocket, File f) { 
    try { 
     InputStream in = clientSocket.getInputStream(); 
     FileOutputStream output = new FileOutputStream(f); 
     byte[] content; 
     byte[] bytes = new byte[1024 << 8]; 
     int bytesRead; 
     while (true) { 
      if (recieveStop(f)) { 
       removeStop(f); 
       break; 
      } 
      bytesRead = in.read(bytes); 
      output.write(bytes, 0, bytesRead); 
     } 
    } catch (IOException ex) { 
     Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    return f; 
} 

public static boolean recieveStop(File f) { 
    BufferedReader br = null; 
    try { 
     br = new BufferedReader(new FileReader(f)); 
     String currentLine; 
     String lastLine = ""; 
      while ((currentLine = br.readLine()) != null) { 
       lastLine = currentLine; 
      } 
     if (lastLine.equals("stop")) { 
      return true; 
     } 
    } catch (FileNotFoundException ex) { 
     Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (IOException ex) { 
      Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
     } finally { 
     try { 
      br.close(); 
     } catch (IOException ex) { 
      Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
    return false; 
} 

public static void removeStop(File f) { 
    try { 
     RandomAccessFile raFile = new RandomAccessFile(f, "rw"); 
     long length = raFile.length(); 
     raFile.setLength(length - 4); 
     raFile.close(); 
    } catch (FileNotFoundException ex) { 
     Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (IOException ex) { 
     Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex); 
    } 

} 

希望這將幫助其他有同樣的問題。

+0

有一件事:你可能不會使用「停止」作爲標記,除非你真的確定有效載荷永遠不會包含「停止」。 – MadConan

+0

哦,是的,謝謝你,我沒有真正考慮它..它可能有時包含它.. – Ulbo

相關問題